
Pendahuluan
Cerita dimulai dengan hackathon berbasis blockchain. Pada awal acara, saya bertemu dengan seorang pria yang menciptakan permainan papan bisnis sebagai hobi (saya berada di playtest dari satu permainan seperti itu), kami bekerja sama, dan bersama-sama kami menemukan sebuah tim yang dengannya mereka “membutakan” permainan strategis sederhana selama akhir pekan. Hackathon berlalu, tetapi antusiasme tetap ada. Dan kami datang dengan ide permainan kartu multipemain tentang kebahagiaan, komunitas dunia, dan pemilihan umum.
Dalam seri artikel kami akan mencerminkan jalan kami untuk membuat game, dengan deskripsi dari rake yang telah kami injak dan akan melangkah seiring kami bergerak maju.
Di bawah potongan akan:
- Ringkasan Game
- Bagaimana keputusan dibuat tentang apa yang harus dilakukan backend. Di mana ia "hidup" sehingga tidak membayar untuk itu pada tahap pengembangan
- Langkah pertama dalam pengembangan - otentikasi pemain dan pengaturan perjodohan
- Rencana selanjutnya
Tentang game apa
Manusia bosan dengan perang dunia, menipisnya sumber daya dan kompetisi terus-menerus. Faksi-faksi utama sepakat untuk menggunakan teknologi modern untuk memilih satu kepemimpinan. Pada waktu yang ditentukan, pemilih dunia harus memutuskan pilihan fraksi yang akan memerintah planet ini untuk milenium berikutnya. Faksi-faksi utama terlibat dalam perebutan kekuasaan “jujur”. Dalam sesi permainan, setiap pemain mewakili sebagian kecil.
Permainan kartu ini tentang pemilihan. Setiap faksi memiliki anggaran untuk menyelenggarakan pemilihan, sumber pendapatan meningkatkan anggaran dan mulai memilih. Di awal permainan, dek dengan kartu aksi dicampur dan 4 kartu dikeluarkan untuk masing-masing peserta. Setiap belokan, pemain dapat melakukan hingga dua aksi game. Untuk menggunakan kartu, pemain menaruhnya di atas meja dan, jika perlu, menentukan tujuan dan mengurangi dari anggaran biaya penggunaan kartu. Setelah akhir ronde, pemain hanya dapat menyimpan satu kartu yang tidak digunakan. Pada awal setiap putaran, pemain mendapatkan kartu dari dek, sehingga pada awal setiap putaran, setiap pemain memiliki 4 kartu aksi di tangan.
Di akhir babak 3, 6 dan 9, pemain dengan jumlah suara paling sedikit dihapus dari permainan. Jika beberapa pemain memiliki jumlah suara minimum yang sama, maka semua pemain dengan hasil ini dihilangkan dari permainan. Suara-suara para pemain ini pergi ke kolam pemilih umum.
Di akhir babak 12, pemenangnya adalah yang memiliki suara terbanyak.
Memilih alat untuk backend
Dari deskripsi game berikut:
- Ini multipemain
- Penting untuk mengidentifikasi pemain dan mengelola akun
- Kehadiran komponen sosial akan menguntungkan permainan - teman, komunitas (klan), obrolan, pencapaian (prestasi)
- Papan peringkat dan fungsionalitas perjodohan akan diperlukan.
- Fungsi manajemen turnamen akan berguna di masa depan
- Mengingat permainan ini adalah permainan kartu, Anda perlu mengelola katalog kartu, Anda mungkin perlu menyimpan kartu yang tersedia untuk pemain dan menyusun deck
- Di masa depan, ekonomi dalam game mungkin diperlukan, termasuk mata uang dalam game, pertukaran barang virtual (kartu)
Melihat daftar kebutuhan, saya langsung sampai pada kesimpulan bahwa membuat backend saya sendiri pada tahap awal tidak masuk akal dan pergi ke google apa opsi lain. Jadi saya menemukan bahwa ada backend gaming cloud khusus, di antaranya PlayFab (dibeli oleh Microsoft) dan GameSparks (dibeli oleh Amazon) menonjol.
Secara umum, mereka secara fungsional serupa dan mencakup kebutuhan dasar. Selain itu, arsitektur internal mereka sangat berbeda, tugas yang sama diselesaikan sedikit berbeda, dan korespondensi eksplisit dalam fitur sulit untuk dilacak. Di bawah ini adalah fitur positif dan negatif dari setiap platform dan pertimbangan pada topik pilihan.
Playfab
Fitur positif:
- Akun dari game yang berbeda digabungkan menjadi akun master
- Ekonomi permainan dijelaskan tanpa satu baris kode, termasuk penetapan harga ke toko virtual terpisah
- Antarmuka pengguna yang ramah
- Microsoft Mengakuisisi Produk Setelah Akuisisi
- Biaya kepemilikan dalam produksi oleh langganan Indie Studio adalah $ 99 (hingga 100k MAU), ketika beralih ke langganan MAU 1k Profesional akan dikenakan biaya $ 8 (akun minimum $ 300)
Fitur negatif:
- Penyimpanan data permainan sangat terbatas, misalnya, dalam langganan gratis untuk menyimpan data untuk sesi permainan tertentu (jika saya memahami semuanya dengan benar, Grup Entitas digunakan untuk ini) 3 slot masing-masing 500 byte tersedia
- Untuk mengatur Multiplayer, Anda perlu menghubungkan server pihak ketiga yang akan memproses acara dari klien dan menghitung logika game. Ini adalah Photon pada perangkat keras Anda atau Azure Thunderhead, dan Anda tidak hanya perlu mengatur server, tetapi juga meningkatkan langganan Anda ke setidaknya Indie Studio
- Perlu untuk memasang fakta bahwa kode cloud tanpa autocomplete dan tidak ada cara untuk masuk ke modul (atau tidak menemukan?)
- Tidak ada debugger normal, Anda hanya dapat menulis log di CloudScript dan melihat
Taman Bermain
Fitur positif:
- Penyimpanan data game. Tidak hanya ada banyak tempat di mana Anda dapat menyimpan data (metadata permainan umum, barang virtual, profil pemain, sesi multipemain, dll.), Platform ini juga menyediakan basis data lengkap sebagai layanan yang tidak terikat pada apa pun, Selain itu, baik MongoDB dan Redis tersedia segera untuk berbagai jenis data. Di lingkungan pengembangan Anda dapat menyimpan 10 MB, dalam pertempuran 10 GB
- Multiplayer tersedia dalam berlangganan gratis (Pengembangan) dengan batas 10 koneksi simultan dan 10 permintaan per detik
- Pekerjaan mudah dengan CloudCode, termasuk alat bawaan untuk pengujian dan debugging (Test Harness)
Fitur negatif:
- Perasaan bahwa sejak pembelian oleh Amazon (musim dingin 2018) alat ini mengalami stagnasi, tidak ada inovasi
- Sekali lagi, setelah akuisisi Amazon, tarif menjadi lebih buruk, sebelumnya dimungkinkan untuk menggunakan hingga 10.000 MAU dalam produksi secara gratis
- Biaya produksi kepemilikan mulai dari $ 300 (berlangganan standar)
Refleksi
Pertama, Anda harus memeriksa konsep permainan. Untuk melakukan ini, saya ingin membuat prototipe stick dan scotch tape tanpa investasi moneter dan mulai bermain tes mekanika game. Karena itu, sejak awal ketika memilih, saya meningkatkan kesempatan untuk mengembangkan dan menguji mekanik pada berlangganan gratis.
GameSparks memenuhi kriteria ini, tetapi PlayFab tidak, karena Anda akan memerlukan server yang akan menangani acara-acara klien game dan langganan tingkat studio Indie ($ 99).
Pada saat yang sama, saya menerima risiko bahwa Amazon tidak mengembangkan GameSparks, yang artinya bisa "mati". Mengingat hal ini dan masih biaya kepemilikan dalam produksi, saya memikirkan potensi kebutuhan untuk pindah ke platform lain atau ke backend saya sendiri.
Langkah pertama dalam pengembangan
Koneksi dan Otentikasi
Jadi, pilihan jatuh pada GameSparks sebagai backend pada tahap prototyping. Langkah pertama adalah mempelajari cara menghubungkan ke platform dan mengotentikasi pemain. Poin penting adalah bahwa pengguna harus dapat bermain tanpa registrasi dan SMS segera setelah menginstal game. Untuk melakukan ini, GameSparks menawarkan opsi untuk membuat profil anonim dengan memanggil metode DeviceAuthenticationRequest, nanti berdasarkan profil anonim Anda dapat membuat profil lengkap dengan menghubungkan, misalnya, dengan akun Google Anda.
Mengingat saya memiliki TDD otak, saya mulai dengan membuat tes untuk menghubungkan klien ke permainan. Karena di masa depan CloudCode perlu ditulis dalam JS, saya akan melakukan tes integrasi di JS menggunakan mocha.js dan chai.js. Tes pertama ternyata seperti ini:
var expect = require("chai").expect; var GameClientModule = require("../src/gameClient"); describe("Integration test", function () { this.timeout(0); it("should connect client to server", async function () { var gameClient = new GameClientModule.GameClient(); expect(gameClient.connected()).is.false; await gameClient.connect(); expect(gameClient.connected()).is.true; }); })
Secara default, batas waktu di mocha.js adalah 2 detik, saya langsung membuatnya tidak ada habisnya, karena tes adalah integrasi. Dalam pengujian, saya membuat klien game yang belum diimplementasikan, memeriksa bahwa tidak ada koneksi ke server, memanggil perintah untuk terhubung ke backend, dan memverifikasi bahwa klien telah berhasil terhubung.
Agar tes berubah menjadi hijau, Anda perlu mengunduh dan menambahkan GameSparks JS SDK ke proyek, serta menghubungkan dependensinya (crypto-js dan ws), dan, tentu saja, mengimplementasikan GameClientModule:
var GameSparks = require("../gamesparks-javascript-sdk-2018-04-18/gamesparks-functions"); var config = new require("./config.json"); exports.GameClient = function () { var gamesparks = new GameSparks(); this.connected = () => (gamesparks.connected === true); this.connect = function () { return new Promise(function (resolve, reject) { gamesparks.initPreview({ key: config.gameApiKey, secret: config.credentialSecret, credential: config.credential, onInit: () => resolve(), onMessage: onMessage, onError: (error) => reject(error), logger: console.log }); }); } function onMessage(message) { console.log("GAME onMessage: " + JSON.stringify(message)); } }
Di awal implementasi klien game, kunci yang diperlukan untuk otorisasi teknis untuk membuat koneksi dari aplikasi klien dibaca dari konfigurasi. Metode yang terhubung membungkus bidang yang sama dari SDK. Yang paling penting terjadi dalam metode koneksi, ia mengembalikan janji dengan panggilan balik untuk koneksi yang sukses atau kesalahan, juga mengikat penangan onMessage ke panggilan balik yang sama. onMessage akan bertindak sebagai manajer pemrosesan pesan dari backend, untuk sekarang biarkan ia mencatat pesan ke konsol.
Tampaknya pekerjaan telah selesai, tetapi tes tetap merah. Ternyata GameSparks JS SDK tidak bekerja dengan node.js; untuk itu, Anda lihat, tidak memiliki konteks browser. Mari kita buat dia berpikir bahwa simpul adalah Chrome di poppy. Kami pergi ke gamesparks.js dan pada awalnya menambahkan:
if (typeof module === 'object' && module.exports) {
Tes berubah hijau, bergerak.
Seperti yang saya tulis sebelumnya, seorang pemain harus dapat mulai bermain segera setelah dia memasuki permainan, sementara saya ingin mulai mengumpulkan analitik dalam aktivitas. Untuk melakukan ini, kami mengikat pengidentifikasi perangkat atau pengidentifikasi yang dibuat secara acak. Periksa ini akan menjadi tes seperti itu:
it("should auth two anonymous players", async function () { var gameClient1 = new GameClientModule.GameClient(); expect(gameClient1.playerId).is.undefined; var gameClient2 = new GameClientModule.GameClient(); expect(gameClient2.playerId).is.undefined; await gameClient1.connect(); await gameClient1.authWithCustomId("111"); expect(gameClient1.playerId).is.equals("5b5f5614031f5bc44d59b6a9"); await gameClient2.connect(); await gameClient2.authWithCustomId("222"); expect(gameClient2.playerId).is.equals("5b5f6ddb031f5bc44d59b741"); });
Saya memutuskan untuk segera memeriksa 2 klien untuk memastikan bahwa setiap klien membuat profil sendiri di backend. Untuk melakukan ini, Anda memerlukan metode di klien game tempat Anda dapat memberikan pengenal eksternal ke GameSparks, dan kemudian memeriksa bahwa klien telah menghubungi profil pemain. Profil dipersiapkan sebelumnya di portal GameSparks.
Untuk implementasi di GameClient, tambahkan:
this.playerId = undefined; this.authWithCustomId = function (customId) { return new Promise(resolve => { var requestData = { "deviceId": customId , "deviceOS": "NodeJS" } sendRequest("DeviceAuthenticationRequest", requestData) .then(response => { if (response.userId) { this.playerId = response.userId; resolve(); } else { reject(new Error(response)); } }) .catch(error => { console.error(error); }); }); } function sendRequest(requestType, requestData) { return new Promise(function (resolve) { gamesparks.sendWithData(requestType, requestData, (response) => resolve(response)); }); }
Implementasi turun ke mengirim permintaan DeviceAuthenticationRequest, menerima pengidentifikasi pemain dari respons, dan menempatkannya di properti klien. Dengan segera, dalam metode terpisah, helper mengirim permintaan ke GameSparks dengan pembungkus dengan janji.
Kedua tes berwarna hijau, tetap menambahkan penutupan koneksi dan refactor.
Di GameClient, saya menambahkan metode yang menutup koneksi ke server (disconnect) dan connectAsAnonymous menggabungkan connect dan authWithCustomId. Di satu sisi, connectAsAnonymous melanggar prinsip tanggung jawab tunggal, tetapi tampaknya tidak melanggar ... Pada saat yang sama itu menambah kegunaan, karena dalam tes sering diperlukan untuk mengotentikasi klien. Apa yang Anda pikirkan tentang ini?
Dalam pengujian, ia menambahkan pembantu metode pabrik yang membuat instance baru dari klien game dan menambahkan ke array klien yang dibuat. Di mocha handler khusus, setelah setiap tes berjalan untuk klien dalam array, saya memanggil metode putuskan sambungan dan menghapus array ini. Saya belum menyukai "string ajaib" dalam kode, jadi saya menambahkan kamus dengan pengidentifikasi khusus yang digunakan dalam pengujian.
Kode akhir dapat dilihat di repositori, tautan yang akan saya berikan di akhir artikel.
Organisasi pencarian game (perjodohan)
Saya akan memulai fitur perjodohan, yang sangat penting untuk multipemain. Sistem ini mulai berfungsi ketika kami menekan tombol "Temukan permainan" di dalam sebuah permainan. Dia mengambil saingan, atau rekan satu tim, atau keduanya (tergantung pada permainan). Sebagai aturan, dalam sistem tersebut, setiap pemain memiliki indikator numerik MMR (Match Making Ratio) - peringkat pribadi pemain, yang digunakan untuk memilih pemain lain dengan tingkat keterampilan yang sama.
Untuk menguji fungsi ini, saya datang dengan tes berikut:
it("should find match", async function () { var gameClient1 = newGameClient(); var gameClient2 = newGameClient(); var gameClient3 = newGameClient(); await gameClient1.connectAsAnonymous(playerCustomIds.id1); await gameClient2.connectAsAnonymous(playerCustomIds.id2); await gameClient3.connectAsAnonymous(playerCustomIds.id3); await gameClient1.findStandardMatch(); expect(gameClient1.state) .is.equals(GameClientModule.GameClientStates.MATCHMAKING); await gameClient2.findStandardMatch(); expect(gameClient2.state) .is.equals(GameClientModule.GameClientStates.MATCHMAKING); await gameClient3.findStandardMatch(); expect(gameClient3.state) .is.equals(GameClientModule.GameClientStates.MATCHMAKING); await sleep(3000); expect(gameClient1.state) .is.equals(GameClientModule.GameClientStates.CHALLENGE); expect(gameClient1.challenge, "challenge").is.not.undefined; expect(gameClient1.challenge.challengeId).is.not.undefined; expect(gameClient2.state) .is.equals(GameClientModule.GameClientStates.CHALLENGE); expect(gameClient2.challenge.challengeId) .is.equals(gameClient1.challenge.challengeId); expect(gameClient3.state) .is.equals(GameClientModule.GameClientStates.CHALLENGE); expect(gameClient3.challenge.challengeId) .is.equals(gameClient1.challenge.challengeId); });
Tiga klien terhubung ke permainan (di masa depan itu adalah minimum yang diperlukan untuk memeriksa beberapa skenario) dan terdaftar untuk mencari permainan. Setelah mendaftarkan pemain ke-3 di server, sesi permainan terbentuk dan para pemain harus terhubung ke sana. Pada saat yang sama, keadaan klien berubah, dan konteks sesi permainan dengan pengidentifikasi yang sama muncul.
Pertama, siapkan backend. Di GameSparks ada alat yang siap pakai untuk mengkustomisasi pencarian game, tersedia di jalur "Configurator-> Matches". Saya membuat yang baru dan melanjutkan dengan pengaturan. Selain parameter standar seperti kode, nama, dan deskripsi pertandingan, jumlah minimum dan maksimum pemain yang diperlukan untuk mode permainan khusus ditunjukkan. Saya akan menetapkan kode "StandardMatch" ke pertandingan yang dibuat dan menunjukkan jumlah pemain dari 2 hingga 3.
Sekarang Anda perlu mengkonfigurasi aturan untuk memilih pemain di bagian "Ambang Batas". Untuk setiap ambang, waktu aksinya, ketik (absolut, relatif dan dalam persen) dan batas ditunjukkan.

Misalkan seorang pemain dengan MMR 19 mulai mencari. Dalam contoh di atas, 10 detik pertama adalah pemilihan pemain lain dengan MMR 19 hingga 21. Jika para pemain tidak dipilih, batas pencarian kedua diaktifkan, yang memperluas rentang pencarian dari 16 selama 20 detik berikutnya ( 19-3) hingga 22 (19 + 3). Selanjutnya, ambang ketiga dimasukkan, di mana pencarian akan dilakukan selama 30 detik dalam rentang dari 14 (19-25%) hingga 29 (19 + 50%), sementara pertandingan dianggap selesai jika jumlah minimum pemain yang dibutuhkan telah diakumulasikan (Terima tanda Min Min Pemain).
Bahkan, mekanismenya lebih rumit, karena memperhitungkan MMR dari semua pemain yang berhasil bergabung dengan pertandingan tertentu. Saya akan menganalisis detail-detail ini ketika saatnya tiba untuk membuat mode rating dari game (tidak ada dalam artikel ini). Untuk mode permainan standar, di mana saya belum berencana untuk menggunakan MMR, saya hanya perlu satu ambang batas jenis apa pun.
Ketika semua pemain telah dipilih, Anda harus membuat sesi permainan dan menghubungkan pemain ke sana. Di GameSparks, fungsi sesi permainan adalah "Tantangan". Sebagai bagian dari entitas ini, data sesi game disimpan, dan pesan dipertukarkan antara klien game. Untuk membuat tipe Tantangan baru, Anda harus menyusuri jalur "Configurator-> Tantangan". Di sana saya menambahkan tipe baru dengan kode "StandardChallenge" dan menunjukkan bahwa jenis sesi permainan ini adalah Turn Based, yaitu. pemain bergiliran, tidak secara bersamaan. GameSparks pada saat yang sama mengendalikan urutan gerakan.
Agar klien mendaftar untuk mencari permainan, Anda dapat menggunakan permintaan tipe MatchmakingRequest, tetapi saya tidak akan merekomendasikannya, karena nilai MMR pemain diperlukan sebagai salah satu parameter. Hal ini dapat menyebabkan penipuan pada bagian dari klien game, dan klien seharusnya tidak mengetahui MMR, ini adalah bisnis backend. Untuk mendaftar dengan benar untuk pencarian game, saya membuat acara yang sewenang-wenang dari klien. Ini dilakukan di bagian "Configurator-> Events". Saya menyebut acara FindStandardMatch tanpa atribut. Sekarang Anda perlu mengonfigurasi reaksi untuk acara ini, untuk ini saya akan pergi ke "Configurator-> Cloud Code" dari kode cloud, saya menulis penangan berikut untuk FindStandardMatch di bagian "Acara":
var matchRequest = new SparkRequests.MatchmakingRequest(); matchRequest.matchShortCode = "StandardMatch"; matchRequest.skill = 0; matchRequest.Execute();
Kode ini mendaftarkan pemain di StandardMatch dengan MMR 0, sehingga setiap pemain yang terdaftar untuk mencari permainan standar akan cocok untuk membuat sesi permainan. Dalam pemilihan pertandingan peringkat, mungkin ada banding ke data pribadi dari profil pemain untuk mendapatkan MMR dari jenis pertandingan ini.
Ketika ada cukup banyak pemain untuk memulai sesi permainan, GameSparks akan mengirim pesan MatchFoundMessage ke semua pemain yang dipilih. Di sini Anda dapat secara otomatis membuat sesi permainan dan menambahkan pemain ke dalamnya. Untuk melakukan ini, di "Pesan Pengguna-> MatchFoundMessage" tambahkan kode:
var matchData = Spark.getData(); if (Spark.getPlayer().getPlayerId() != matchData.participants[0].id) { Spark.exit(); } var challengeCode = ""; var accessType = "PRIVATE"; switch (matchData.matchShortCode) { case "StandardMatch": challengeCode = "StandardChallenge"; break; default: Spark.exit(); } var createChallengeRequest = new SparkRequests.CreateChallengeRequest(); createChallengeRequest.challengeShortCode = challengeCode; createChallengeRequest.accessType = accessType; var tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); createChallengeRequest.endTime = tomorrow.toISOString(); createChallengeRequest.usersToChallenge = []; var participants = matchData.participants; var numberOfPlayers = participants.length; for (var i = 1; i < numberOfPlayers; i++) { createChallengeRequest.usersToChallenge.push(participants[i].id) } createChallengeRequest.Send();
Kode pertama memeriksa bahwa itu adalah pemain pertama dalam daftar peserta. Selanjutnya, atas nama pemain pertama, sebuah instance dari StandardChallenge dibuat dan pemain yang tersisa diundang. Pemain yang diundang dikirimi pesan ChallengeIssuedMessage. Di sini Anda dapat membayangkan perilaku ketika undangan untuk bergabung dengan permainan ditampilkan pada klien dan memerlukan konfirmasi dengan mengirim AcceptChallengeRequest, atau Anda dapat menerima undangan dalam mode senyap. Jadi saya akan melakukannya, untuk ini di "Pesan Pengguna-> ChallengeIssuedMessage" Saya akan menambahkan kode berikut:
var challangeData = Spark.getData(); var acceptChallengeRequest = new SparkRequests.AcceptChallengeRequest(); acceptChallengeRequest.challengeInstanceId = challangeData.challenge.challengeId; acceptChallengeRequest.message = "Joining"; acceptChallengeRequest.SendAs(Spark.getPlayer().getPlayerId());
Langkah selanjutnya, GameSparks mengirimkan acara ChallengeStartedMessage. Penangan global dari acara ini ("Pesan Global-> ChallengeStartedMessage") adalah tempat yang ideal untuk menginisialisasi sesi permainan, saya akan mengurus ini ketika menerapkan logika game.
Waktunya telah tiba untuk aplikasi klien. Perubahan pada modul klien:
exports.GameClientStates = { IDLE: "Idle", MATCHMAKING: "Matchmaking", CHALLENGE: "Challenge" } exports.GameClient = function () { this.state = exports.GameClientStates.IDLE; this.challenge = undefined; function onMessage(message) { switch (message["@class"]) { case ".MatchNotFoundMessage": this.state = exports.GameClientStates.IDLE; break; case ".ChallengeStartedMessage": this.state = exports.GameClientStates.CHALLENGE; this.challenge = message.challenge; break; default: console.log("GAME onMessage: " + JSON.stringify(message)); } } onMessage = onMessage.bind(this); this.findStandardMatch = function () { var eventData = { eventKey: "FindStandardMatch" } return new Promise(resolve => { sendRequest("LogEventRequest", eventData) .then(response => { if (!response.error) { this.state = exports.GameClientStates.MATCHMAKING; resolve(); } else { console.error(response.error); reject(new Error(response)); } }) .catch(error => { console.error(error); reject(new Error(error)); }); }); } }
Sesuai dengan tes, beberapa bidang muncul di negara klien dan tantangan. Metode onMessage telah memperoleh tampilan yang berarti dan sekarang merespons pesan tentang awal sesi permainan dan pesan bahwa tidak mungkin untuk mengambil permainan. Metode findStandardMatch juga telah ditambahkan, yang mengirimkan permintaan yang sesuai ke backend. Tesnya hijau, tapi saya puas, pilihan permainan dikuasai.
Apa selanjutnya
Dalam artikel berikut ini saya akan menjelaskan proses mengembangkan logika game, dari menginisialisasi sesi permainan hingga pemrosesan gerakan. Saya akan menganalisis fitur penyimpanan berbagai jenis data - deskripsi metadata game, karakteristik dunia game, data dari sesi permainan, dan data tentang pemain. Logika game akan dikembangkan melalui dua jenis pengujian - unit dan integrasi.
Saya akan mengunggah sumber di github dalam porsi yang terkait dengan artikel.
Ada pemahaman bahwa untuk maju secara efektif dalam menciptakan permainan, Anda perlu memperluas tim penggemar kami. Artis / desainer akan segera bergabung. Dan guru di, misalnya, Unity3D, yang akan membuat garis depan untuk platform seluler, masih harus ditemukan.