Ausgewogenheit im Design von Desktop-Spielen: Erstellen von Grafiken mit Google App Script und Gephi





Hallo, alle miteinander! Mein Name ist Nikita und ich möchte Ihnen einige praktische Aspekte der Entwicklung meines Brettspiels Ghost Letters (das diesen Monat von Economics veröffentlicht wird) mitteilen. Wir haben versucht, den Entwicklungsprozess so systematisch wie möglich anzugehen, sodass unsere Erfahrung fĂŒr jemanden interessant sein kann.





Ghost Letters ist ein Detektivbrettspiel mit geheimen Rollen fĂŒr Deduktion, Bluff und assoziatives Denken. Wenn Sie gerne "Mafia" oder "Imaginarium" spielen, werden Sie es sicher auch mögen. Von modernen Brettspielen im Genre ist es "Mysterium" und "Criminalist" am nĂ€chsten.





Aufgaben

Die Grundmechanik von Ghost Letters basiert auf Assoziationen zwischen Karten mit Bildern verschiedener Objekte (Beweiskarten). Und in einem der frĂŒhen Entwicklungsstadien stellten wir die Frage: "Ist es möglich, Assoziationen im Spiel zu berechnen und auszugleichen?" Warum nicht mal probieren?





Die Aufgabe, Assoziationen auszugleichen, war ungefÀhr so:





  • Minimieren Sie die Anzahl starker „eindeutiger“ Assoziationen. Jede Karte sollte idealerweise mehreren Karten mit ungefĂ€hr gleicher StĂ€rke zugeordnet werden.





  • “ ”. , .





  • .





, , . 150 , – . , .





Google Docs

- Google , . - :





  • Google App Script. JS , -.





  • , . , .





  • , . - . .





Gephi

. .





:





. Google Sheets, , .





4 :





0 –

1 – ,

2 –

3 –





, – , .





, 150 150 ( , “”). , . , , , .





, , – , . , .





:





. id , . , id.





//     
function RefreshPictures() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  //  
  var sheet_a = ss.getSheetByName("");
  var range_a = sheet_a.getDataRange();
  //   
  var sheet_p = ss.getSheetByName("");
  var range_p = sheet_p.getDataRange();
  
  //    
  var row = sheet_a.getActiveCell().getRow();
  var col = sheet_a.getActiveCell().getColumn();
  
  //  id 
  var id1 = range_a.getCell(row, 1).getDisplayValue().toString();
  var id2 = range_a.getCell(1, col).getDisplayValue().toString();
  
  //        id
  var pos_pic1 = RowOfId(id1, range_p);
  var pos_pic2 = RowOfId(id2, range_p);
  
  // ,       id
  if (pos_pic1 != -1) {
    //       ,
    //      
    var pic1_f = range_p.getCell(pos_pic1, 2).getFormula();
    range_a.getCell(2, 1).setFormula(pic1_f);
  }
  else
  {
    range_a.getCell(2, 1).setValue("X");
  }
  
  if (pos_pic2 != -1) {
    var pic2_f = range_p.getCell(pos_pic2, 2).getFormula();
    range_a.getCell(2, 2).setFormula(pic2_f);
  }
  else
  {
    range_a.getCell(2, 2).setValue("X");
  }
}

//        id
function RowOfId(id, rng) {  
  var height = rng.getHeight();
  var data = rng.getValues();
  
  for (var i = 1; i < height; i++) {    
    if (data[i][0].toString() == id) {
      return i + 1;
    }
  }
  
  return -1;
}
      
      



. 150 , Google Sheets ( ). -, Google App Script .





//        Google Drive
function LoadPicturesFromDrive() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet_p = ss.getSheetByName("");
  var range_p = sheet_p.getDataRange();
  
  var art_folder = DriveApp.getRootFolder().getFoldersByName("  ").next()
  var files = art_folder.getFiles();
  
  //     
  var i = 1;
  while (files.hasNext()) {
    var file = files.next();
    
    var file_name = file.getName();
    //     id 
    var id = file_name.slice(0, file_name.indexOf("."));
    
    //  id  
    sheet_p.getRange(i + 1, 1).setValue(id);
    
    //     
    file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
    var file_id = file.getId();
    
    //        IMAGE
    sheet_p.getRange(i + 1, 2).setFormula("=IMAGE(\"" + "https://drive.google.com/uc?export=download&id=" + file_id + "\")");
    
    i = i + 1;
  }
}
      
      



, Google Sheets Google Drive, - 10% . , , , . API Dropbox, . Dropbox , , .





