Bagaimana cara memperbarui status entitas dan animasi dalam game berbasis komponen?

10

Saya mencoba merancang sistem entitas berbasis komponen untuk tujuan pembelajaran (dan kemudian digunakan pada beberapa game) dan saya mengalami beberapa masalah ketika memperbarui status entitas.

Saya tidak ingin memiliki metode pembaruan () di dalam Komponen untuk mencegah dependensi antara Komponen.

Apa yang saya pikirkan saat ini adalah bahwa komponen menyimpan data dan komponen pembaruan sistem.

Jadi, jika saya memiliki permainan 2D sederhana dengan beberapa entitas (misalnya pemain, musuh1, musuh2) yang memiliki komponen Transform, Movement, State, Animation dan Rendering, saya pikir saya harus memiliki:

  • Suatu MovementSystem yang menggerakkan semua komponen Gerakan dan memperbarui komponen Negara
  • Dan RenderSystem yang memperbarui komponen Animasi (komponen animasi harus memiliki satu animasi (yaitu seperangkat bingkai / tekstur) untuk setiap negara bagian dan memperbarui itu berarti memilih animasi yang sesuai dengan keadaan saat ini (misalnya melompat, bergerak, bergerak, dll), dan memperbarui indeks bingkai). Kemudian, RenderSystem memperbarui komponen Render dengan tekstur yang sesuai dengan bingkai saat ini dari masing-masing entitas Animasi dan menampilkan semuanya di layar.

Saya telah melihat beberapa implementasi seperti kerangka kerja Artemis, tapi saya tidak tahu bagaimana menyelesaikan situasi ini:

Katakanlah permainan saya memiliki entitas berikut. Setiap entitas memiliki serangkaian negara dan satu animasi untuk setiap negara:

  • pemain: "idle", "moving_right", "jumping"
  • musuh1: "moving_up", "moving_down"
  • musuh2: "moving_left", "moving_right"

Apa pendekatan yang paling diterima untuk memperbarui keadaan saat ini dari setiap entitas? Satu-satunya hal yang dapat saya pikirkan adalah memiliki sistem yang terpisah untuk setiap kelompok entitas dan komponen Negara dan Animasi terpisah sehingga saya akan memiliki PlayerState, PlayerAnimation, Enemy1State, Enemy1Animation ... PlayerMovementSystem, PlayerRenderingSystem ... tapi saya pikir ini buruk solusi dan mematahkan tujuan memiliki sistem berbasis komponen.

Seperti yang Anda lihat, saya sangat tersesat di sini, jadi saya sangat menghargai bantuan apa pun.

EDIT: Saya pikir solusi untuk membuat ini berfungsi seperti yang saya inginkan adalah yang ini:

Anda membuat komponen statistik dan komponen animasi cukup umum untuk digunakan untuk semua entitas. Data yang dikandungnya akan menjadi pengubah untuk mengubah hal-hal seperti animasi yang dimainkan atau yang menyatakan tersedia. - Byte56

Sekarang, saya mencoba mencari cara untuk mendesain 2 komponen ini cukup umum sehingga saya dapat menggunakannya kembali. Mungkinkah memiliki UID untuk setiap negara bagian (mis. Berjalan, berlari ...) dan menyimpan animasi di peta ke dalam AnimationComponent yang dikunci oleh pengenal ini menjadi solusi yang baik?

miviclin
sumber
Saya berasumsi Anda telah melihat ini: Menyatakan perubahan dalam entitas atau komponen ? Apakah pertanyaan Anda secara fundamental berbeda dari yang itu?
MichaelHouse
@ Byte56 Ya, saya membacanya beberapa jam yang lalu. Solusi yang Anda sarankan ada mirip dengan ide yang saya paparkan di sini. Tapi masalah saya muncul ketika komponen StateComponent dan AnimationComponent tidak sama untuk semua entitas di dalam sistem. Haruskah saya membagi sistem itu menjadi sistem yang lebih kecil yang memproses kelompok entitas yang memiliki kemungkinan keadaan dan animasi yang sama? (lihat bagian terakhir dari posting asli saya untuk klarifikasi yang lebih baik)
miviclin
1
Anda membuat statecomponentdan animationcomponentcukup umum untuk digunakan untuk semua entitas. Data yang dikandungnya akan menjadi pengubah untuk mengubah hal-hal seperti animasi yang dimainkan atau yang menyatakan tersedia.
MichaelHouse
Ketika Anda berbicara tentang ketergantungan, apakah maksud Anda ketergantungan data atau ketergantungan urutan eksekusi? Juga, dalam solusi yang Anda usulkan, MovementSystem sekarang harus menerapkan semua cara yang berbeda untuk memindahkan sesuatu? Ini sepertinya melanggar ide sistem berbasis komponen ...
ADB
@ADB Saya berbicara tentang ketergantungan data. Untuk memperbarui animasi (mis. Ubah dari animasi move_right ke animasi move_left) Saya perlu mengetahui status entitas saat ini dan saya tidak melihat cara membuat 2 komponen ini lebih umum.
miviclin

