ชื่อนี้มีความหมายเกินความจริงและมันอาจเป็นความไม่ชำนาญของฉันกับรูปแบบ แต่นี่คือเหตุผลของฉัน:
"ปกติ" หรือเนื้อหาที่ตรงไปตรงมาของการใช้งานเอนทิตีคือการใช้พวกเขาเป็นวัตถุและ subclassing พฤติกรรมที่พบบ่อย สิ่งนี้นำไปสู่ปัญหาแบบคลาสสิกของ "is EvilTreesubclass of Treeor 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 จะมีปัญหาที่คล้ายกัน