Pertanyaan tentang arsitektur game dengan XNA

12

Jadi saya akhirnya sempat bermain-main dengan XNA dan telah bermain-main dengan membuat game 2D (Saya memiliki banyak aset seni dari seorang teman yang mengembangkannya di iOS)

Banyak hal yang tampaknya mudah dilakukan dan keluar dari kotak, tetapi saya bingung karena banyak literatur (buku yang saya beli misalnya) tidak terlalu memperhatikan 2D.

Saya sangat menghargai klarifikasi atau diarahkan ke informasi lebih lanjut tentang pencarian berikut:

  1. Apa gunanya Layanan Game? Saya memahami seluruh idiom mendaftarkan suatu objek sebagai layanan sehingga setiap GameComponent lain dapat mengambilnya, namun bagaimana cara mengalahkannya dengan membuatnya menjadi publik atau statis? Sebagai contoh, buku saya merekomendasikan mendaftarkan objek SpriteBatch di kelas Game.cs. Saya tidak yakin bagaimana ini lebih baik daripada membuatnya menjadi publik / statis karena seharusnya hanya ada satu contoh Game (tunggal)?

  2. Saya bingung kapan saya harus mewarisi dari GameComponent atau RenderableGameComponent. Saya mencoba mengikuti desain Manajer / Pengendali, sehingga semua entitas dibuat / dimiliki oleh satu manajer dan sama untuk hal-hal lain. Saat ini saya memiliki setiap Manajer / Pengendali yang mewarisi dari GameComponent, namun bagaimana hal ini mengalahkan memiliki objek Game yang memiliki semua Manajer dan secara manual memanggil pembaruan pada mereka dan menggambar?

  3. Saya perhatikan bahwa Inisialisasi dipanggil sebelum ContentLoad (), saya menemukan ini menjengkelkan karena di Inisialisasi saya adalah di mana saya ingin membuat beberapa entitas saya (yaitu Sprite, Player dll.), Namun saya tidak bisa memberi mereka dimuat SpriteSheets atau Textures karena panggilan untuk memuatnya belum terjadi. Apakah saya mungkin melakukan inisialisasi yang salah atau apakah orang hanya menetapkan tekstur lebih jauh di ContentLoad?

Tampaknya itu adalah " WTF " terbesar saya yang tidak terlalu mengerti

Setheron
sumber

Jawaban:

11

Jawaban atas pertanyaan Anda sederhana: Lakukan apa saja yang berhasil. Idealnya, lakukan apa yang sederhana dan berhasil. Sering menggunakan arsitektur built-in tidak sederhana karena, seperti yang Anda temukan, Anda harus melompati lingkaran untuk menyusun gim Anda seperti yang Anda inginkan.

Untuk menjawab pertanyaan pertama, saya akan mengarahkan Anda ke jawaban saya untuk pertanyaan "Mengapa menggunakan layanan?" . Jawaban singkatnya adalah bahwa layanan adalah cara yang baik untuk menghindari masalah kopling (versi, ketergantungan, ekstensibilitas) yang tidak akan pernah Anda temui dalam game mandiri . Sebagian besar waktu lebih mudah untuk hanya membuat anggota public(dan mungkin bahkan static, jika Anda sedang terburu-buru) dan khawatir tentang masalah yang lebih menarik.

Untuk menjawab pertanyaan kedua Anda, saya akan mengarahkan Anda ke jawaban saya untuk pertanyaan "Apa kontra menggunakan DrawableGameComponent untuk setiap instance objek game?" dan juga pemikiran saya tentang arsitektur game . Jawaban singkatnya adalah: tidak ada untungnya menggunakan GameComponentover hanya membuat kelas Anda sendiri dan memanggil metode seperti Drawdan Updatediri Anda sendiri. Jika GameComponentcocok dengan arsitektur yang Anda inginkan dengan tepat, tentu saja gunakan itu - tetapi hampir selalu tidak.

Menggunakan layanan dan komponen hanya benar-benar menjadi menarik jika Anda sedang membangun perpustakaan untuk konsumsi pihak ketiga. XNA sendiri melakukan ini - yang dimilikinya IGraphicsDeviceServicedan GamerServicesComponent, misalnya. Ini memenuhi persyaratan pelepasan kunci spesifik yang biasanya tidak Anda temui ketika mengembangkan game.

