ฉันจะพูดจากประสบการณ์เพียงเล็กน้อยตั้งแต่การออกแบบ OO แบบแข็งไปจนถึงการออกแบบ Entity-Component-System (ECS)
ไม่นานมานี้ฉันก็เหมือนคุณฉันมีสิ่งต่าง ๆ มากมายที่มีคุณสมบัติคล้ายกันและฉันได้สร้างวัตถุต่าง ๆ และพยายามที่จะใช้การสืบทอดเพื่อแก้ปัญหา บุคคลที่ฉลาดมากบอกว่าอย่าทำอย่างนั้น แต่ใช้ Entity-Component-System แทน
ตอนนี้ECSเป็นแนวคิดที่ยิ่งใหญ่และยากที่จะทำถูก มีงานที่ต้องทำมากมายสร้างหน่วยงานส่วนประกอบและระบบอย่างถูกต้อง อย่างไรก็ตามก่อนที่เราจะสามารถทำเช่นนั้นได้เราจำเป็นต้องกำหนดเงื่อนไข
- Entity : นี่คือสิ่งที่ผู้เล่นสัตว์ NPC, สิ่งที่ มันเป็นสิ่งที่ต้องการส่วนประกอบที่แนบมากับมัน
- ส่วนประกอบ : นี่คือคุณสมบัติหรือคุณสมบัติเช่น "ชื่อ" หรือ "อายุ" หรือ "ผู้ปกครอง" ในกรณีของคุณ
- ระบบนี้เป็นตรรกะที่อยู่เบื้องหลังส่วนประกอบหรือพฤติกรรม โดยทั่วไปคุณสร้างหนึ่งระบบต่อองค์ประกอบ แต่ไม่สามารถทำได้เสมอไป นอกจากนี้บางครั้งระบบจำเป็นต้องมีอิทธิพลต่อระบบอื่น ๆ
ดังนั้นที่นี่ฉันจะไปกับสิ่งนี้:
ก่อนอื่นสร้างID
สำหรับตัวละครของคุณ int
, Guid
สิ่งที่คุณชอบ นี่คือ "เอนทิตี"
ประการที่สองเริ่มคิดเกี่ยวกับพฤติกรรมที่แตกต่างที่คุณเกิดขึ้น สิ่งต่างๆเช่น "Family Tree" - นั่นเป็นพฤติกรรม แทนการสร้างแบบจำลองที่เป็นคุณลักษณะในกิจการสร้างระบบที่ถือได้ว่าข้อมูลทั้งหมด ระบบสามารถตัดสินใจว่าจะทำอย่างไรกับมัน
ในทำนองเดียวกันเราต้องการสร้างระบบสำหรับ "ตัวละครมีชีวิตหรือตายแล้ว" นี่คือหนึ่งในระบบที่สำคัญที่สุดในการออกแบบของคุณเพราะมันมีผลต่อคนอื่น ๆ ทั้งหมด ระบบบางระบบสามารถลบอักขระ "ตาย" (เช่นระบบ "สไปรต์") ระบบอื่นสามารถจัดเรียงสิ่งต่าง ๆ ภายในเพื่อสนับสนุนสถานะใหม่ได้ดีขึ้น
คุณจะสร้างระบบ "Sprite" หรือ "Drawing" หรือ "Rendering" ระบบนี้จะมีความรับผิดชอบในการกำหนดสิ่งที่ตัวละครต้องแสดงด้วยและวิธีการแสดง จากนั้นเมื่อตัวละครตายให้ลบออก
นอกจากนี้ระบบ "AI" ที่สามารถบอกตัวละครว่าจะทำอย่างไรจะไปที่ไหน ฯลฯ สิ่งนี้ควรมีปฏิสัมพันธ์กับระบบอื่น ๆ อีกมากมายและการตัดสินใจขึ้นอยู่กับพวกเขา อีกครั้งตัวละครที่ตายแล้วอาจถูกลบออกจากระบบนี้เนื่องจากพวกเขาไม่ได้ทำอะไรอีกแล้ว
ระบบ "ชื่อ" และ "ต้นไม้ครอบครัว" ของคุณน่าจะเก็บอักขระ (มีชีวิตหรือตายไป) ไว้ในหน่วยความจำ ระบบนี้จำเป็นต้องจำข้อมูลนั้นโดยไม่คำนึงถึงสถานะของตัวละครว่าเป็นอย่างไร (จิมยังคงเป็นจิมแม้หลังจากที่เราฝังเขา)
สิ่งนี้ยังช่วยให้คุณได้รับประโยชน์จากการเปลี่ยนแปลงเมื่อระบบตอบสนองได้อย่างมีประสิทธิภาพมากขึ้น: ระบบมีตัวจับเวลา บางระบบจำเป็นต้องยิงอย่างรวดเร็วบางระบบไม่ต้องการ นี่คือจุดเริ่มต้นของเราในการทำให้เกมทำงานได้อย่างมีประสิทธิภาพ เราไม่จำเป็นต้องคำนวณสภาพอากาศใหม่ทุก ๆ มิลลิวินาทีเราอาจทำอย่างนั้นทุกๆ 5 หรือมากกว่านั้น
นอกจากนี้ยังช่วยให้คุณใช้ประโยชน์จากความคิดสร้างสรรค์มากขึ้น: คุณสามารถสร้างระบบ "Pathfinder" ที่สามารถจัดการการคำนวณเส้นทางจาก A-to-B และสามารถอัปเดตตามความจำเป็นช่วยให้ระบบการเคลื่อนไหวพูดว่า "ที่ไหนที่ฉันต้องการ ไปต่อไปเหรอ? ขณะนี้เราสามารถแยกข้อกังวลเหล่านี้ออกได้อย่างสมบูรณ์และเหตุผลเกี่ยวกับสิ่งเหล่านี้ได้อย่างมีประสิทธิภาพมากขึ้น การเคลื่อนไหวไม่จำเป็นต้องค้นหาเส้นทางมันแค่ต้องการพาคุณไปที่นั่น
คุณจะต้องเปิดเผยบางส่วนของระบบออกไปด้านนอก ในของคุณระบบคุณอาจจะต้องการPathfinder
Vector2 NextPosition(int entity)
วิธีนี้คุณสามารถเก็บองค์ประกอบเหล่านั้นไว้ในอาร์เรย์หรือรายการที่ควบคุมได้อย่างแน่นหนา คุณสามารถใช้ขนาดเล็กstruct
ประเภทซึ่งสามารถช่วยให้คุณเก็บชิ้นส่วนขนาดเล็กในบล็อกหน่วยความจำที่อยู่ติดกันซึ่งสามารถทำให้การปรับปรุงระบบมากได้เร็วขึ้น (โดยเฉพาะอย่างยิ่งหากอิทธิพลภายนอกต่อระบบมีน้อยที่สุดในตอนนี้เพียงต้องการดูแลเกี่ยวกับสถานะภายในเช่นName
)
แต่และฉันไม่สามารถเครียดได้พอตอนนี้Entity
ก็เป็นเพียงแค่ID
รวมถึงไทล์วัตถุ ฯลฯ หากเอนทิตีไม่ได้เป็นของระบบจากนั้นระบบจะไม่ติดตาม ซึ่งหมายความว่าเราสามารถสร้างวัตถุ "ต้นไม้" ของเราเก็บไว้ในSprite
และMovement
ระบบ (ต้นไม้จะไม่ย้าย แต่มีองค์ประกอบ "ตำแหน่ง") และทำให้พวกเขาออกจากระบบอื่น ๆ เราไม่ต้องการรายการพิเศษสำหรับต้นไม้อีกต่อไปเนื่องจากการแสดงต้นไม้ไม่แตกต่างจากตัวละครนอกเหนือจากกระดาษ (ซึ่งSprite
ระบบสามารถควบคุมได้หรือPaperdoll
ระบบสามารถควบคุมได้) ตอนนี้เราNextPosition
สามารถเขียนใหม่ได้เล็กน้อย: Vector2? NextPosition(int entity)
และสามารถส่งคืนnull
ตำแหน่งสำหรับเอนทิตีที่ไม่สนใจ นอกจากนี้เรายังใช้สิ่งนี้กับเราNameSystem.GetName(int entity)
มันจะส่งคืนnull
ต้นไม้และหิน
ฉันจะวาดนี้ใกล้จะถึง แต่ความคิดที่นี่คือการให้ข้อมูลพื้นฐานบางอย่างเกี่ยวกับ ECS และวิธีที่คุณสามารถจริงๆใช้ประโยชน์จากมันเพื่อให้คุณมีการออกแบบที่ดีขึ้นในเกมของคุณ คุณสามารถเพิ่มประสิทธิภาพแยกองค์ประกอบที่ไม่เกี่ยวข้องออกและทำให้สิ่งต่าง ๆ เป็นระเบียบมากขึ้น (นี่ยังคู่กันได้ดีกับภาษาการทำงาน / การตั้งค่าเช่น F # และ LINQ ซึ่งผมขอแนะนำให้ตรวจสอบจาก F # ถ้าคุณยังไม่ได้มันคู่มากดีด้วย C # เมื่อคุณใช้ร่วม.)