Katı bir OO tasarımından Entity-Component-System (ECS) tasarımına kadar biraz deneyimden bahsedeceğim.
Bir süre önce tıpkı sizin gibiydim , benzer özelliklere sahip bir dizi farklı şeyim vardı ve çeşitli nesneler inşa ettim ve çözmek için miras kullanmaya çalıştım. Çok zeki bir insan bana bunu yapmadığını ve bunun yerine Entity-Component-System'ı kullandığını söyledi.
Şimdi, ECS büyük bir kavram ve doğru olmak zor. Varlıkları, bileşenleri ve sistemleri düzgün bir şekilde inşa eden çok fazla iş var. Bunu yapmadan önce terimleri tanımlamamız gerekir.
- Varlık : bu şey , oyuncu, hayvan, NPC, her neyse . Ekli bileşenlere ihtiyaç duyan bir şey.
- Bileşen : Bu, durumunuzdaki "Ad" veya "Yaş" veya "Ebeveynler" gibi özellik veya özelliktir .
- Sistem : Bu, bir bileşenin veya davranışın arkasındaki mantıktır . Genellikle, bileşen başına bir sistem oluşturursunuz, ancak bu her zaman mümkün değildir. Ayrıca, bazen sistemlerin diğer sistemleri de etkilemesi gerekir .
İşte bununla nereye gideceğim:
Her şeyden önce, ID
karakterleriniz için bir oluşturun . An int
, Guid
ne istersen. Bu "Varlık" tır.
İkincisi, yaşadığınız farklı davranışları düşünmeye başlayın. "Aile Ağacı" gibi şeyler - bu bir davranış. Varlık üzerinde öznitelik olarak modellemek yerine, tüm bu bilgileri içeren bir sistem oluşturun . Sistem daha sonra onunla ne yapacağına karar verebilir.
Benzer şekilde, "Karakter canlı mı, ölü mü?" Bu, tasarımınızdaki en önemli sistemlerden biridir, çünkü diğerlerini etkiler. Bazı sistemler "ölü" karakterleri ("hareketli grafik" sistemi gibi) silebilirken, diğer sistemler yeni durumu daha iyi desteklemek için işleri dahili olarak yeniden düzenleyebilir.
Örneğin, bir "Sprite" veya "Çizim" veya "Oluşturma" sistemi oluşturacaksınız. Bu sistem, karakterin hangi hareketli grafikle gösterilmesi gerektiğini ve nasıl gösterileceğini belirleme sorumluluğuna sahip olacaktır. Ardından, bir karakter öldüğünde onları kaldırın.
Ek olarak, bir karaktere ne yapacağını, nereye gideceğini vb. Söyleyebilen bir "AI" sistemi. Bu, diğer birçok sistemle etkileşime girmeli ve bunlara dayalı kararlar almalıdır. Yine, ölü karakterler muhtemelen bu sistemden kaldırılabilir, çünkü artık hiçbir şey yapmıyorlar.
"Ad" sisteminiz ve "Aile Ağacı" sisteminiz muhtemelen karakteri (canlı veya ölü) bellekte tutmalıdır. Bu sistemin, karakterin durumu ne olursa olsun bu bilgiyi hatırlaması gerekir. (Jim onu gömdükten sonra bile hala Jim'dir.)
Bu aynı zamanda bir sistem daha verimli tepki verdiğinde değiştirme avantajı sağlar : sistemin kendi zamanlayıcısı vardır. Bazı sistemlerin hızlı bir şekilde ateş etmesi gerekir, bazılarının ateş etmemesi gerekir. Burası, bir oyunu verimli bir şekilde çalıştıran şeyin içine girmeye başladığımız yerdir. Havayı her milisaniyede bir yeniden hesaplamamız gerekmiyor, muhtemelen her 5 ya da daha fazla.
Aynı zamanda size daha yaratıcı bir kaldıraç sağlar: A'dan B'ye bir yolun hesaplanmasını işleyebilen ve gerektiğinde güncelleyebilen bir "Yol Bulucu" sistemi oluşturabilir, Hareket sisteminin "nerede yapmam gerekir? sonrakine git?" Artık bu endişeleri ve nedenlerini daha etkin bir şekilde ayırabiliriz. Hareketin yolu bulmasına gerek yok, sadece oraya gitmeniz gerekiyor.
Bir sistemin bazı kısımlarını dışarıya maruz bırakmak isteyeceksiniz. Senin içinde Pathfinder
sistemin muhtemelen isteyeceksiniz Vector2 NextPosition(int entity)
. Bu şekilde, bu öğeleri sıkı denetimli dizilerde veya listelerde tutabilirsiniz. struct
Bileşenleri, sistem güncellemelerini çok daha hızlı hale getirebilecek daha küçük, bitişik bellek bloklarında tutmanıza yardımcı olabilecek daha küçük türler kullanabilirsiniz . (Özellikle bir sistem üzerindeki dış etkiler asgari düzeyde ise, şimdi yalnızca bunun iç durumunu dikkate alması gerekir Name
.)
Ama, bunu yeterince vurgulayamıyorum, şimdi an Entity
sadece ID
fayans, nesne vb. İçeren bir. Bir varlık bir sisteme ait değilse, sistem onu izlemez. Bu, "Ağaç" nesnelerimizi oluşturabildiğimiz, bunları Sprite
ve Movement
sistemlerinde saklayabileceğimiz anlamına gelir (ağaçlar hareket etmez, ancak "Konum" bileşenine sahiptir) ve bunları diğer sistemlerin dışında tutabiliriz. Artık ağaç için özel bir listeye ihtiyacımız yok, çünkü bir ağaç oluşturmak, kağıt doldurmanın yanı sıra bir karakterden farklı değildir. ( Sprite
Sistemin kontrol edebileceği veya Paperdoll
sistemin kontrol edebileceği.) Şimdi NextPosition
biraz yeniden yazılabilir: Vector2? NextPosition(int entity)
ve null
umursamadığı varlıklar için bir konum döndürebilir . Bunu da kendimize NameSystem.GetName(int entity)
uyguluyoruz null
, ağaçlar ve kayalar için geri dönüyor .
Bunu sonuna kadar çizeceğim, ancak burada fikir size ECS hakkında biraz arka plan vermek ve oyununuzda daha iyi bir tasarım sağlamak için gerçekten nasıl kullanabileceğinizdir. Performansı artırabilir, alakasız öğeleri çözebilir ve işleri daha düzenli bir şekilde tutabilirsiniz. (Eğer varsa ben çok F # kontrol tavsiye F # ve LINQ gibi bu da çiftleri de fonksiyonel dilleri / kurulumları, değil zaten, bu çiftleri çok iyi C # ile size birlikte kullanıldıklarında.)