Memisahkan Mesin Game dari kode game dalam game yang sama, dengan versi


15

Saya memiliki permainan yang sudah selesai, yang ingin saya tolak di versi lain. Ini akan menjadi game yang serupa, dengan desain yang kurang lebih sama, tetapi tidak selalu, pada dasarnya segala sesuatunya mungkin berubah, kadang kecil, kadang besar.

Saya ingin kode inti diversi secara terpisah dari gim, sehingga jika katakan saya memperbaiki bug yang ditemukan di gim A, perbaikannya akan ada di gim B.

Saya mencoba mencari cara terbaik untuk mengelola itu. Gagasan awal saya adalah ini:

  • Buat enginemodul / folder / apa pun, yang berisi semua yang bisa digeneralisasi dan 100% independen dari sisa permainan. Ini akan mencakup beberapa kode, tetapi juga aset umum yang dibagikan di antara gim.
  • Masukkan mesin ini ke dalam gitrepositorinya sendiri , yang akan dimasukkan dalam game sebagai agit submodule

Bagian yang saya perjuangkan adalah bagaimana mengelola sisa kode. Katakanlah Anda memiliki adegan menu, kode ini khusus untuk gim, tetapi sebagian besar cendrung bersifat generik dan dapat digunakan kembali di gim lain. Saya tidak bisa memasukkannya ke dalam engine, tetapi mengkode ulang untuk setiap game akan menjadi tidak efisien.

Mungkin menggunakan semacam variasi git branch bisa efektif untuk mengelolanya, tapi saya rasa ini bukan cara terbaik.

Adakah yang punya ide, pengalaman untuk dibagikan atau apa?


Bahasa apa yang digunakan mesin Anda? Beberapa bahasa memiliki manajer paket khusus yang mungkin lebih masuk akal daripada menggunakan submit git. Misalnya, NodeJS memiliki npm (yang dapat menargetkan repositori Git sebagai sumber).
Dan Pantry

Apakah pertanyaan Anda tentang cara terbaik mengelola konfigurasi kode generik atau bagaimana konfigurasi mengelola kode "semi-generik" atau bagaimana merancang kode, bagaimana merancang kode atau apa?
Dunk

Ini mungkin berbeda di setiap Lingkungan Pemrograman Bahasa, tetapi, Anda dapat mempertimbangkan tidak hanya Perangkat Lunak Versi Kontrol, tetapi, juga tahu mulai dengan cara memisahkan mesin gim dari kode gim, (seperti paket, folder, dan API), dan kemudian , terapkan Versi Kontrol.
umlcat

Cara memiliki riwayat bersih satu folder dalam satu cabang: Refactor mesin Anda sehingga repo terpisah (masa depan) ada di folder terpisah, itulah komit terakhir Anda. Kemudian buat cabang baru, hapus semua yang ada di luar folder itu, dan komit. Lalu pergi ke komit pertama repo, dan gabungkan dengan cabang baru Anda. Anda sekarang memiliki cabang dengan hanya folder itu: tarik di proyek lain dan / atau gabungkan kembali dengan proyek yang ada. Ini banyak membantu saya dengan memisahkan mesin di cabang, jika kode Anda sudah dipisahkan. Saya tidak perlu modul git.
Barry Staes

Jawaban:


13

Buat modul mesin / folder / apa pun, yang berisi semua yang bisa digeneralisasi dan 100% independen dari sisa permainan. Ini akan mencakup beberapa kode, tetapi juga aset umum yang dibagikan di antara gim.

Masukkan mesin ini di repositori gitnya sendiri, yang akan dimasukkan dalam gim sebagai submodule git

Itulah yang saya lakukan dan bekerja dengan sangat baik. Saya memiliki kerangka kerja aplikasi dan pustaka rendering, dan masing-masing diperlakukan sebagai submodul dari proyek saya. Saya menemukan SourceTree berguna ketika datang ke submodules, karena mengelola mereka dengan baik dan tidak akan membiarkan Anda melupakan apa pun, misalnya jika Anda memperbarui submodule mesin di proyek A, itu akan memberi tahu Anda untuk menarik perubahan dalam proyek B.

