Bagaimana cara menerapkan fitur dalam sistem entitas?


31

Setelah mengajukan dua pertanyaan tentang sistem entitas ( 1 , 2 ), dan membaca beberapa artikel tentang mereka, saya pikir saya memahaminya jauh lebih baik daripada sebelumnya. Saya masih memiliki beberapa ketidakpastian, terutama tentang membangun emitor partikel, sistem input, dan kamera. Saya jelas masih memiliki beberapa masalah dalam memahami sistem entitas, dan mereka mungkin berlaku untuk berbagai objek, tetapi saya memilih tiga karena mereka konsep yang sangat berbeda, harus mencakup tanah yang cukup luas, dan membantu saya memahami sistem entitas dan cara menangani masalah seperti ini, saya sendiri, ketika mereka datang

Saya sedang membangun sebuah mesin dalam JavaScript, dan saya telah mengimplementasikan sebagian besar fitur inti, yang meliputi: penanganan input, sistem animasi fleksibel, penghasil partikel, kelas matematika dan fungsi, penanganan adegan, kamera dan render, dan sejumlah besar dari hal-hal lain yang biasanya didukung oleh mesin. Saya membaca jawaban Byte56, yang membuat saya tertarik membuat mesin menjadi sistem entitas. Itu masih tetap mesin game HTML5, dengan filosofi adegan dasar, tetapi harus mendukung penciptaan entitas yang dinamis dari komponen.


Masalah yang saya miliki, sekarang, adalah menyesuaikan konsep mesin lama saya ke dalam paradigma pemrograman baru ini. Ini adalah beberapa definisi dari pertanyaan sebelumnya, yang diperbarui:

  • Sebuah Entity adalah sebuah identifier. Itu tidak memiliki data, itu bukan objek, ini adalah id sederhana yang mewakili indeks dalam daftar adegan semua entitas (yang sebenarnya saya rencanakan untuk diimplementasikan sebagai matriks komponen).

  • Sebuah Komponen adalah pemegang data, tetapi dengan metode yang dapat beroperasi pada data tersebut. Contoh terbaik adalah Vector2Dkomponen, atau "Posisi". Memiliki data: xdan y, tetapi juga beberapa metode yang membuat operasi pada data sedikit lebih mudah: add(), normalize(), dan sebagainya.

  • Sebuah Sistem adalah sesuatu yang dapat beroperasi pada set entitas yang memenuhi persyaratan tertentu; biasanya entitas perlu memiliki serangkaian komponen tertentu, untuk dioperasikan. Sistem adalah bagian "logika", bagian "algoritma", semua fungsi yang disediakan oleh komponen murni untuk memudahkan pengelolaan data.


Kamera

Kamera memiliki Vector2Dproperti posisi, properti rotasi, dan beberapa metode untuk memusatkannya di sekitar titik. Setiap bingkai, diumpankan ke penyaji, bersama dengan adegan, dan semua objek diterjemahkan sesuai dengan posisinya. Adegan kemudian ditampilkan.

Bagaimana saya bisa mewakili objek semacam ini dalam sistem entitas? Apakah kamera akan menjadi entitas, komponen, atau kombinasi (sesuai jawaban saya )?

Emitor Partikel

Masalah yang saya miliki dengan penghasil partikel adalah, sekali lagi, apa yang seharusnya. Saya cukup yakin bahwa partikel itu sendiri tidak harus menjadi entitas, karena saya ingin mendukung lebih dari 10.000 dari mereka, dan saya percaya bahwa menciptakan banyak entitas akan menjadi pukulan berat pada kinerja saya.

Bagaimana saya bisa mewakili objek semacam ini dalam sistem entitas?

Manajer Input

Yang terakhir yang ingin saya bicarakan adalah bagaimana input harus ditangani. Dalam versi mesin saya saat ini, ada kelas yang disebut Input. Ini adalah penangan yang berlangganan acara browser, seperti penekanan tombol dan perubahan posisi mouse, dan juga mempertahankan keadaan internal. Kemudian, kelas pemain memiliki react()metode, yang menerima objek input sebagai argumen. Keuntungan dari ini adalah bahwa objek input dapat diserialisasi ke .JSON, dan kemudian dibagikan melalui jaringan, memungkinkan untuk simulasi multipemain yang mulus.

Bagaimana ini diterjemahkan ke dalam sistem entitas?

Jawaban:


