Melakukan powerups dalam sistem berbasis komponen

29

Saya baru mulai benar-benar memahami desain berbasis komponen. Saya tidak tahu apa cara "benar" untuk melakukan ini.

Inilah skenarionya. Pemain bisa menggunakan perisai. Perisai digambarkan sebagai gelembung di sekitar pemain, ia memiliki bentuk tabrakan yang terpisah, dan mengurangi kerusakan yang diterima pemain dari efek area.

Bagaimana tameng seperti itu dirancang dalam game berbasis komponen?

Di mana saya bingung adalah bahwa perisai jelas memiliki tiga komponen yang terkait dengannya.

  • Pengurangan kerusakan / penyaringan
  • Sebuah sprite
  • Seorang collider.

Untuk membuatnya lebih buruk, variasi perisai yang berbeda dapat memiliki lebih banyak perilaku, yang semuanya dapat menjadi komponen:

  • meningkatkan kesehatan maksimum pemain
  • regen kesehatan
  • defleksi proyektil
  • dll

  1. Apakah saya terlalu memikirkan ini? Haruskah perisai hanya menjadi komponen super?
    Saya pikir ini jawaban yang salah. Jadi jika Anda pikir ini adalah cara untuk pergi tolong jelaskan.

  2. Haruskah perisai menjadi entitasnya sendiri yang melacak lokasi pemain?
    Itu mungkin membuat sulit untuk menerapkan penyaringan kerusakan. Ini juga agak mengaburkan garis antara komponen dan entitas yang terpasang.

  3. Haruskah perisai menjadi komponen yang menampung komponen lainnya?
    Saya belum pernah melihat atau mendengar hal seperti ini, tapi mungkin itu biasa dan saya belum cukup dalam.

  4. Haruskah perisai hanya set komponen yang ditambahkan ke pemain?
    Mungkin dengan komponen tambahan untuk mengelola yang lain, misalnya agar mereka semua dapat dihapus sebagai grup. (Tanpa sengaja meninggalkan komponen pengurangan kerusakan, sekarang akan menyenangkan).

  5. Hal lain yang jelas bagi seseorang dengan lebih banyak pengalaman komponen?

deft_code
sumber
Saya mengambil kebebasan untuk membuat judul Anda lebih spesifik.
Tetrad

Jawaban:

11

Haruskah perisai menjadi entitasnya sendiri yang melacak lokasi pemain? Itu mungkin membuat sulit untuk menerapkan penyaringan kerusakan. Ini juga agak mengaburkan garis antara komponen dan entitas yang terpasang.

Sunting: Saya pikir tidak ada "perilaku otonom" yang cukup untuk entitas yang terpisah. Dalam kasus khusus ini, perisai mengikuti target, bekerja untuk target dan tidak hidup lebih lama dari target. Walaupun saya cenderung setuju bahwa tidak ada yang salah dengan konsep "objek pelindung", dalam hal ini kita berurusan dengan perilaku, yang cocok dengan komponen. Tapi saya juga seorang penganjur entitas logis murni (sebagai lawan dari sistem entitas full-blown di mana Anda dapat menemukan komponen Transform dan Rendering).

Haruskah perisai menjadi komponen yang menampung komponen lainnya? Saya belum pernah melihat atau mendengar hal seperti ini, tapi mungkin itu biasa dan saya belum cukup dalam.

Lihat dalam perspektif yang berbeda; menambahkan komponen menambahkan komponen lain juga, dan setelah dihapus, komponen tambahan juga hilang.

Haruskah perisai hanya set komponen yang ditambahkan ke pemain? Mungkin dengan komponen tambahan untuk mengelola yang lain, misalnya sehingga mereka semua dapat dihapus sebagai grup. (Tanpa sengaja meninggalkan komponen pengurangan kerusakan, sekarang akan menyenangkan).

Ini bisa menjadi solusi, itu akan mempromosikan penggunaan kembali, namun juga lebih rentan kesalahan (untuk masalah yang Anda sebutkan, misalnya). Itu tidak selalu buruk. Anda mungkin menemukan kombinasi mantra baru dengan coba-coba :)

Hal lain yang jelas bagi seseorang dengan lebih banyak pengalaman komponen?