Jawaban:

5

IMHO Movementkomponen harus menahan keadaan saat ini ( Movement.state) dan Animationkomponen harus mengamati perubahan Movement.statedan memperbarui animasi saat ini ( Animation.animation) sesuai, dengan menggunakan pencarian sederhana status id ke animasi (seperti yang disarankan pada akhir OP). Jelas ini berarti Animationakan tergantung pada Movement.

Struktur alternatif adalah memiliki Statekomponen generik , yang Animationmengamati, dan Movementmemodifikasi, yang pada dasarnya adalah model-view-controller (state-animation-movement dalam kasus ini).

Alternatif lain adalah meminta entitas mengirimkan suatu peristiwa ke komponennya ketika statusnya berubah. Animationakan mendengarkan acara ini dan memperbarui animasinya sesuai. Ini menghilangkan ketergantungan, meskipun Anda bisa berpendapat bahwa versi dependen adalah desain yang lebih transparan.

Semoga berhasil.

Torious
sumber
Jadi Animasi mengamati Negara dan Negara mengamati Gerakan ... Ketergantungan masih ada tetapi saya mungkin mencobanya. Apakah alternatif terakhir akan seperti ini: Gerakan memberi tahu perubahan pada entitas dan entitas mengirimkan acara ke Negara, dan kemudian proses yang sama akan diulang untuk Negara dan Animasi? Bagaimana pendekatan ini memengaruhi kinerja?
miviclin
Kasus pertama: Movementakan mengontrol State (tidak mengamati). Kasus terakhir: Ya Movementakan melakukannya entity.dispatchEvent(...);atau lebih, dan semua komponen lain yang mendengarkan acara semacam itu akan menerimanya. Kinerja tentu saja lebih buruk daripada pemanggilan metode murni, tetapi tidak banyak. Anda dapat menggabungkan objek acara misalnya. Namun, Anda tidak harus menggunakan entitas sebagai "simpul acara", Anda juga bisa menggunakan "bus peristiwa" khusus, sehingga kelas entitas Anda sepenuhnya tidak ada di dalamnya.
Torious
2

Tentang masalah Anda, jika NEGARA hanya digunakan dalam Animasi, maka Anda bahkan tidak perlu mengungkapkannya ke Komponen lain. Jika memiliki lebih dari satu penggunaan, maka Anda perlu memaparkannya.

Sistem Komponen / Subsistem yang Anda gambarkan terasa lebih berbasis hierarki daripada berbasis komponen. Bagaimanapun, apa yang Anda gambarkan sebagai komponen sebenarnya adalah struktur data. Itu tidak berarti itu adalah sistem yang buruk, hanya saja saya tidak berpikir itu cocok dengan pendekatan berbasis komponen dengan baik.

Seperti yang Anda catat, dependensi adalah masalah besar dalam sistem berbasis komponen. Ada berbagai cara untuk menghadapinya. Beberapa memerlukan setiap komponen untuk menyatakan dependensi mereka dan melakukan pemeriksaan ketat. Pertanyaan lain untuk komponen yang mengimplementasikan antarmuka spesifik. Yang lain meneruskan referensi ke komponen dependen ketika mereka instantiate masing-masing.

Secara independen dari metode yang Anda gunakan, Anda akan membutuhkan semacam GameObject untuk bertindak sebagai kumpulan Komponen. Apa yang disediakan GameObject dapat sangat bervariasi dan Anda dapat menyederhanakan dependensi antar-komponen dengan mendorong beberapa data yang sering digunakan ke level GameObject. Unity melakukan itu dengan transformasi misalnya, memaksa semua objek game untuk memilikinya.

Mengenai masalah yang Anda minta dari berbagai negara / animasi untuk objek game yang berbeda, inilah yang akan saya lakukan. Pertama, saya tidak akan terlalu suka pada tahap implementasi ini: hanya terapkan apa yang Anda butuhkan sekarang untuk membuatnya bekerja, kemudian tambahkan bel dan peluit saat Anda membutuhkannya.