26
  • Kamera: Membuat komponen ini cukup rapi. Itu hanya akan memilikiisRenderingbendera dan rentang kedalaman seperti kata Sean. Selain "bidang pandang" (saya kira Anda mungkin menyebutnya skala dalam 2D?) Dan zona output. Zona output dapat menentukan bagian dari jendela permainan yang diberikan kamera ini. Itu tidak akan memiliki posisi / rotasi terpisah seperti yang Anda sebutkan. Entitas yang Anda buat yang memiliki komponen kamera akan menggunakan posisi dan komponen rotasi entitas itu. Maka Anda akan memiliki sistem kamera yang mencari entitas yang memiliki komponen kamera, posisi dan rotasi. Sistem mengambil entitas itu dan menarik semua entitas yang dapat "dilihat" dari posisinya, rotasi, kedalaman tampilan, dan bidang tampilan, ke bagian layar yang ditentukan. Itu memberi Anda banyak pilihan untuk mensimulasikan banyak port tampilan, jendela "tampilan karakter", multiplayer lokal,

  • Particle Emitter: Ini juga seharusnya menjadi komponen. Sistem partikel akan mencari entitas yang memiliki posisi, rotasi, dan penghasil partikel. Emitor memiliki semua properti yang diperlukan untuk mereproduksi emitor Anda saat ini, saya tidak yakin apa itu semua, hal-hal seperti: kecepatan, kecepatan awal, waktu peluruhan dan sebagainya. Anda tidak perlu membuat banyak lintasan. Sistem partikel mengetahui entitas mana yang memiliki komponen itu. Saya membayangkan Anda dapat menggunakan kembali banyak kode yang ada.

  • Input: Saya harus mengatakan menjadikan ini sebagai komponen yang paling masuk akal mengingat saran yang saya buat di atas. Andainput systemakan diperbarui setiap frame dengan acara masukan saat ini. Kemudian ketika sedang melalui semua entitas itu yang memiliki komponen input, itu akan menerapkan peristiwa itu. Komponen input akan memiliki daftar kejadian keyboard dan mouse semua panggilan balik metode yang terkait. Saya tidak begitu yakin di mana metode callback akan hidup. Mungkin beberapa kelas pengontrol input? Apa pun yang paling masuk akal untuk modifikasi nanti oleh pengguna mesin Anda. Tapi ini akan memberi Anda kekuatan untuk dengan mudah menerapkan kontrol input ke entitas kamera, entitas player, atau apa pun yang Anda butuhkan. Ingin menyinkronkan gerakan sekelompok entitas dengan keyboard? Beri mereka semua komponen input yang merespons input yang sama dan sistem input menerapkan peristiwa pemindahan itu ke semua komponen yang meminta mereka.

Jadi sebagian besar ini berada di luar kepala saya, jadi mungkin tidak masuk akal tanpa penjelasan lebih lanjut. Jadi beri tahu saya apa yang Anda tidak jelas. Pada dasarnya, saya sudah memberi Anda banyak hal untuk dikerjakan :)


Jawaban hebat lainnya! Terima kasih! Sekarang, satu-satunya masalah saya adalah menyimpan dan mengambil entitas dengan cepat, sehingga pengguna benar-benar dapat mengimplementasikan loop permainan / logika ... Saya akan mencoba mencari tahu sendiri, tetapi saya harus terlebih dahulu belajar bagaimana Javascript menangani array, objek dan nilai yang tidak terdefinisi dalam memori untuk membuat perkiraan yang baik ... Itu akan menjadi masalah karena browser yang berbeda mungkin menerapkannya secara berbeda.
jcora

Ini terasa murni secara arsitektural, tetapi bagaimana sistem rendering menentukan kamera aktif yang tidak iterasi melalui semua entitas?
Laju

@Pace Karena saya ingin kamera aktif ditemukan dengan sangat cepat, saya kemungkinan akan mengizinkan sistem kamera untuk tetap mengacu pada entitas yang memiliki kamera aktif.
MichaelHouse

Di mana Anda meletakkan logika untuk mengontrol beberapa kamera (lihat, putar, pindahkan, dll.)? Bagaimana Anda mengontrol banyak kamera?
plasmacel

@plasmacel Jika Anda memiliki beberapa objek yang berbagi kontrol, itu akan menjadi tanggung jawab sistem kontrol Anda untuk menentukan objek mana yang menerima input.
MichaelHouse

13

Inilah cara saya mendekati ini:

Kamera