//        Dropbox
function LoadPicturesFromDropbox() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet_p = ss.getSheetByName("");
  var range_p = sheet_p.getDataRange();
  
  //    POST-
  var data = {
    "path": "",
    "recursive": false,
    "include_media_info": false,
    "include_deleted": false,
    "include_has_explicit_shared_members": false,
    "include_mounted_folders": true,
    "include_non_downloadable_files": true
  };
  var payload = JSON.stringify(data);
  
  var options = {
    "method" : "POST",
    "contentType" : "application/json",
    "headers" : {
       "Authorization" : "Bearer [ ]"
    },
    "payload" : payload,
    muteHttpExceptions : true
  };
  
  //  POST-      
  var url = "https://api.dropboxapi.com/2/files/list_folder";
  var response = UrlFetchApp.fetch(url, options);
  var json = JSON.parse(response.getContentText());
  
  //    
  for (var i = 0; i < json.entries.length; i++) {
    var name = json.entries[i].name;
    //     
    CreateSharedLink(name);
    var sh_link = GetSharedLink(name);
    
    //     id 
    id = name.slice(0, name.indexOf("."))
  
    //        IMAGE
    sheet_p.getRange(i + 2, 1).setValue(id);
    sheet_p.getRange(i + 2, 2).setFormula("=IMAGE(\"" + sh_link+"\")");
  }
}

//      
function CreateSharedLink(name) {
  //    POST-
  var data = {
    "path": ("/" + name),
    "settings": {
        "requested_visibility": "public",
        "audience": "public",
        "access": "viewer"
    }
  };
  var payload = JSON.stringify(data);
  
  var options = {
    "method" : "POST",
    "contentType" : "application/json",
    "headers" : {
       "Authorization" : "Bearer [ ]"
    },
    "payload" : payload,
    muteHttpExceptions : true
  };
  
  //  POST-      
  var url = "https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings";
  var response = UrlFetchApp.fetch(url, options);
}

//     
function GetSharedLink(name) {
  //    POST-
  var data = {
    "path": ("/" + name)
  };
  var payload = JSON.stringify(data);
  
  var options = {
    "method" : "POST",
    "contentType" : "application/json",
    "headers" : {
       "Authorization" : "Bearer [ ]"
    },
    "payload" : payload,
    muteHttpExceptions : true
  };
  
  //  POST-      
  var url = "https://api.dropboxapi.com/2/sharing/list_shared_links";
  var response = UrlFetchApp.fetch(url, options);
  var json = JSON.parse(response.getContentText());
  
  //       
  var urlForDownload = json.links[0].url.slice(0, -1) + '1';
  
  return urlForDownload;
}
      
      



Gephi ( ) CSV. : (: id, label) (: source, target, weight).





//         
function CreateGraph() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet_a = ss.getSheetByName("");
  var range_a = sheet_a.getDataRange();
  var data = range_a.getValues();
  var height = range_a.getHeight();
  
  //   
  var sheet_lbl = ss.getSheetByName("Graph Labels");
  //    
  var sheet_edg = ss.getSheetByName("Graph Edges");
  
  //     
  var weights = new Array("1", "2", "3");
  var edg_num = 0;
  
  //    
  var lbl_header = ["Id", "Label"];
  //     
  var edg_header = ["Source", "Target", "Weight"];
  
  //  
  sheet_lbl.clear();
  sheet_edg.clear();
  
  //    
  sheet_lbl.appendRow(lbl_header);
  sheet_edg.appendRow(edg_header);
  
  // ,        
  var tmp_arr = [];
  var tmp_arr_len = 0;
  
  //     (  )
  for (var i = 2; i < height; i++) {
    var id1 = data[i][0];
    var name1 = data[i][1];
    
    //      
    var lbl_row = [id1, name1];
    sheet_lbl.appendRow(lbl_row);
    
    for (var j = i + 1; j < height; j++) {
      var wt = data[i][j].toString();
      
      if (weights.includes(wt)) {
        var id2 = data[0][j];
        edg_num += 1;
        
        var edg_row = [id1, id2, wt];
        
        tmp_arr.push(edg_row);
        tmp_arr_len += 1;
        
        //      100 ,     .
        //        ,   
        //     Google App Script
        if (tmp_arr_len >= 100) {
          sheet_edg.getRange(sheet_edg.getLastRow() + 1, 1, tmp_arr_len, 3).setValues(tmp_arr);
          tmp_arr = [];
          tmp_arr_len = 0;
        }
      }
    }
  }
  
  //        
  if (tmp_arr_len > 0) {
    sheet_edg.getRange(sheet_edg.getLastRow() + 1, 1, tmp_arr_len, 3).setValues(tmp_arr);
    tmp_arr = [];
    tmp_arr_len = 0;
  }
}
      
      



Gephi ( ). , , , . .





, , . , “1” , . “2” “3”. .





, , , - . “”, . “” “” Gephi. , 100 :





, , “” . , . “”. , .





In Bezug auf die Visualisierung des Graphen und die Methoden seiner Analyse bleibt natĂŒrlich noch viel zu tun, aber dieser Ansatz hat sich bereits bewĂ€hrt. Wenn Sie in Ihrer Spieleentwicklung auch Grafiken verwendet haben, ist es sehr interessant, ĂŒber Ihre Erfahrungen Bescheid zu wissen.






Wenn Sie daran interessiert sind, die Entwicklung des Projekts zu verfolgen , abonnieren Sie die Spielegruppe VKontakte und Instagram . Hier poste ich Entwicklungsnotizen, Plot-Snippets und mehr.








All Articles