Dengan pengalaman, pengetahuan tentang kode apa yang harus ada di mesin vs apa yang seharusnya per proyek. Saya menyarankan bahwa jika Anda bahkan agak tidak yakin, bahwa Anda menyimpannya di setiap proyek untuk saat ini. Seiring berjalannya waktu, Anda akan melihat di antara berbagai proyek Anda apa yang tetap sama dan kemudian Anda dapat secara bertahap memasukkannya ke dalam kode mesin Anda. Dengan kata lain: kode duplikat hingga Anda hampir 100% yakin bahwa itu tidak berubah secara terpisah per proyek, kemudian menggeneralisasikannya.

Catatan tentang Kontrol Sumber dan Binari

Ingatlah bahwa jika Anda mengharapkan aset biner Anda sering berubah, Anda mungkin tidak ingin meletakkannya dalam kontrol sumber berbasis teks seperti git. Katakan saja ... ada solusi yang lebih baik untuk binari. Hal paling sederhana yang dapat Anda lakukan untuk saat ini untuk membantu menjaga repositori dan sumber "engine-source" Anda tetap bersih adalah memiliki repositori "engine-binaries" terpisah yang hanya menyimpan binari, yang juga Anda sertakan sebagai submodule dalam proyek Anda. Dengan cara ini Anda mengurangi kerusakan kinerja yang dilakukan pada repositori "sumber mesin" Anda, yang berubah sepanjang waktu dan karenanya Anda memerlukan iterasi cepat: komit, dorong, tarik, dll. Sistem manajemen kontrol sumber seperti git beroperasi pada delta teks , dan segera setelah Anda memperkenalkan binari, Anda memperkenalkan delta besar dari perspektif teks - yang akhirnya menghabiskan waktu Anda.Lampiran GitLab . Google temanmu.


Mereka tidak benar-benar sering berubah, tetapi saya tertarik pada hal itu. Saya tidak tahu apa-apa tentang versi biner. Solusi apa yang ada?
Malharhak

@Malharhak Diedit untuk menjawab komentar Anda.
Insinyur

@Malharak Berikut ini sedikit info menarik tentang topik ini.
Insinyur

1
+1 untuk menyimpan sesuatu - dalam proyek selama mungkin. Kode umum memberikan kompleksitas yang lebih tinggi. Ini harus dihindari sampai benar-benar diperlukan.
Gusdor

1
@Malharhak Tidak, terutama karena tujuan Anda hanya untuk menyimpan "salinan" sampai Anda mencatat bahwa kata kode tidak dapat diubah dan dapat dianggap sebagai hal biasa. Gusdor mengulangi hal ini - diperingatkan - orang dapat dengan mudah membuang banyak waktu dengan memfaktorkan terlalu dini, kemudian mencoba menemukan cara untuk menjaga kode itu cukup umum agar tetap umum, namun cukup mudah beradaptasi agar sesuai dengan berbagai proyek ... Anda berakhir dengan seluruh banyak parameter dan switch dan itu berubah menjadi berantakan jelek yang masih tidak apa yang Anda butuhkan karena Anda akhirnya mengubah itu per proyek baru pula . Jangan faktor terlalu dini . Bersabarlah.
Insinyur

6

Pada titik tertentu mesin HARUS mengkhususkan diri dan tahu hal-hal tentang permainan. Saya akan pergi bersinggungan di sini.

Ambil sumber daya dalam RTS. Satu permainan mungkin memiliki Creditsdan yang Crystallainnya MetaldanPotatoes

Anda harus menggunakan konsep OO dengan benar dan mencari maks. penggunaan kembali kode. Jelas bahwa konsep Resourceada di sini.

Jadi kami memutuskan sumber daya memiliki yang berikut:

  1. Sebuah kait di loop utama untuk menambah / mengurangi sendiri
  2. Cara untuk mendapatkan jumlah saat ini (mengembalikan sebuah int)
  3. Cara untuk mengurangi / menambah sewenang-wenang (pemain mentransfer sumber daya, pembelian ....)

Perhatikan bahwa gagasan tentang a ini Resourcebisa mewakili pembunuhan atau poin dalam permainan! Itu tidak terlalu kuat.