Kamera saya adalah entitas seperti yang lainnya, yang memiliki komponen yang terpasang:

  1. Transformmemiliki Translation, Rotationdan Scaleproperti, selain yang lain untuk kecepatan, dll.

  2. Pov(Sudut pandang) telah FieldOfView, AspectRatio, Near, Far, dan hal lain yang diperlukan untuk menghasilkan matriks proyeksi, di samping IsOrthobendera yang digunakan untuk beralih antara perspektif dan proyeksi ortografi. Povjuga menyediakan properti lazy-load yang ProjectionMatrixdigunakan oleh sistem rendering yang dihitung secara internal saat dibaca, dan di-cache hingga salah satu properti lainnya dimodifikasi.

Tidak ada sistem kamera khusus. Sistem Render menyimpan daftar Pov's dan berisi logika untuk menentukan mana yang akan digunakan saat rendering.

Memasukkan

Sebuah InputReceiverkomponen dapat melekat pada entitas apapun. Ini memiliki pengendali kejadian yang terlampir (atau lambda jika bahasa Anda mendukungnya) yang digunakan untuk menahan pemrosesan input khusus entitas, yang mengambil parameter untuk keadaan tombol saat ini dan sebelumnya, lokasi mouse saat ini dan keadaan tombol dan keadaan tombol, dll. (Sebenarnya, ada penangan terpisah untuk mouse dan keyboard).

Misalnya, dalam game uji mirip Asteroid yang saya buat ketika terbiasa dengan Entity / Component, saya memiliki dua metode input lambda. Satu menangani navigasi kapal dengan memproses tombol panah dan bilah ruang (untuk menembak). Yang lain menangani input keyboard umum - tombol untuk keluar, jeda, dll, me-restart level, dll. Saya membuat dua komponen, melampirkan masing-masing lambda ke komponennya sendiri, kemudian menetapkan komponen penerima navigasi ke entitas kapal, yang lain ke entitas pemroses perintah yang tidak terlihat.