Saya akan menguraikan sedikit.

Saya yakin Anda memperhatikan bagaimana beberapa komponen harus diprioritaskan tidak peduli kapan mereka telah ditambahkan ke entitas (ini akan menjawab pertanyaan Anda yang lain juga).

Saya juga akan menganggap kita menggunakan komunikasi berbasis pesan (demi diskusi, itu hanya abstraksi atas panggilan metode untuk saat ini).

Setiap kali komponen pelindung "dipasang", penangan pesan komponen pelindung dirantai dengan urutan tertentu (lebih tinggi).

Handler Stage    Handler Level     Handler Priority
In               Pre               System High
Out              Invariant         High
                 Post              AboveNormal
                                   Normal
                                   BelowNormal
                                   Low
                                   System Low

In - incoming messages
Out - outgoing messages
Index = ((int)Level | (int)Priority)

Komponen "stats" menginstal pawang pesan "damage" di indeks In / Invariant / Normal. Setiap kali pesan "kerusakan" diterima, kurangi HP dengan jumlah "nilainya".

Perilaku standar yang adil (dimasukkan ke dalam beberapa resistensi kerusakan alami dan / atau sifat ras, apa pun).

Komponen perisai menginstal pawang pesan "kerusakan" di indeks In / Pre / High.

Every time a "damage" message is received, deplete the shield energy and substract
the shield energy from the damage value, so that the damage down the message
handler pipeline is reduced.

damage -> stats
    stats
        stats.hp -= damage.value

damage -> shield -> stats
    shield
        if(shield.energy) {
            remove_me();
            return;
        }
        damage.value -= shield.energyquantum
        shield.energy -= shield.energyquantum;

     stats
        stats.hp -= damage.value

Anda dapat melihat ini cukup fleksibel, meskipun itu akan memerlukan perencanaan yang cermat ketika mendesain interaksi komponen, karena Anda harus menentukan di bagian mana dari pesan penanganan pipa menangani pesan komponen komponen handler yang diinstal.

Masuk akal? Beri tahu saya jika saya dapat menambahkan lebih banyak detail.

Sunting: mengenai beberapa komponen komponen (dua komponen pelindung). Anda bisa melacak jumlah instance total hanya dalam satu instance entitas (namun, ini membunuh status per-komponen) dan tetap menambahkan penangan event pesan, atau memastikan kontainer komponen Anda memperbolehkan jenis komponen duplikat di muka.

Raine
sumber
Anda telah menjawab "Tidak" untuk pertanyaan pertama tanpa memberikan alasan apa pun. Mengajar orang lain adalah tentang membantu mereka memahami alasan di balik keputusan apa pun. IMO, fakta bahwa dalam RL medan gaya akan menjadi "entitas fisik" yang terpisah dari tubuh Anda sendiri sudah cukup untuk menjadikannya entitas yang terpisah dalam kode. Bisakah Anda menyarankan alasan bagus untuk menyarankan mengapa rute ini buruk?
Insinyur
@Nick, saya sama sekali tidak mencoba mengajarkan apa pun kepada siapa pun, melainkan berbagi apa yang saya ketahui tentang masalah ini. Namun saya akan menambahkan alasan di balik "tidak" yang mudah-mudahan akan menghapus downvote yang tidak menyenangkan :(
Raine
Titik otonomi Anda masuk akal. Tetapi Anda perhatikan: "dalam hal ini kita berurusan dengan perilaku". Benar - perilaku yang melibatkan objek fisik yang sepenuhnya terpisah (bentuk benturan perisai). Bagi saya, satu entitas terikat dengan satu tubuh fisika (atau kumpulan senyawa tubuh yang terhubung misalnya dengan sendi). Bagaimana Anda mendamaikan ini? Bagi saya, saya akan merasa tidak nyaman menambahkan perlengkapan fisik "boneka" yang hanya akan aktif jika pemain menggunakan perisai. IMO tidak fleksibel, sulit dipertahankan di semua entitas. Pertimbangkan juga, sebuah permainan di mana sabuk pelindung menjaga perisai tetap bahkan setelah kematian (Dune).
Insinyur
@Nick, mayoritas sistem entitas memiliki baik komponen logis dan yang berhubungan dengan grafis, jadi, dalam hal ini, memiliki entitas untuk perisai benar-benar masuk akal. Dalam sistem entitas yang sepenuhnya logis, "otonomi" adalah produk dari seberapa kompleks suatu objek, ketergantungannya, dan masa pakainya. Pada akhirnya, persyaratan adalah raja - dan mengingat bahwa tidak ada konsensus nyata tentang apa itu sistem entitas, ada banyak ruang untuk solusi yang disesuaikan dengan proyek :)
Raine
@deft_code, beri tahu saya jika saya dapat meningkatkan jawaban saya.
Raine
4