Jadi, saya akan mulai dengan komponen 'Status': PlayerStateComponent, Enemy1State, Enemy2State. Komponen negara akan mengurus perubahan negara pada waktu yang tepat. Status adalah sesuatu yang hampir semua objek Anda miliki, sehingga dapat berada di GameObject.

Lalu, akan ada AnimationCompoment. Ini akan memiliki kamus animasi yang dikunci untuk negara bagian. Di pembaruan (), ubah animasi jika keadaan berubah.

Ada artikel bagus tentang membangun kerangka kerja yang tidak bisa saya temukan. Dikatakan bahwa ketika Anda tidak memiliki pengalaman dalam domain, Anda harus memilih satu masalah dan melakukan implementasi paling sederhana yang menyelesaikan masalah saat ini . Kemudian Anda menambahkan masalah / kasus penggunaan lain dan memperluas kerangka saat Anda melanjutkan, sehingga tumbuh secara organik. Saya sangat suka pendekatan itu, terutama ketika bekerja dengan konsep baru seperti yang Anda lakukan.

Implementasi yang saya usulkan cukup naif, tetapi di sini ada beberapa kemungkinan perbaikan saat Anda menambahkan lebih banyak use-case:

  • ganti variabel GameObject dengan kamus. Setiap komponen menggunakan kamus untuk menyimpan nilai. (pastikan untuk menangani tabrakan dengan benar ...)
  • ganti kamus nilai polos dengan referensi sebagai gantinya: class FloatVariable () {nilai publik [...]}
  • Alih-alih beberapa komponen keadaan, buat StateComponent generik di mana Anda dapat membangun mesin keadaan variabel. Anda harus memiliki serangkaian kondisi umum yang dapat diubah oleh suatu keadaan: penekanan tombol, input mouse, perubahan variabel (Anda dapat mengikatnya dengan FloatVariable di atas).
ADB
sumber
Pendekatan ini berhasil, saya mengimplementasikan sesuatu yang mirip setahun yang lalu, tetapi masalahnya adalah hampir setiap komponen tergantung pada komponen lain, jadi sepertinya kurang fleksibel untuk saya. Saya juga berpikir tentang mendorong komponen yang paling umum (misalnya mengubah, membuat, menyatakan ...) ke entitas tetapi saya pikir ini merusak tujuan komponen karena beberapa dari mereka terkait dengan entitas dan beberapa entitas mungkin tidak membutuhkannya. Itu sebabnya saya mencoba mendesain ulang dengan sistem yang bertanggung jawab untuk memperbarui logika sehingga komponen tidak akan tahu tentang satu sama lain karena mereka tidak memperbarui sendiri.
miviclin
0

Selain jawaban ADB Anda dapat menggunakan http://en.wikipedia.org/wiki/Dependency_injection , yang membantu ketika Anda perlu membangun banyak komponen dengan mengirimkannya sebagai referensi ke konstruktor mereka. Jelas mereka masih akan saling bergantung (jika itu diperlukan dalam basis kode Anda), tetapi Anda dapat meletakkan semua ketergantungan itu di satu tempat di mana dependensi diatur dan sisa kode Anda tidak perlu tahu tentang dependensi.

Pendekatan ini juga bekerja dengan baik jika Anda menggunakan antarmuka karena setiap kelas komponen hanya meminta apa yang dibutuhkan atau di mana ia perlu terdaftar dan hanya kerangka kerja injeksi ketergantungan (atau tempat di mana Anda mengatur semuanya, biasanya aplikasi) tahu tentang siapa yang butuh apa .

Untuk sistem sederhana, Anda mungkin lolos tanpa menggunakan DI atau kode bersih, kelas RenderingSystem Anda terdengar seperti Anda perlu memanggilnya secara statis atau setidaknya membuatnya tersedia di setiap komponen, yang cukup banyak membuat mereka saling bergantung dan sulit untuk diubah. Jika Anda tertarik pada pendekatan yang lebih bersih, periksa tautan DI wiki di atas dan bacalah tentang Clean Code: http://clean-code-developer.com/

exDreamDuck
sumber
Saya sudah memiliki satu sistem di mana komponen saling tergantung satu sama lain. Saya banyak menggunakan injeksi dependensi di sana, dan meskipun saya lebih suka menggunakan hierarki yang dalam, saya mencoba membuat yang baru untuk menghindari pemasangan komponen jika memungkinkan. Saya tidak akan memanggil apa pun secara statis. Saya akan memiliki ComponentManager yang setiap sistem memiliki akses ke (setiap sistem harus memiliki referensi untuk itu), dan RendererSystem akan mendapatkan semua komponen animasi dari manajer komponen dan membuat keadaan saat ini setiap animasi.
miviclin