Akhirnya, jawaban untuk pertanyaan ketiga Anda cukup sederhana: Cukup buat entitas game Anda di LoadContent. Tidak ada yang spesial tentang ini Initialize.

Patut ditunjukkan bahwa seluruh Microsoft.Xna.Framework.Gameunit adalah opsional . Ini memberikan titik awal yang sangat berguna - tetapi seharusnya tidak dianggap sebagai "satu-satunya cara yang tepat" untuk melakukan sesuatu.

Andrew Russell
sumber
Cara yang sangat menarik untuk melihatnya. Jauh lebih realistis dan membumi daripada jawaban saya. +1 memang layak, Pak.
Jesse Emond
Saya punya satu pertanyaan lagi! Bagaimana dengan asalnya ketika Anda menggambar untuk Texture2D. Apakah biasa menempatkan asal di tengah bawah tekstur? Saya mencoba melakukan animasi, dan saya menemukan asal pada (0,0) menyebabkan tekstur bergeser sedikit jika lebar dan tinggi tidak sama
Setheron
@Setheron: Anda harus benar-benar membuat pertanyaan baru - karena ini sangat tidak terkait dengan pertanyaan awal. Saya akan mengembalikan suntingan yang Anda buat untuk pertanyaan ini. Asal untuk SpriteBatch.Drawditentukan dalam koordinat tekstur-piksel relatif ke kiri atas tekstur (atau persegi panjang sumber, jika Anda menggunakannya).
Andrew Russell
1
@Andrew: Saya baru-baru ini refactored game saya sehingga sepenuhnya didasarkan pada layanan, bukan public/ staticproperti. Mengapa? Testabilitas. Hampir mustahil untuk mengubah hal-hal dengan pendekatan properti, sedangkan itu sepele jika semuanya diinisialisasi dengan IServiceProvideryang dapat diisi dengan apa pun yang dibutuhkan kelas dengan metode pengujian Anda. Itu juga menghindari perlunya instantiate Gameobjek itu sendiri dalam pengujian Anda, yang menjadi berantakan sangat cepat.
Matthew Scharley
Selain itu, saya masih memiliki banyak properti publik di Gameobjek. Mereka kebetulan diakses melalui antarmuka yang didorong ke Game.Servicesyang kemudian akan diteruskan ke segala sesuatu untuk mendapatkan apa yang mereka butuhkan lagi.
Matthew Scharley
3

Untuk pertanyaan pertama Anda, saya harus mengakui bahwa saya tidak tahu jawaban yang sebenarnya. Saya kira itu akan menjadi alasan yang sama mengapa singleton umumnya merupakan pola desain yang buruk. Saya akan mengarahkan Anda ke kutipan dari tautan ini :

Yang pertama kami pikirkan (dan salah satu alasan di balik memperkenalkan layanan) adalah membuat referensi GraphicsDevice tersedia di seluruh permainan. Biasanya kami memiliki Game yang memiliki GraphicsDevice dan memaparkannya melalui properti seperti Game.GraphicsDevice. Masalah dengan ini adalah bahwa ini dengan erat mengikat GraphicsDevice ke Game, tidak memungkinkan orang lain untuk "memiliki" perangkat (seperti renderer) dan mencegah seseorang menggunakan GraphicsDevice yang diperbarui di masa depan tanpa mengirimkan versi baru dari Game yang tidak akan ' t kompatibel.

Untuk pertanyaan kedua Anda, saya anggap menggunakan Komponen seperti ini akan lebih berguna jika Anda akan mengikuti pendekatan berbasis komponen , seolah-olah Anda akan memiliki daftar Spritekomponen yang akan tahu cara menggambar dan memperbarui sendiri daripada manajer yang tahu cara memperbarui dan menggambar setiap sprite. Saya setuju, kedengarannya sama tetapi saya lebih suka desain berbasis komponen karena saya sangat suka pendekatan berorientasi objek yang dimilikinya.

Untuk pertanyaan ketiga Anda, ya, Anda harus memuat segala bentuk konten (aset, font, dll.) Dalam metode LoadContent. Adapun inisialisasi, Anda biasanya akan membuat objek Player dalam fungsi Inisialisasi dan kemudian memuat kontennya dalam LoadContent .. Atau Anda bisa melakukan semuanya dalam LoadContent jika Anda mau.

Jesse Emond
sumber