1) Apakah saya terlalu memikirkan ini? Haruskah perisai hanya menjadi komponen super?

Mungkin, tergantung pada seberapa dapat digunakan kembali kode yang Anda inginkan dan apakah itu masuk akal.

2) Haruskah perisai menjadi entitasnya sendiri yang melacak lokasi pemain?

Tidak, kecuali tameng ini adalah sejenis makhluk yang bisa berjalan secara independen pada tahap tertentu.

3) Haruskah perisai menjadi komponen yang menampung komponen lain?

Ini terdengar sangat mirip entitas, jadi jawabannya tidak.

4) Haruskah perisai hanya set komponen yang ditambahkan ke pemain?

Kemungkinan.

"Pengurangan / penyaringan kerusakan"

  • fungsionalitas komponen pelindung inti.

"Sebuah sprite"

  • adakah alasan Anda tidak dapat menambahkan SpriteComponent lain ke entitas karakter Anda (dengan kata lain lebih dari satu komponen tipe tertentu per entitas)?

"Seorang collider"

  • Anda yakin perlu yang lain? Ini tergantung pada mesin fisika Anda. Bisakah Anda mengirim pesan ke ColliderComponent entitas karakter dan memintanya untuk berubah bentuk?

"Tingkatkan kesehatan maksimal pemain, regen kesehatan, defleksi proyektil dll."

  • artefak lain mungkin dapat melakukan ini (pedang, sepatu bot, cincin, mantra / ramuan / kuil kunjungan dll) jadi ini harus menjadi komponen.
Sarang
sumber
3

Perisai, sebagai entitas fisik , tidak berbeda dari fisik lainnya entitas , misalnya drone yang melingkari Anda (dan yang pada kenyataannya, itu sendiri bisa menjadi semacam perisai!). Jadi buatlah perisai sebagai entitas logis yang terpisah (sehingga memungkinkannya untuk memegang komponennya sendiri).

Berikan perisai Anda beberapa komponen: komponen Fisik / Spasial untuk mewakili bentuk tumbukannya, dan komponen DamageAffector yang memegang referensi ke beberapa entitas yang akan menerapkan peningkatan atau pengurangan kerusakan (mis. Karakter pemain Anda) setiap kali entitas memegang DamageAffector akan rusak. Dengan demikian pemain Anda menerima kerusakan "oleh proxy".

Atur posisi entitas perisai ke posisi pemain setiap centang. (Tulis kelas komponen yang dapat digunakan kembali yang melakukan ini: tulis sekali, gunakan berkali-kali.)

Anda harus membuat entitas pelindung, mis. tentang mengumpulkan powerup. Saya menggunakan konsep generik yang disebut Emitter, yang merupakan jenis komponen entitas yang memunculkan entitas baru (biasanya melalui penggunaan EntityFactory yang dirujuk). Di mana Anda memutuskan untuk menemukan emitor terserah Anda - mis. letakkan di powerup dan picu ketika powerup dikumpulkan.


Haruskah perisai menjadi entitasnya sendiri yang melacak lokasi pemain? Itu mungkin membuat sulit untuk menerapkan penyaringan kerusakan. Ini juga agak mengaburkan garis antara komponen dan entitas yang terpasang.

Ada garis tipis antara subkomponen logis (Spasial, AI, slot senjata, Pemrosesan input, dll.) Dan subkomponen fisik. Anda perlu memutuskan sisi mana Anda berdiri, karena ini sangat menentukan apa jenis sistem entitas yang Anda miliki. Bagi saya, subkomponen Fisika dari Entitas saya menangani hubungan fisika-hierarkis (seperti tungkai dalam tubuh - pikirkan node scenegraph), sedangkan pengontrol logika yang disebutkan di atas biasanya apa yang diwakili oleh komponen entitas Anda - daripada yang mewakili "perlengkapan" fisik individu.

