مرحبا جميعا! اسمي نيكيتا ، وأود أن أشارككم بعض الجوانب العملية لتطوير لعبة لوح Ghost Letters (التي ستصدر هذا الشهر بواسطة Economikus). لقد حاولنا التعامل مع عملية التطوير بشكل منهجي قدر الإمكان ، لذلك قد تكون تجربتنا ممتعة بالنسبة لشخص ما.
Ghost Letters هي لعبة لوحة تحري بأدوار سرية للخصم والخداع والتفكير الترابطي. إذا كنت تحب لعب "Mafia" أو "Imaginarium" - فأنا متأكد من أنك ستحبها أيضًا. من ألعاب الطاولة الحديثة في النوع ، فهي الأقرب إلى "Mysterium" و "Criminalist".
المهام المعينة
تعتمد الآلية الأساسية لـ Ghost Letters على الارتباط بين البطاقات بصور لأشياء مختلفة (بطاقات الأدلة). وفي إحدى مراحل التطوير الأولى طرحنا السؤال التالي: "هل من الممكن حساب وبناء التوازن في لعبة الجمعيات؟" في الواقع ، لماذا لا تجربها.
كانت مهمة موازنة الجمعيات تقريبًا على النحو التالي:
قلل من عدد الجمعيات القوية "الواضحة". يجب أن ترتبط كل بطاقة بشكل مثالي مع العديد من البطاقات الأخرى بنفس القوة تقريبًا.
“ ”. , .
.
, , . 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;
}
}
, , . , “1” , . “2” “3”. .
, , , - . “”, . “” “” Gephi. , 100 :
, , “” . , . “”. , .
بالطبع ، فيما يتعلق بتصور الرسم البياني وطرق تحليله ، لا يزال هناك عمل يتعين القيام به ، لكن هذا النهج أظهر نفسه جيدًا بالفعل. إذا استخدمت الرسوم البيانية أيضًا في تطوير ألعابك ، فسيكون من الممتع جدًا معرفة تجربتك.
إذا كنت مهتمًا بمتابعة تطوير المشروع ، فقم بالاشتراك في مجموعة ألعاب VKontakte و Instagram . هذا هو المكان الذي أنشر فيه ملاحظات التطوير ومقتطفات المؤامرة والمزيد.