Ini adalah pertanyaan yang sulit dijawab karena setiap orang memiliki ide sendiri tentang bagaimana sistem komponen entitas harus disusun. Hal terbaik yang dapat saya lakukan adalah membagikan kepada Anda beberapa hal yang menurut saya paling berguna bagi saya.
Kesatuan
Saya mengambil pendekatan kelas lemak untuk ECS, mungkin karena saya menemukan metode pemrograman ekstrim menjadi sangat tidak efisien (dalam hal produktivitas manusia). Untuk itu, entitas bagi saya adalah kelas abstrak untuk diwarisi oleh kelas yang lebih khusus. Entitas memiliki sejumlah properti virtual dan bendera sederhana yang memberi tahu saya apakah entitas ini harus ada atau tidak. Jadi relatif terhadap pertanyaan Anda tentang sistem render, seperti inilah Entity
tampilannya:
public abstract class Entity {
public bool IsAlive = true;
public virtual SpatialComponent Spatial { get; set; }
public virtual ImageComponent Image { get; set; }
public virtual AnimationComponent Animation { get; set; }
public virtual InputComponent Input { get; set; }
}
Komponen
Komponen "bodoh" karena mereka tidak melakukan atau tahu apa - apa. Mereka tidak memiliki referensi ke komponen lain, dan mereka biasanya tidak memiliki fungsi (saya bekerja di C #, jadi saya menggunakan properti untuk menangani getter / setter - jika mereka memiliki fungsi, mereka didasarkan pada pengambilan data yang mereka pegang).
Sistem
Sistem kurang "bodoh", tetapi masih merupakan robot bodoh. Mereka tidak memiliki konteks sistem keseluruhan, tidak memiliki referensi ke sistem lain dan tidak memiliki data kecuali untuk beberapa buffer yang mereka mungkin perlu melakukan pemrosesan masing-masing. Bergantung pada sistemnya, ia mungkin memiliki spesialisasi Update
, atau Draw
metode, atau dalam beberapa kasus, keduanya.
Antarmuka
Antarmuka adalah struktur utama dalam sistem saya. Mereka digunakan untuk mendefinisikan apa yang System
bisa diproses, dan apa yang Entity
mampu dilakukan. Antarmuka yang relevan untuk rendering adalah: IRenderable
dan IAnimatable
.
Antarmuka hanya memberitahu sistem komponen mana yang tersedia. Misalnya, sistem rendering perlu mengetahui kotak pembatas entitas dan gambar yang akan digambar. Dalam kasus saya, itu akan menjadi SpatialComponent
dan ImageComponent
. Jadi sepertinya ini:
public interface IRenderable {
SpatialComponent Component { get; }
ImageComponent Image { get; }
}
Sistem Rendering
Jadi bagaimana sistem rendering menarik entitas? Ini sebenarnya cukup sederhana, jadi saya hanya akan menunjukkan kepada Anda kelas telanjang untuk memberi Anda ide:
public class RenderSystem {
private SpriteBatch batch;
public RenderSystem(SpriteBatch batch) {
this.batch = batch;
}
public void Draw(List<IRenderable> list) {
foreach(IRenderable obj in list) {
this.batch.draw(
obj.Image.Texture,
obj.Spatial.Position,
obj.Image.Source,
Color.White);
}
}
}
Melihat kelas, sistem render bahkan tidak tahu apa Entity
itu. Yang ia tahu hanyalah IRenderable
dan hanya diberi daftar mereka untuk menggambar.
Bagaimana Ini Semua Bekerja
Mungkin juga membantu untuk memahami bagaimana saya membuat objek game baru dan bagaimana saya memasukkannya ke sistem.
Menciptakan Entitas
Semua objek game mewarisi dari Entity, dan semua antarmuka yang berlaku yang menjelaskan apa yang bisa dilakukan objek game itu. Semua yang dianimasikan di layar terlihat seperti ini:
public class MyAnimatedWidget : Entity, IRenderable, IAnimatable {}
Memberi Makan Sistem
Saya menyimpan daftar semua entitas yang ada di dunia game dalam satu daftar bernama List<Entity> gameObjects
. Setiap frame, saya kemudian menyaring daftar itu dan menyalin referensi objek ke lebih banyak daftar berdasarkan jenis antarmuka, seperti List<IRenderable> renderableObjects
, dan List<IAnimatable> animatableObjects
. Dengan cara ini, jika sistem yang berbeda perlu memproses entitas yang sama, mereka bisa. Kemudian saya hanya menyerahkan daftar itu ke masing-masing sistem Update
atau Draw
metode dan membiarkan sistem melakukan pekerjaan mereka.
Animasi
Anda mungkin ingin tahu bagaimana sistem animasi bekerja. Dalam kasus saya, Anda mungkin ingin melihat antarmuka IAnimatable:
public interface IAnimatable {
public AnimationComponent Animation { get; }
public ImageComponent Image { get; set; }
}
Hal utama yang perlu diperhatikan di sini adalah ImageComponent
aspek IAnimatable
antarmuka tidak hanya baca; ia memiliki setter .
Seperti yang sudah Anda duga, komponen animasi hanya menyimpan data tentang animasi; daftar frame (yang merupakan komponen gambar), frame saat ini, jumlah frame per detik yang akan diambil, waktu yang berlalu sejak peningkatan frame terakhir, dan opsi lainnya.
Sistem animasi mengambil keuntungan dari sistem rendering dan hubungan komponen gambar. Itu hanya mengubah komponen gambar entitas karena ia menambah bingkai animasi. Dengan begitu, animasi diberikan secara tidak langsung oleh sistem rendering.