นี่เป็นคำถามที่ตอบยากเพราะทุกคนมีความคิดของตนเองเกี่ยวกับวิธีการจัดโครงสร้างองค์ประกอบของเอนทิตี สิ่งที่ดีที่สุดที่ฉันสามารถทำได้คือแบ่งปันบางสิ่งที่ฉันพบว่ามีประโยชน์กับฉันมากที่สุด
เอกลักษณ์
ฉันใช้วิธีการระดับไขมันกับ ECS อาจเป็นเพราะฉันพบว่าวิธีการเขียนโปรแกรมแบบสุดขีดไม่มีประสิทธิภาพสูง (ในแง่ของการผลิตของมนุษย์) ด้วยเหตุนี้เอนทิตีสำหรับฉันเป็นคลาสนามธรรมที่จะสืบทอดโดยคลาสพิเศษเพิ่มเติม เอนทิตีมีจำนวนของคุณสมบัติเสมือนจริงและแฟล็กแบบง่ายที่บอกฉันว่าเอนทิตีนี้ควรมีอยู่หรือไม่ ดังนั้นเมื่อเทียบกับคำถามของคุณเกี่ยวกับระบบการแสดงผลนี่คือEntity
ลักษณะที่ปรากฏ:
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; }
}
ส่วนประกอบ
ส่วนประกอบคือ "โง่" โดยที่พวกเขาไม่ได้ทำหรือไม่รู้อะไรเลย พวกเขาไม่มีการอ้างอิงถึงส่วนประกอบอื่น ๆ และโดยทั่วไปแล้วพวกเขาไม่มีฟังก์ชั่น (ฉันทำงานใน C # ดังนั้นฉันจึงใช้คุณสมบัติเพื่อจัดการ getters / setters - ถ้าพวกมันมีฟังก์ชั่น
ระบบ
ระบบนั้น "โง่" น้อยกว่า แต่ก็ยังเป็นแบบอัตโนมัติ พวกเขาไม่มีบริบทของระบบโดยรวมไม่มีการอ้างอิงถึงระบบอื่นและไม่มีข้อมูลยกเว้นบัฟเฟอร์บางตัวที่พวกเขาอาจต้องทำการประมวลผลแต่ละอย่าง ทั้งนี้ขึ้นอยู่กับระบบก็อาจจะมีความเชี่ยวชาญUpdate
หรือDraw
วิธีการหรือในบางกรณีทั้งสอง
อินเตอร์เฟซ
การเชื่อมต่อเป็นโครงสร้างสำคัญในระบบของฉัน พวกเขาจะใช้เพื่อกำหนดสิ่งที่System
กระบวนการสามารถและสิ่งที่มีEntity
ความสามารถ อินเตอร์เฟซที่เกี่ยวข้องกับการแสดงผลมีดังนี้: และIRenderable
IAnimatable
อินเทอร์เฟซจะบอกระบบว่ามีส่วนประกอบใดบ้าง ตัวอย่างเช่นระบบการเรนเดอร์จำเป็นต้องรู้ถึงขอบเขตของเอนทิตีและรูปภาพที่จะวาด ในกรณีของฉันที่จะเป็นและSpatialComponent
ImageComponent
ดังนั้นดูเหมือนว่านี้:
public interface IRenderable {
SpatialComponent Component { get; }
ImageComponent Image { get; }
}
RenderingSystem
ดังนั้นระบบเรนเดอร์จะดึงเอนทิตีอย่างไร จริงๆแล้วมันค่อนข้างง่ายดังนั้นฉันจะแสดงให้คุณเห็นชั้นเรียนที่ถูกปล้นเพื่อให้แนวคิด:
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);
}
}
}
มองไปที่ระดับที่ทำให้ระบบไม่ได้รู้ว่าสิ่งที่Entity
เป็น สิ่งที่รู้เกี่ยวกับIRenderable
มันและมันก็แค่ให้รายชื่อพวกมันวาด
มันทำงานอย่างไร
มันอาจช่วยให้เข้าใจว่าฉันสร้างวัตถุเกมใหม่และวิธีป้อนข้อมูลเหล่านั้นไปยังระบบได้อย่างไร
การสร้างเอนทิตี
วัตถุในเกมทั้งหมดสืบทอดมาจาก Entity และอินเทอร์เฟซที่ใช้งานได้ใด ๆ ที่อธิบายสิ่งที่เกมนั้นสามารถทำได้ ทุกอย่างเกี่ยวกับภาพเคลื่อนไหวบนหน้าจอจะเป็นดังนี้:
public class MyAnimatedWidget : Entity, IRenderable, IAnimatable {}
การให้อาหารระบบ
List<Entity> gameObjects
ฉันเก็บรายชื่อของทุกหน่วยงานที่มีอยู่ในโลกของเกมในรายการเดียวที่เรียกว่า แต่ละเฟรมจากนั้นผมก็ลอดผ่านรายการนั้นและคัดลอกอ้างอิงวัตถุไปยังรายการอื่น ๆ ขึ้นอยู่กับชนิดของอินเตอร์เฟซเช่นและList<IRenderable> renderableObjects
List<IAnimatable> animatableObjects
ด้วยวิธีนี้หากระบบที่แตกต่างกันจำเป็นต้องประมวลผลเอนทิตีเดียวกันพวกเขาสามารถทำได้ จากนั้นฉันก็แค่ส่งรายการเหล่านั้นไปยังแต่ละระบบUpdate
หรือDraw
วิธีการแล้วปล่อยให้ระบบทำงานได้
นิเมชั่น
คุณอาจสงสัยว่าระบบภาพเคลื่อนไหวทำงานอย่างไร ในกรณีของฉันคุณอาจต้องการดูอินเทอร์เฟซ IAnimatable:
public interface IAnimatable {
public AnimationComponent Animation { get; }
public ImageComponent Image { get; set; }
}
สิ่งสำคัญที่ควรสังเกตที่นี่คือImageComponent
ลักษณะของIAnimatable
ส่วนต่อประสานนั้นไม่ได้เป็นแบบอ่านอย่างเดียว ก็มีหมา
ตามที่คุณอาจเดาเอาไว้ส่วนประกอบของแอนิเมชันจะเก็บข้อมูลเกี่ยวกับแอนิเมชัน รายการของเฟรม (ซึ่งเป็นส่วนประกอบของภาพ), เฟรมปัจจุบัน, จำนวนเฟรมต่อวินาทีที่จะวาด, เวลาที่ผ่านไปตั้งแต่การเพิ่มเฟรมล่าสุดและตัวเลือกอื่น ๆ
ระบบภาพเคลื่อนไหวใช้ประโยชน์จากระบบการแสดงผลและความสัมพันธ์ขององค์ประกอบภาพ มันเพียงแค่เปลี่ยนองค์ประกอบภาพของเอนทิตีเมื่อมันเพิ่มเฟรมของภาพเคลื่อนไหว ด้วยวิธีนี้ภาพเคลื่อนไหวจะแสดงผลทางอ้อมโดยระบบการแสดงผล