Bir Varlık Bileşen Sistemi ayırma / bilgi gizleme için korkunç değil mi?


11

Başlık kasıtlı olarak hiperboliktir ve sadece desenle deneyimim olmayabilir, ancak işte mantığım:

Varlıkları uygulamanın "olağan" veya tartışmasız açık yolu, onları nesne olarak uygulamak ve ortak davranışı alt sınıflamaktır. Bu klasik soruna yol açar " EvilTreebir alt sınıfı Treeveya Enemy?". Birden fazla mirasa izin verirsek, elmas problemi ortaya çıkar. Bunun yerine , Tanrı sınıflarına götüren hiyerarşinin birleşik işlevselliğini Treeve Enemydaha da üstünü alabiliriz veya kasıtlı olarak bizim Treeve Entitysınıflarımızdaki davranışları (aşırı durumda arayüzler haline getirerek) dışarıda bırakabiliriz EvilTree; kod çoğaltma hiç varsa SomewhatEvilTree.

Varlık-Bileşen Sistemleri bu sorunu, Treeve Enemynesneyi farklı bileşenlere (örneğin Position, Healthve AI- bölerek) bölerek çözmeye çalışır ve örneğin, AISystembir Yetki'nin konumunu AI kararlarına göre değiştiren sistemler gibi . Şimdiye kadar çok iyi ama EvilTreebir powerup alabilir ve hasar verebilirse ne olur ? Öncelikle a CollisionSystemve a'ya ihtiyacımız var DamageSystem(muhtemelen bunlara zaten sahibiz). CollisionSystemİhtiyaçları ile iletişim kurmak için DamageSystem: iki şey çarpışır Her zaman CollisionSystembir mesaj gönderir DamageSystemo çıkarma böylece sağlık. Hasar aynı zamanda güçlendirmelerden de etkilenir, bu yüzden bunu bir yerde saklamamız gerekir. PowerupComponentVarlıklara eklediğimiz yeni bir öğe mi yaratıyoruz ? Ama sonraDamageSystemhiçbir şey bilmeyeceği bir şey bilmelidir - sonuçta, powerups'ı alamayan hasar veren şeyler de vardır (örneğin a Spike). Bu cevaba benzer hasar hesaplamaları için kullanılan PowerupSystema'nın değiştirilmesine izin veriyor muyuz ? Ancak şimdi iki sistem aynı verilere erişiyor. Oyunumuz daha karmaşık hale geldikçe, bileşenlerin birçok sistem arasında paylaşıldığı somut olmayan bir bağımlılık grafiği haline gelecektir. Bu noktada global statik değişkenleri kullanabilir ve tüm kazan plakasından kurtulabiliriz.StatComponent

Bunu çözmenin etkili bir yolu var mı? Sahip olduğum bir fikir, bileşenlerin belirli işlevlere sahip olmasına izin vermekti, örneğin StatComponent attack(), varsayılan olarak sadece bir tamsayı döndüren ver, ancak bir güçlendirme gerçekleştiğinde oluşturulabilir:

attack = getAttack compose powerupBy(20) compose powerdownBy(40)

Bu, attackbirden çok sistem tarafından erişilen bir bileşende kaydedilmesi gereken sorunu çözmez, ancak en azından onu destekleyen bir dil varsa işlevleri düzgün bir şekilde yazabilirim:

// In StatComponent
type Strength = PrePowerup | PostPowerup
type Damage = Int
type PrePowerup = Int
type PostPowerup = Int
attack: Strength = getAttack //default value, can be changed by systems
getAttack: PrePowerup

// these functions can be defined in other components or in PowerupSystems
powerupBy: Strength -> PostPowerup
powerdownBy: Strength -> PostPowerup
subtractArmor: Strength -> Damage

// in DamageSystem
dealDamage: Damage -> () = attack compose subtractArmor compose hurtSomeEntity