Insinyur
sumber
3

Haruskah perisai menjadi komponen yang menampung komponen lainnya?

Mungkin tidak merumahkan komponen lain, tetapi mengontrol masa pakai sub komponen. Jadi dalam beberapa kode pseudo kasar, kode klien Anda akan menambahkan komponen "perisai" ini.

class Shield : Component
{
    void Start() // happens when the component is added
    {
        sprite = entity.add_component<Sprite>( "shield" );
        collider = entity.add_component<Collider>( whatever );
        //etc
    }

    void OnDestroy() // when the component is removed
    {
        entity.remove_component( sprite );
        entity.remove_component( collider );
    }

    void Update() // every tick
    {
        if( ShouldRemoveSelf() ) // probably time based or something
            entity.remove_component( this );
    }
}
Tetrad
sumber
Tidak jelas apa thisartinya dalam jawaban Anda. Apakah thismengacu pada komponen Shield atau maksud Anda entitas yang menggunakan pelindung, induknya? Kebingungan mungkin salahku. "Berbasis komponen" agak kabur. Dalam versi saya entitas berbasis komponen, sebuah entitas hanyalah sebuah wadah komponen dengan beberapa fungsi minimal sendiri (nama objek, tag, pesan, dll).
deft_code
Akan lebih membingungkan jika saya menggunakan gameObjectatau sesuatu. Ini adalah referensi ke objek game saat ini / entitas / apa pun yang memiliki komponen.
Tetrad
0

Jika sistem komponen Anda memungkinkan skrip, komponen pelindung bisa jadi hampir merupakan komponen super yang hanya memanggil skrip untuk parameter "efek" nya. Dengan cara itu Anda mempertahankan kesederhanaan komponen tunggal untuk perisai, dan melepaskan semua logika apa yang sebenarnya dilakukannya pada file skrip khusus yang diumpankan ke perisai dengan definisi entitas Anda.

Saya melakukan sesuatu yang mirip dengan komponen Moveable saya, itu menghitung bidang yang merupakan skrip reaksi kunci (subkelas skrip di mesin saya) skrip ini mendefinisikan metode yang mengikuti pesan input saya. karena itu saya bisa melakukan sesuatu seperti ini di file definisi tempalte saya

camera template
    moveable
    {
        keyreaction = "scriptforcameramoves"

    }  

player template
    moveable
    {
        keyreaction = "scriptfroplayerkeypress"

    }  

kemudian di komponen saya yang dapat dipindahkan saat mendaftar pesan saya mendaftarkan metode scripts Do (kode dalam C #)

Owner.RegisterHandler<InputStateInformation>(MessageType.InputUpdate, kScript.Do);

tentu saja ini bergantung pada metode Do saya mengikuti pola fungsi yang diambil RegisterHandler saya. Dalam hal ini (Pengirim IComponent, argumen tipe ref)

jadi "script" saya (dalam kasus saya juga C # runime dikompilasi) mendefinisikan

 public class CameraMoveScript : KeyReactionScript
{
 public override void Do(IComponent pSender, ref InputStateInformation inputState)
 {
    //code here
 }
}

dan kelas dasar saya KeyReactionScript

public class KeyReactionScript : Script
{
      public virtual void Do(IComponent pSender, ref InputStateInformation inputState);
}

lalu nanti ketika komponen input mengirim pesan bertipe MessageTypes.InputUpdate dengan jenisnya

 InputStateInformation myInputState = InputSystem.GetInputState();
 SendMessage<InputStateInformation>(MessageTypes.InputUpdate, ref myInputState);

Metode dalam skrip yang terikat pada pesan dan tipe data tersebut akan diaktifkan dan menangani semua logika.

Kode ini cukup spesifik untuk mesin saya, tetapi logikanya harus fungsional dalam hal apapun. Saya melakukan ini untuk banyak jenis untuk menjaga struktur komponen tetap sederhana dan fleksibel.

exnihilo1031
sumber