Inilah pengendali acara untuk menangani kunci yang dipegang di antara frame yang terhubung ke InputReceiverkomponen kapal (C #):

  void ship_input_Hold(object sender, InputEventArgs args)
    {
        var k = args.Keys;
        var e = args.Entity;

        var dt = (float)args.GameTime.ElapsedGameTime.TotalSeconds;

        var verlet = e.As<VerletMotion>();
        var transform = e.As<Transform>();

        if (verlet != null)
        {

        /// calculate applied force 
            var force = Vector3.Zero;
            var forward = transform.RotationMatrix.Up * Settings.ShipSpeedMax;

            if (k.Contains(Keys.W))
                force += forward;

            if (k.Contains(Keys.S))
                force -= forward;

            verlet.Force += force * dt;
        }

        if (transform != null)
        {
            var theta = Vector3.Zero;

            if (k.Contains(Keys.A))
                theta.Z += Settings.TurnRate;

            if (k.Contains(Keys.D))
                theta.Z -= Settings.TurnRate;

            transform.Rotation += theta * dt;
        }

        if (k.Contains(Keys.Space))
        {
            var time = (float)args.GameTime.TotalGameTime.TotalSeconds - _rapidFireLast;

            if (time >= _rapidFireDelay)
            {
                Fire();
                _rapidFireLast = (float)args.GameTime.TotalGameTime.TotalSeconds;
            }
        }
    }

Jika kamera Anda mobile, memberikan sendiri InputReceiverdan Transformkomponen, melampirkan lambda atau handler yang mengimplementasikan apa pun jenis kontrol yang Anda inginkan, dan Anda sudah selesai.

Ini agak rapi karena Anda dapat memindahkan InputReceiverkomponen dengan pengendali navigasi yang terpasang dari kapal ke asteroid, atau yang lainnya, dan menerbangkannya. Atau, dengan menetapkan Povkomponen ke hal lain dalam adegan Anda - asteroid, lampu jalan, dll. - Anda dapat melihat pemandangan Anda dari perspektif entitas itu.

Sebuah InputSystemkelas yang mempertahankan keadaan internal untuk keyboard, mouse, dll InputSystemmenyaring koleksi entitas internal untuk entitas yang memiliki InputReceiverkomponen. Dalam Update()metodenya, iterates melalui koleksi itu dan memanggil input handler yang melekat pada masing-masing komponen dengan cara yang sama seperti sistem rendering menarik setiap entitas dengan suatu Renderablekomponen.

Partikel

Ini benar-benar tergantung pada bagaimana Anda berencana berinteraksi dengan partikel. Jika Anda hanya membutuhkan sistem partikel yang berperilaku seperti satu objek - katakanlah, kembang api menunjukkan bahwa pemain tidak dapat menyentuh atau memukul - maka saya akan membuat entitas tunggal, dan ParticleRenderGroupkomponen yang berisi informasi apa pun yang Anda butuhkan untuk partikel - pembusukan, dll. - yang tidak tercakup oleh Renderablekomponen Anda . Saat merender, sistem render akan melihat apakah suatu entitas memiliki RenderParticleGrouplampiran dan menanganinya sesuai.

Jika Anda membutuhkan partikel individu untuk berpartisipasi dalam deteksi tumbukan, merespons masukan, dll., Tetapi Anda hanya ingin menjadikannya sebagai kumpulan, saya akan membuat Particlekomponen yang berisi informasi tersebut berdasarkan per-partikel, dan membuatnya sebagai entitas yang terpisah. Sistem render masih dapat mengelompokkannya, tetapi mereka akan diperlakukan sebagai objek yang terpisah oleh sistem lain. (Ini bekerja sangat baik dengan instancing.)

Kemudian, baik di MotionSystem(atau apa pun yang Anda gunakan yang menangani memperbarui posisi entitas, dll.) Atau dalam dedikasi ParticleSystem, lakukan pemrosesan apa pun yang diperlukan untuk setiap partikel per-bingkai. Itu RenderSystemakan bertanggung jawab untuk membangun / mengumpulkan dan menyimpan koleksi partikel saat mereka dibuat dan dihancurkan, dan membuatnya sesuai kebutuhan.

Satu hal yang menyenangkan tentang pendekatan ini adalah Anda tidak perlu memiliki kasus khusus untuk tabrakan, pemusnahan, dll untuk partikel; mereka kode yang Anda tulis untuk setiap jenis entitas lain masih dapat digunakan.

Kesimpulan

Jika Anda mempertimbangkan untuk melakukan lintas-platform - tidak berlaku super untuk JavaScript - semua kode khusus platform Anda (yaitu rendering dan input) diisolasi ke dalam dua sistem. Logika gim Anda tetap berada di kelas platform-agnosit (gerakan, tabrakan, dll.) Sehingga Anda tidak perlu menyentuhnya saat porting.

Saya mengerti dan setuju dengan posisi Sean bahwa hal-hal yang berhubungan dengan sepatu menjadi suatu pola untuk benar-benar mengikuti pola itu, daripada mengubah pola untuk memenuhi kebutuhan aplikasi Anda, itu buruk. Saya hanya tidak melihat apa pun di Input, Kamera atau Partikel yang memerlukan perlakuan semacam itu.


Di mana Anda meletakkan logika untuk mengontrol beberapa kamera (lihat, putar, pindahkan, dll.)?
plasmacel

7

Input dan logika game kemungkinan akan ditangani dalam kode khusus di luar sistem komponen entitas. Secara teknis dimungkinkan untuk memasukkannya ke dalam desain, tetapi ada sedikit manfaatnya - logika permainan dan UI berantakan dan penuh abstraksi bocor tidak peduli apa yang Anda lakukan, dan mencoba untuk memaksa pasak persegi ke dalam lubang bundar hanya karena kemurnian arsitektur adalah pemborosan waktu.

Demikian juga, penghasil partikel adalah binatang buas khusus, terutama jika Anda benar-benar peduli tentang kinerja. Komponen emitor masuk akal, tetapi grafik akan melakukan beberapa sihir khusus dengan komponen-komponen itu, dicampur dengan sihir selama rendering lainnya.

Mengenai kamera Anda, cukup beri kamera bendera yang aktif dan mungkin indeks "kedalaman", dan biarkan sistem grafis membuat semuanya yang diaktifkan. Ini sebenarnya berguna untuk banyak trik, termasuk GUI (ingin GUI Anda dirender dalam mode ortografis di atas dunia game? Tidak masalah, mereka hanya dua kamera dengan topeng objek berbeda dan GUI diatur ke lapisan yang lebih tinggi). Ini juga berguna untuk lapisan efek khusus dan semacamnya.


4

Apakah kamera akan menjadi entitas atau hanya komponen?

Saya tidak yakin apa pertanyaan ini sebenarnya. Mengingat bahwa satu-satunya hal yang Anda miliki dalam permainan adalah entitas, maka kamera harus menjadi entitas. Fungsi kamera diimplementasikan melalui semacam komponen kamera. Jangan memiliki komponen "Posisi" dan "Rotasi" yang terpisah - yang terlalu rendah. Mereka harus digabungkan menjadi semacam komponen WorldPosition yang akan berlaku untuk setiap entitas yang terletak di dunia. Adapun yang harus digunakan ... Anda harus mendapatkan logika ke dalam sistem entah bagaimana. Entah Anda menyandikannya ke dalam sistem penanganan kamera Anda, atau Anda melampirkan skrip, atau sesuatu. Anda dapat memiliki bendera yang diaktifkan / dinonaktifkan pada komponen kamera jika itu membantu.

Saya cukup yakin bahwa partikel itu sendiri tidak harus menjadi entitas

Saya juga. Sebuah emitor partikel akan menjadi entitas, dan sistem partikel akan melacak partikel yang terkait dengan entitas yang diberikan. Hal-hal seperti ini adalah di mana Anda menyadari bahwa "semuanya adalah entitas" bukan kepalang yang tidak praktis. Dalam praktiknya, satu-satunya hal yang merupakan entitas adalah objek yang relatif kompleks yang mendapat manfaat dari kombinasi komponen.

Adapun Input: input tidak ada di dunia game seperti itu sehingga ditangani oleh suatu sistem. Belum tentu 'sistem komponen' karena tidak semua yang ada di gim Anda akan berputar di sekitar komponen. Tetapi akan ada sistem input. Anda mungkin ingin menandai entitas yang merespons input dengan semacam komponen Player, tetapi inputnya akan kompleks dan sepenuhnya spesifik game sehingga tidak ada gunanya mencoba membuat komponen untuk ini.


1

Inilah beberapa ide saya untuk menyelesaikan masalah ini. Mereka mungkin akan memiliki sesuatu yang salah dengan mereka, dan mungkin akan ada pendekatan yang lebih baik, jadi tolong, arahkan saya kepada mereka yang menjawab!

Kamera :

Ada komponen "Kamera", yang dapat ditambahkan ke entitas apa pun. Saya tidak dapat benar-benar mengetahui data apa yang harus saya masukkan ke dalam komponen ini: saya dapat memisahkan komponen "Posisi" dan "Rotasi"! The followmetode tidak perlu dilaksanakan, karena sudah mengikuti entitas itu melekat! Dan saya bebas untuk memindahkannya. Masalah dengan sistem ini akan banyak objek kamera yang berbeda: bagaimana bisa RendererSystemtahu mana yang harus digunakan? Dan juga, saya dulu hanya melewati objek kamera, tetapi sekarang tampaknya RendererSystemkebutuhan untuk beralih dua kali dari semua entitas: pertama untuk menemukan yang bertindak seperti kamera, dan kedua, untuk benar-benar membuat semuanya.

ParticleEmitter :

Akan ada ParticleSystemyang akan memperbarui semua entitas yang memiliki komponen "Emitter". Partikel adalah benda bodoh dalam ruang koordinat relatif, di dalam komponen itu. Ada masalah render di sini: Saya perlu membuat ParticleRenderersistem, atau memperluas fungsionalitas yang sudah ada.

Sistem input :

Perhatian utama bagi saya di sini adalah logika, atau react()metode. Satu-satunya solusi yang saya temukan adalah sistem terpisah untuk itu, dan komponen untuk setiap sistem, yang akan menunjukkan mana yang akan digunakan. Ini benar-benar terlihat terlalu berantakan, dan saya tidak tahu bagaimana cara menanganinya dengan baik. Satu hal adalah, selama saya khawatir, Inputbisa tetap diimplementasikan sebagai kelas, tetapi saya tidak melihat bagaimana saya bisa mengintegrasikannya ke sisa permainan.


Sebenarnya tidak ada alasan bagi RendererSystem untuk beralih ke semua entitas - ia seharusnya sudah memiliki daftar drawable (dan kamera, dan lampu (kecuali lampu drawable)), atau tahu di mana daftar tersebut berada. Selain itu, Anda mungkin ingin melakukan pemusnahan untuk kamera yang ingin Anda render, jadi mungkin kamera Anda bisa berisi daftar ID entitas yang dapat digambar yang dapat dilihat. Anda dapat memiliki banyak kamera dan satu yang aktif, atau satu kamera yang terhubung dengan POV yang berbeda, yang keduanya dapat dikontrol oleh sejumlah hal, seperti skrip dan pemicu dan input

@ melak47, itu benar, aku juga memikirkannya, tapi aku ingin menerapkannya seperti Aremis melakukannya. Tetapi "sistem ini menyimpan referensi ke entitas yang relevan" tampaknya semakin banyak cacat ...
jcora

Bukankah Artemis menyimpan setiap tipe Komponen dalam daftar itu sendiri? jadi tidakkah Anda memiliki daftar komponen yang dapat ditarik, komponen kamera, lampu, dan apa yang tidak ada di suatu tempat?
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.