Sekarang mari kita pikirkan sebuah game. Kita dapat mengurutkan mata uang dengan bertransaksi dalam penny dan menambahkan titik desimal ke output. Yang tidak bisa kita lakukan adalah sumber daya "instan". Seperti mengatakan "pembangkit listrik"

Katakanlah Anda menambahkan InstantResource kelas dengan metode serupa. Anda sekarang (mulai) mencemari mesin Anda dengan sumber daya.


Masalah

Mari kita ambil contoh RTS lagi. Misalkan pemain apa pun menyumbangkan sebagian Crystalkepada pemain lain. Anda ingin melakukan sesuatu seperti:

if(transfer.target == engine.getPlayerId()) {
    engine.hud.addIncoming("You got "+transfer.quantity+" of "+
        engine.resourceDictionary.getNameOf(transfer.resourceId)+
        " from "+engine.getPlayer(transfer.source).name);
}
engine.getPlayer(transfer.target).getResourceById(transfer.resourceId).add(transfer.quantity)
engine.getPlayer(transfer.source).getResourceById(transfer.resourceId).add(-transfer.quantity)

Namun ini benar-benar sangat berantakan. Ini tujuan umum, tapi berantakan. Meskipun sudah memaksakan resourceDictionaryyang berarti sekarang sumber daya Anda harus memiliki nama! DAN itu adalah per pemain, jadi Anda tidak dapat memiliki sumber daya tim lagi.

Ini adalah "terlalu banyak" abstraksi (bukan contoh yang brilian akan saya akui) sebagai gantinya Anda harus mencapai titik di mana Anda menerima bahwa permainan Anda memiliki pemain dan kristal, maka Anda hanya dapat memiliki (misalnya)

engine.getPlayer(transfer.target).crystal().receiveDonation(transfer)
engine.getPlayer(transfer.source).crystal().sendDonation(transfer)

Dengan kelas Playerdan kelas CurrentPlayerdi mana CurrentPlayer'scrystal objek secara otomatis akan menampilkan hal-hal di HUD untuk transfer / pengiriman donasi.

Ini mencemari mesin dengan kristal, sumbangan kristal, pesan pada HUD untuk pemain saat ini dan semua itu. Lebih cepat dan lebih mudah untuk membaca / menulis / memelihara (yang lebih penting, karena tidak secara signifikan lebih cepat)


Komentar akhir

Kasus sumber daya tidak brilian. Saya harap Anda masih bisa mengerti intinya. Jika ada yang saya tunjukkan bahwa "sumber daya tidak termasuk dalam mesin" seperti apa yang dibutuhkan oleh game tertentu dan apa yang berlaku untuk semua pengertian tentang sumber daya adalah SANGAT berbeda. Apa yang biasanya Anda temukan adalah 3 (atau 4) "lapisan"

  1. "Core" - ini adalah definisi mesin buku teks, ini adalah adegan grafik dengan kait acara, ini berkaitan dengan shader dan paket jaringan dan gagasan abstrak pemain
  2. "GameCore" - Ini sangat umum untuk jenis game tetapi tidak untuk semua game - misalnya sumber daya di RTS atau amunisi di FPS. Logika permainan mulai meresap ke sini. Di sinilah konsep sumber daya kami sebelumnya. Kami telah menambahkan hal-hal ini yang masuk akal untuk sebagian besar sumber daya RTS.
  3. "GameLogic" SANGAT spesifik untuk game yang sebenarnya dibuat. Anda akan menemukan variabel dengan nama-nama seperti creatureatau shipatau squad. Menggunakan warisan Anda akan mendapatkan kelas yang menjangkau semua 3 lapisan (misalnya Crystal adalah Resource yang merupakan GameLoopEventListener kata)
  4. "Aset" ini tidak berguna untuk game lain. Ambil contoh skrip AI gabungan di paruh 2, mereka tidak akan digunakan dalam RTS dengan mesin yang sama.

Membuat game baru dari mesin lama