Bu şekilde en azından sistemler tarafından eklenen çeşitli fonksiyonların doğru sıralanmasını garanti ederim. Her iki durumda da, burada işlevsel reaktif programlamaya hızla yaklaşıyorum gibi görünüyor, bu yüzden kendime bunu başından beri kullanmamam gerektiğini soruyorum (sadece FRP'ye baktım, bu yüzden burada yanlış olabilirim). ECS'nin karmaşık sınıf hiyerarşileri üzerinde bir gelişme olduğunu görüyorum ama bunun ideal olduğuna ikna olmadım.

Bunun etrafında bir çözüm var mı? ECS'yi daha temiz bir şekilde ayırmak için kaçırdığım bir işlevsellik / desen var mı? FRP bu sorun için kesinlikle daha uygun mu? Bu sorunlar sadece programlamaya çalıştığım şeyin doğasında var olan karmaşıklıktan mı kaynaklanıyor; yani FRP'nin benzer sorunları olur mu?



Eric'in blogunu gerçekten özlüyorum (C # hakkında olduğu zamandan itibaren).
OldFart

Yanıtlar:


21

ECS veri gizlemeyi tamamen mahveder. Bu, modelin değiş tokuşudur.

ECS ayırmada mükemmeldir . İyi bir ECS, bir hareket sisteminin, hangi varlık türlerinin mevcut olduğunu veya bu bileşenlere hangi diğer sistemlerin eriştiğini umursamadan, hızı ve pozisyon bileşeni olan herhangi bir varlık üzerinde çalıştığını bildirmesine izin verir. Bu, en azından oyun nesnelerinin belirli arayüzleri uygulamasına olan gücü ayırmada eşdeğerdir.

Aynı bileşenlere erişen iki sistem sorun değil bir özelliktir. Tam olarak beklenir ve sistemleri hiçbir şekilde birleştirmez. Sistemlerin örtük bir bağımlılık grafiğine sahip olacağı doğrudur, ancak bu bağımlılıklar modellenen dünyanın doğasında vardır. Hasar sisteminin güçlendirme sistemine örtük bir bağımlılığa sahip olmaması gerektiğini söylemek, güç artışlarının hasarı etkilemediğini iddia etmek ve muhtemelen yanlıştır. Bununla birlikte, bağımlılık mevcut olsa da, sistemler birleştirilmez - hasar sistemini etkilemeden powerup sistemini oyundan kaldırabilirsiniz, çünkü iletişim stat bileşeni aracılığıyla gerçekleşti ve tamamen örtüktü.

Bu bağımlılıkların ve sipariş sistemlerinin çözülmesi, bir DI sistemindeki bağımlılık çözümlemesinin nasıl çalıştığına benzer şekilde tek bir merkezi konumda yapılabilir. Evet, karmaşık bir oyun karmaşık bir sistem grafiğine sahip olacak, ancak bu karmaşıklık doğası gereği ve en azından içeriyor.


7

Bir sistemin birden fazla bileşene erişmesi gerektiğinin hemen hemen hiçbir yolu yoktur. VelocitySystem gibi bir şeyin çalışması için muhtemelen bir VelocityComponent ve PositionComponent'e erişmesi gerekir. Bu arada RenderingSystem'ın da bu verilere erişmesi gerekiyor. Ne yaparsanız yapın, bir noktada oluşturma sisteminin nesneyi nerede oluşturacağını ve VelocitySystem'ın nesneyi nereye taşıyacağını bilmesi gerekir.

Bunun için ihtiyaç duyduğunuz şey bağımlılıkların açık olmasıdır. Her sistem ihtiyaçları olduğu açık o okuyacak ve hangi verilerin bunun için yazacak hangi verileri hakkında. Bir sistem belirli bir bileşeni almak istediğinde, bunu yalnızca açıkça yapabilmesi gerekir . En basit haliyle, sadece argüman olarak ihtiyaç duyduğu her türün bileşenlerine sahiptir (örneğin, RenderSystem'ın RenderComponents ve PositionComponents'e ihtiyacı vardır) ve değiştirdiği her şeyi döndürür (örneğin yalnızca RenderComponents).

Bu şekilde en azından sistemler tarafından eklenen çeşitli fonksiyonların doğru sıralanmasını garanti ederim

Böyle bir tasarımda sipariş verebilirsiniz. Hiçbir şey ECS için sistemlerinizin düzenden veya başka bir şeyden bağımsız olması gerektiğini söylemez.

FRP bu sorun için kesinlikle daha uygun mu? Bu sorunlar sadece programlamaya çalıştığım şeyin doğasında var olan karmaşıklıktan mı kaynaklanıyor; yani FRP'nin benzer sorunları olur mu?

Bu Varlık-bileşen-sistem tasarımını ve FRP'yi kullanmak birbirini dışlamaz. Aslında, sistemler sadece veri dönüşümleri (bileşenler) gerçekleştirerek, durumları olmayan başka bir şey olarak görülemez.

FRP, bazı işlemleri gerçekleştirmek için ihtiyaç duyduğunuz bilgileri kullanmak zorunda kalma sorununu çözmez.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.