ชื่อนี้มีความหมายเกินความจริงและมันอาจเป็นความไม่ชำนาญของฉันกับรูปแบบ แต่นี่คือเหตุผลของฉัน:
"ปกติ" หรือเนื้อหาที่ตรงไปตรงมาของการใช้งานเอนทิตีคือการใช้พวกเขาเป็นวัตถุและ subclassing พฤติกรรมที่พบบ่อย สิ่งนี้นำไปสู่ปัญหาแบบคลาสสิกของ "is EvilTree
subclass of Tree
or Enemy
?" หากเรายอมให้มีการสืบทอดหลายครั้งปัญหาเพชรจะเกิดขึ้น เราแทนสามารถดึงการทำงานรวมกันTree
และEnemy
ขึ้นไปลำดับชั้นซึ่งนำไปสู่การเรียนพระเจ้าหรือเราจงใจสามารถออกจากพฤติกรรมของเราTree
และEntity
การเรียน (ทำให้พวกเขาเชื่อมต่อในกรณีที่รุนแรง) เพื่อให้EvilTree
สามารถดำเนินการที่ตัวเอง - ซึ่งจะนำไปสู่ SomewhatEvilTree
การทำสำเนารหัสถ้าเราเคยมี
ระบบ Entity-Component พยายามที่จะแก้ปัญหานี้โดยการหารTree
และEnemy
วัตถุเป็นส่วนประกอบที่แตกต่างกัน - พูดPosition
, Health
และAI
- และดำเนินการระบบเช่นAISystem
ที่มีการเปลี่ยนแปลงตำแหน่งของ Entitiy ตามการตัดสินใจของเอไอ จนถึงดีมาก แต่จะเกิดอะไรขึ้นหากEvilTree
สามารถหยิบพลังและจัดการความเสียหายได้? ก่อนอื่นเราต้องการ a CollisionSystem
และ a DamageSystem
(เราอาจมีสิ่งเหล่านี้อยู่แล้ว) CollisionSystem
ความต้องการในการสื่อสารกับDamageSystem
ทุกครั้งที่สองสิ่งชนCollisionSystem
ส่งข้อความถึงDamageSystem
สุขภาพเพื่อที่จะสามารถลบ ความเสียหายยังได้รับอิทธิพลจากการเติมพลังดังนั้นเราต้องเก็บมันไว้ที่ไหนซักแห่ง เราสร้างใหม่PowerupComponent
ที่เราแนบกับหน่วยงาน? แต่แล้วDamageSystem
จำเป็นต้องรู้เกี่ยวกับบางสิ่งบางอย่างมันค่อนข้างจะไม่รู้อะไรเลย - นอกจากนี้ยังมีบางสิ่งที่สร้างความเสียหายที่ไม่สามารถรับพลังได้ (เช่นกSpike
) เราอนุญาตให้มีPowerupSystem
การแก้ไข a StatComponent
ที่ใช้สำหรับการคำนวณความเสียหายที่คล้ายกับคำตอบนี้หรือไม่? แต่ตอนนี้ทั้งสองระบบเข้าถึงข้อมูลเดียวกัน เมื่อเกมของเรามีความซับซ้อนมากขึ้นมันจะกลายเป็นกราฟพึ่งพาไม่มีตัวตนที่องค์ประกอบร่วมกันระหว่างระบบต่างๆ ณ จุดนี้เราสามารถใช้ตัวแปรคงที่ทั่วโลกและกำจัดแผ่นเหล็กทั้งหมด
มีวิธีที่มีประสิทธิภาพในการแก้ปัญหานี้หรือไม่? หนึ่งความคิดที่ฉันมีคือการปล่อยให้องค์ประกอบมีฟังก์ชั่นบางอย่างเช่นให้สิ่งStatComponent
attack()
ที่เพิ่งจะส่งกลับจำนวนเต็มโดยค่าเริ่มต้น แต่สามารถประกอบเมื่อมีการเพิ่มพลัง:
attack = getAttack compose powerupBy(20) compose powerdownBy(40)
สิ่งนี้ไม่ได้แก้ปัญหาที่attack
ต้องบันทึกไว้ในองค์ประกอบที่เข้าถึงได้โดยหลายระบบ แต่อย่างน้อยฉันก็สามารถพิมพ์ฟังก์ชั่นได้อย่างถูกต้องถ้าฉันมีภาษาที่รองรับอย่างเพียงพอ:
// 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
ด้วยวิธีนี้ฉันอย่างน้อยรับประกันการสั่งซื้อที่ถูกต้องของฟังก์ชั่นต่างๆที่เพิ่มโดยระบบ ไม่ว่าจะด้วยวิธีใดดูเหมือนว่าฉันกำลังเข้าใกล้การเขียนโปรแกรมแบบมีปฏิกิริยาโต้ตอบอย่างรวดเร็วที่นี่ดังนั้นฉันถามตัวเองว่าฉันไม่ควรใช้สิ่งนั้นตั้งแต่เริ่มต้นแทน (ฉันเพิ่งดูเป็น FRP เท่านั้นดังนั้นฉันอาจผิด) ฉันเห็นว่า ECS เป็นการปรับปรุงลำดับชั้นที่ซับซ้อน แต่ฉันไม่มั่นใจว่ามันเหมาะอย่างยิ่ง
มีวิธีแก้ปัญหานี้หรือไม่? มีฟังก์ชั่น / รูปแบบที่ฉันพลาดในการแยก ECS ออกอย่างหมดจดมากขึ้นหรือไม่ FRP เหมาะกว่าสำหรับปัญหานี้หรือไม่? ปัญหาเหล่านี้เกิดจากความซับซ้อนของสิ่งที่ฉันพยายามเขียนโปรแกรมหรือไม่ เช่น FRP จะมีปัญหาที่คล้ายกัน