Ini SANGAT umum. Fase 1 adalah untuk merobek lapisan 3 dan 4 (dan 2 jika permainan adalah tipe yang BENAR-BENAR berbeda) Misalkan kita membuat RTS dari RTS lama. Kami masih memiliki sumber daya, tidak hanya kristal dan barang-barang - sehingga kelas dasar di lapisan 2 dan 1 masih masuk akal, semua kristal yang dirujuk dalam 3 dan 4 dapat dibuang. Jadi kami lakukan. Namun kami dapat memeriksanya sebagai referensi untuk apa yang ingin kami lakukan.


Polusi pada lapisan 1

Ini bisa terjadi. Abstraksi dan kinerja adalah musuh. UE4 misalnya menyediakan banyak kasus komposisi yang dioptimalkan (jadi jika Anda ingin X dan Y seseorang menulis kode yang melakukan X dan Y secara bersamaan dengan sangat cepat - ia tahu ia melakukan keduanya) dan hasilnya BENAR-BENAR cukup besar. Ini tidak buruk tetapi memakan waktu. Layer 1 akan memutuskan hal-hal seperti "bagaimana Anda mengirimkan data ke shaders" dan bagaimana Anda menghidupkan sesuatu. Melakukannya dengan cara terbaik untuk proyek Anda SELALU baik. Coba saja dan rencanakan masa depan, menggunakan kembali kode adalah teman Anda, mewarisi ke mana masuk akal.


Lapisan klasifikasi

TERAKHIR (saya janji) jangan terlalu takut dengan lapisan. Engine adalah istilah kuno dari masa lalu pipa fungsi tetap di mana mesin cukup banyak bekerja dengan cara yang sama secara grafis (dan sebagai hasilnya memiliki banyak kesamaan) pipa yang dapat diprogram menghidupkan ini di kepalanya dan dengan demikian "lapisan 1" menjadi tercemar dengan efek apa pun yang ingin dicapai pengembang. AI adalah fitur yang membedakan (karena berbagai pendekatan) dari mesin, sekarang AI dan grafis.

Kode Anda tidak boleh diajukan di lapisan ini. Bahkan mesin Unreal yang terkenal memiliki BANYAK versi yang berbeda masing-masing khusus untuk permainan yang berbeda. Ada beberapa file (selain struktur data seperti mungkin) yang tidak akan berubah. Ini baik-baik saja! Jika Anda ingin membuat gim baru dari gim lain, dibutuhkan waktu lebih dari 30 menit. Kuncinya adalah merencanakan, untuk mengetahui bit apa yang akan disalin dan ditempelkan dan apa yang harus ditinggalkan.


1

Saran pribadi saya untuk bagaimana menangani konten yang campuran generik dan spesifik adalah membuatnya dinamis. Saya akan mengambil layar menu Anda sebagai contoh. Jika saya salah mengerti apa yang Anda minta, beri tahu saya apa yang ingin Anda ketahui dan saya akan menyesuaikan jawaban saya.

Ada 3 hal yang (hampir) selalu ada pada adegan menu: latar belakang, logo permainan, dan menu itu sendiri. Hal-hal ini biasanya berbeda berdasarkan permainan. Apa yang dapat Anda lakukan untuk konten ini adalah membuat MenuScreenGenerator di mesin Anda, yang mengambil 3 parameter objek: BackGround, Logo, dan Menu. Struktur dasar 3 bagian ini juga merupakan bagian dari mesin Anda, tetapi mesin Anda tidak benar-benar mengatakan bagaimana bagian-bagian ini dihasilkan, hanya parameter apa yang harus Anda berikan kepada mereka.

Kemudian dalam kode gim Anda yang sebenarnya, Anda membuat objek untuk BackGround, Logo dan Menu, dan Anda meneruskannya ke MenuScreenGenerator Anda. Sekali lagi, gim Anda sendiri tidak menangani bagaimana menu dihasilkan, itu untuk mesin. Game Anda hanya perlu memberi tahu mesin seperti apa seharusnya dan di mana seharusnya.

Pada dasarnya, mesin Anda haruslah sebuah API yang akan ditampilkan oleh permainan. Jika dilakukan dengan benar, mesin Anda harus melakukan kerja keras dan permainan Anda sendiri hanya akan memberi tahu mesin apa aset yang harus digunakan, tindakan apa yang harus diambil dan seperti apa dunia ini.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.