ทางเลือกระบบ Game State?


30

เท่าที่ฉันจะบอกได้เกมส่วนใหญ่มี "ระบบสถานะเกม" บางอย่างที่สลับไปมาระหว่างรัฐเกมที่แตกต่างกัน สิ่งเหล่านี้อาจเป็น "Intro", "MainMenu", "CharacterSelect", "กำลังโหลด" และ "เกม"

ในอีกด้านหนึ่งมันเหมาะสมอย่างยิ่งที่จะแยกสิ่งเหล่านี้ออกเป็นระบบรัฐ ท้ายที่สุดพวกเขาจะแตกต่างกันและจะต้องอยู่ในงบสวิตช์ขนาดใหญ่ซึ่งยุ่งเหยิงอย่างเห็นได้ชัด; และแน่นอนว่าพวกเขามีระบบรัฐที่ดี แต่ในเวลาเดียวกันฉันมองไปที่สถานะ "เกม" และสงสัยว่ามีบางอย่างผิดปกติเกี่ยวกับวิธีการของระบบรัฐนี้หรือไม่ เพราะมันเหมือนช้างอยู่ในห้อง มันมีขนาดใหญ่และชัดเจน แต่ก็ไม่มีใครถามถึงแนวทางของระบบเกม

ฉันคิดว่าเกม "โง่" อยู่ในระดับเดียวกับ "เมนูหลัก" แต่ก็ไม่มีวิธีใดที่จะแยกรัฐ "เกม" ออก

ระบบสถานะของเกมเป็นวิธีที่ดีที่สุดหรือไม่? มีเทคนิคที่แตกต่างและดีกว่าในการจัดการและดีกว่า "สถานะเกม" หรือไม่? มันโอเคไหมที่จะมีสถานะอินโทรที่วาดภาพยนตร์และฟังเพื่อป้อนจากนั้นสถานะโหลดที่ลูปบนตัวจัดการทรัพยากรและจากนั้นสถานะของเกมที่ทำทุกอย่างได้จริงหรือไม่ สิ่งนี้ดูเหมือนจะไม่สมดุลสำหรับคุณหรือไม่ ฉันพลาดอะไรไปรึเปล่า?

คำตอบ:


30

ฉันคิดว่าคุณแค่โต้เถียงความหมายที่นี่ มันถูกเรียกว่า Game State เพราะมันทำตัวเหมือนเครื่องจักร Finite State ที่มีจำนวน จำกัด และเปลี่ยนผ่านระหว่างรัฐ 'เกม' ใน 'ระบบสถานะเกม' หมายถึงระบบโดยรวมด้วย 'กำลังโหลด', 'เมนเฟรม' เป็นต้นเป็นสถานะของเกม สิ่งเหล่านี้อาจเรียกได้ง่ายว่า 'ฉาก' หรือ 'หน้าจอ' หรือ 'ระดับ' ความหมายของมัน

ฉันไม่แน่ใจว่าจะใช้ FSM ที่เข้มงวดอีกต่อไปแล้ว ในการใช้งานของฉันฉันเรียกว่า 'หน้าจอ' และอนุญาตให้วางซ้อนกันได้ - เช่น สามารถวาดหน้าจอที่ด้านบนของหน้าจออื่น ๆ ควบคุมว่าหน้าจอด้านล่างนั้นได้รับการปรับปรุงหรือวาด ด้วยวิธีนี้ฉันสามารถเปิดใช้งานหน้าจอหลายหน้าจอพร้อมกันด้วยตรรกะที่มีในตัวเองและรหัสเฉพาะสำหรับหน้าจอนั้นโดยไม่ต้องกังวลกับหน้าจออื่น

ตัวอย่างเช่นหน้าจอหยุดชั่วคราวสามารถเปิดได้ที่ด้านบนของหน้าจอการเล่นเกมหลักที่ไม่อนุญาตให้อัปเดต แต่อนุญาตให้วาดภาพตัวเองด้านล่าง หน้าจอคลังข้อมูลอักขระสามารถอนุญาตทั้งการวาดและการอัปเดตดังนั้นเกมจะเล่นต่อไปในขณะที่คุณกำลังทำงานในคลังของคุณ


ตรงนี้เป็นวิธีที่ควรทำ หน้าจอควรจะมีหน้าจออื่นหลายหน้าจอในสถาปัตยกรรมที่มีลักษณะคล้ายต้นไม้ ดังนั้นโปรแกรมของคุณมีหน้าจอเกมซึ่งมีหน้าจอหยุดเมนูซึ่งมีหน้าจอการตั้งค่าเสียงและหน้าจอการตั้งค่าเกม ฯลฯ
Iain

1
ฉันชอบที่จะเห็นซอร์สโค้ดตัวอย่างสำหรับสิ่งนี้! (เด่นกว่าใน C ++ / C # / Java)
Zolomon

1
น่าเสียดายที่ฉันมีรหัสการผลิตเท่านั้นในขณะนี้ แต่มีแนวคิดที่คล้ายคลึงกันในตัวอย่างสถานะเกม XNA: creators.xna.com/en-GB/samples/gamestatemanagement
DrDeth

7

แน่นอนว่าสถานะของเกมจะมีขนาดใหญ่ แต่ไม่มีเหตุผลว่าสถานะของเกมนั้นจะไม่มีเครื่องสถานะในการจัดการข้อมูล เครื่องสถานะแบบลำดับชั้นมีประโยชน์


4

ฉันชอบคิดว่า "สถานะ" แต่ละฉากเป็น "ฉาก" เสมอ ดังนั้นวิดีโอที่เปิดเป็นฉากหนึ่งจะเป็นภาพนิ่ง เครดิตเป็นฉาก เมนูเป็นฉาก ข้อแตกต่างระหว่างพวกเขาทั้งหมดคือระดับของการโต้ตอบและตรรกะของเกม


3

ฉันมีปัญหากับเรื่องนั้นเช่นกันที่จริง

สมมติว่าคุณมีเกม

แทนที่จะทำให้ 'เกม' เป็นรัฐเช่น 'กำลังโหลด', 'เมนูหลัก' ฯลฯ - IMO จะเป็นการดีกว่าถ้าปล่อยให้เกมมีหลายสถานะ:

"กำลังโหลด" - "เมนูแสดง" - "หยุดชั่วคราว"ฯลฯ

เกมยังคงทำงานอยู่ แต่เมื่อมันแสดงเมนูหลักมันจะอยู่ในโหมด 'แสดงเมนู'

และเมื่อเกมไม่ได้อยู่ในสถานะใดโดยเฉพาะมันจะเริ่มทำงาน

มันสมเหตุสมผลมากกว่าอย่างน้อยสำหรับฉัน :)


ฉันเห็นด้วย. ไม่มีใครอยากจะออกจากเกมรัฐเพียงเพื่อป้อนรัฐหยุดชั่วคราว ในทางกลับกัน: มันยังคงเป็นระบบของรัฐ .. เพียงแค่ซ้อนกัน :)
bummzack

2

โปรแกรมออนไลน์ (ในความหมายดั้งเดิมของออนไลน์เช่นทำงานอย่างต่อเนื่องและตอบสนองต่อการป้อนข้อมูลมากกว่าความหมายที่เชื่อมต่อกับอินเทอร์เน็ต) โดยทั่วไปประกอบด้วย 3 สิ่ง:

  • การรวบรวมและการจัดการอินพุต
  • การปรับปรุงตรรกะ
  • เอาท์พุต

โดยทั่วไปการพูด 3 สิ่งเหล่านี้เกี่ยวข้องและเปลี่ยนแปลงในเวลาเดียวกัน ตัวอย่างเช่นเมื่อแสดงหน้าจอสแปลชคุณอาจแมปคีย์ทั้งหมดของคุณเป็นคำสั่ง 'ปิดหน้าจอ' และการอัปเดตอาจทำให้กราฟิกจางลงอย่างช้าๆโดยเอาต์พุตจะแสดงกราฟิกนั้น แต่เมื่อเล่นเกมคีย์ทั้งหมดอาจแมปไปยังคำสั่งที่แตกต่างกันและการอัปเดตกำลังเปลี่ยนแปลงคุณสมบัติของวัตถุในเกมมากมาย

เมื่อคุณดูด้วยวิธีนี้คุณจะต้องแยกอินโทรออกจากการสร้างตัวละครและจากเกมที่เหมาะสม: แต่ละอันมีกฎอินพุต, อัพเดตและเอาท์พุตของตัวเอง พวกเขาเกือบจะเหมือนโปรแกรมที่มีอยู่ในตัวเองและแบ่งปันข้อมูลและรหัสห้องสมุด และด้วยความคิดนี้มันจึงเหมาะสมที่จะมีเพียงหนึ่งสถานะของเกมเนื่องจากการเล่นเกมนั้นมีความเหมือนกันตลอด

แน่นอนว่าถ้าคุณมีรูปแบบการเล่นที่แตกต่างกัน (เช่นตัวอย่างเกม RPG - แผนที่โลก, แผนที่เมือง, Cutscene, Combat) ด้วยการป้อนข้อมูลการอัปเดตและเอาท์พุทที่แตกต่างกัน เช่นกันแทนที่จะเป็นเพียง 1 สถานะเกม แต่มันก็ขึ้นอยู่กับเกมของคุณ


1

ฉันมองไปทางอื่น 'เมนู', 'คะแนนสูงสุด', 'เครดิต' หรือ whathaveyou ถือได้ว่าเป็นอีกระดับหนึ่งและจากนั้นสถานะนั้นไม่จำเป็นต้องเบากว่าสถานะ 'เกม' ของคุณ (สถานะของเกมเพิ่งจะมีเอนทิตี้ทั่วไปมากกว่า และสิ่งที่แตกต่างกัน แต่ในท้ายที่สุดมันก็เป็นเพียงอีกระดับหนึ่งที่เอนทิตีเกิดขึ้นเพื่อแสดงพฤติกรรมที่ทำนายได้มากขึ้นและโดยทั่วไป 'แผนที่' จะซับซ้อนน้อยกว่า)
การเปลี่ยนความคิดของคุณจะดึงคุณออกจากกลุ่มอาการ "เมนูน่าเบื่อ" อย่างแน่นอน


ฉันจะพูดเหมือนเดิม ... ทุกเมนูหน้าจออะไรก็แค่ระดับเดียว
แข่ง

1

ในเกมของฉันฉันมี:

Execution Managerซึ่งทำให้แอปพลิเคชั่น (เกม) โหลดทรัพยากรเผยแพร่ทรัพยากรเมื่อออกจากแอปพลิเคชั่น ฯลฯ ซึ่งจะทำให้แอปพลิเคชั่นเครื่องยนต์ Engine เป็น GameViewEngine, GameLogicEngine

Game State Managerซึ่งอยู่ใน GameLogicEngine และรับผิดชอบในการควบคุมสิ่งต่าง ๆ ที่เกี่ยวข้องกับวงหลักของเกม: การตรวจจับการชนการคำนวณทางฟิสิกส์การอ่านคีย์บอร์ดการดำเนินการทางคณิตศาสตร์ ฯลฯ

เริ่มแรกฉันมักจะมีเพียงหนึ่ง Game State Manager ซึ่งเป็นส่วนหนึ่งของ GameLogicEngine ของฉัน อย่างไรก็ตามฉันมีปัญหาบางอย่างกับการควบคุมการติดตั้งระบบย่อยหลัก (GameLogic, ApplicationEngine, ... ) มันสามารถทำได้ แต่มันยุ่งกว่า IMO

ตอนนี้ทุกอย่างดูโปร่งใสมากขึ้นสำหรับฉันและฉันมีความสุขกับการออกแบบ


0

เปลี่ยนชื่อสถานะ 'เกม' เป็น 'Gameplay' ถ้าอย่างนั้นตรรกะของคุณก็ดูดีขึ้น; คุณหยุดเล่นเพื่อไปที่เมนู th: คุณออกจากสถานะ Gameplay เพื่อไปยังสถานะ MainMenu

นอกจากนี้ฉันคิดว่าสิ่งต่าง ๆ เช่นหยุดชั่วคราวซึ่งจะทำให้เกมอยู่ในสถานะเดียวกับเมื่อคุณหยุดเกมชั่วคราวไม่ควรแยกรัฐ เด็กและการทำรังบางที? Gameplay มีเมนูหยุดชั่วคราว


0

ฉันคิดว่ามีวิธีการที่ดีที่เรียกว่าสแต็คสถานะเกม ฉันไม่ได้เห็นบทความหรือบทความใด ๆ เกี่ยวกับเรื่องนี้ แต่มันแพร่กระจายด้วยเสียงเล็กน้อย โดยพื้นฐานแล้วสถานะของเกมสูงสุดบนสแต็กจะถูกเรียกก่อนและทำทุกอย่างที่ต้องการด้วยอินพุท / เรนเดอร์ ฯลฯ สถานะของเกมที่สูงที่สุดเป็นสถานะเดียวที่อนุญาตให้กดหรือป๊อปอัป

ในกลไกของฉันสถานะเกมเป็นเพียงรายการของเอนทิตีเกม ฉันมีเอนทิตีที่ทำงานเป็นเมนู เมนูของฉันอาจหยุดเกมชั่วคราว (โดยไม่อัปเดตรายการถัดไปบนสแต็ค) แต่ให้รัฐอื่นผลักโมเดลของพวกเขาไปที่โหมดแสดงภาพเพื่อให้เมนูหยุดชั่วคราวของฉัน (ซึ่งไม่ครอบคลุมทั้งหน้าจอ) มีการเรนเดอร์เกมที่ด้านหลัง

ฉันหวังว่าจะให้แนวคิดเกี่ยวกับระบบที่แตกต่างกันเล็กน้อยซึ่งไม่ได้ขึ้นอยู่กับกลไกของรัฐ


0

มันโอเคไหมที่จะมีสถานะอินโทรที่วาดภาพยนตร์และฟังเพื่อป้อนจากนั้นสถานะโหลดที่ลูปบนตัวจัดการทรัพยากรและจากนั้นสถานะของเกมที่ทำทุกอย่างได้จริงหรือไม่? สิ่งนี้ดูเหมือนจะไม่สมดุลสำหรับคุณหรือไม่ ฉันพลาดอะไรไปรึเปล่า?

นี่เป็นสิ่งที่ดีอย่างสมบูรณ์ หรืออย่างน้อยก็เป็นการปรับปรุง "มีสวิตช์ที่น่าเกลียดขนาดใหญ่ขึ้นอยู่กับสถานะของเกม"

ฉันต้องการที่จะชี้ให้เห็นว่าในเกมส่วนใหญ่คุณจะต้องมีเครื่องจักรที่มีขีด จำกัด เพื่อจัดการกับเอนทิตี้ AI อย่างง่าย ตัวอย่างทั่วไปคือศัตรูที่อยู่ในสถานะ Iddle, Attack หรือ Dieing

หากคุณมี Finite State Machine ที่เป็นนามธรรมเพียงพอแล้วคุณสามารถนำมันกลับมาใช้ใหม่ได้ทั้งวัตถุเกมและ AI ของคุณ ทันใดนั้นคุณก็ไม่ได้ "ลงทุน" ความพยายามมากมายในสถานะเกม - แต่คุณกลับมาใช้รหัสที่คุณใช้อยู่

ปลั๊กตัวเองที่ไร้ยางอาย: ฉันได้ติดตั้ง Finite State Machine บนไลบรารี่เกม Lua ของฉันMiddleClass (ส่วนเสริมที่เรียกว่า MindState) นี่คือวิธีที่คุณทำสิ่งที่รัฐเกมกับมัน


0

วิธีการที่แตกต่างกันในการนี้คือการใช้แนวคิดจากโลกโปรแกรมการทำงานที่เรียกว่าสหภาพจำแนก ขณะที่เหล่านี้จะมักจะพบในภาษา FP คุณสามารถเลียนแบบพวกเขาใช้คลาส

โดยพื้นฐานแล้วสหภาพที่ถูกแบ่งแยกเป็นประเภทที่มักจะเป็นหนึ่งในnกรณีและข้อมูลที่เก็บไว้อาจแตกต่างกันไปในแต่ละกรณี

ตัวอย่างเช่น:

type GameState =
  | Menu of MenuState
  | Playing of SimulationState

ที่นี่เราGameStateชนิดสามารถเป็นได้ทั้งหรือMenu Playingถ้าเป็นMenuเช่นนั้นมันจะมีMenuStateวัตถุ ถ้าเป็นPlayingเช่นนั้นมันจะมีSimulationStateวัตถุ

เพื่อปรับปรุงเราจะmatchอยู่ในสถานะและเรียกใช้ฟังก์ชั่นที่แตกต่างกันตาม:

let update gameTime = 
  let nextState = 
    match gameState with
    | Menu menuState -> updateMenu gameTime menuState
    | Playing simulationState -> updateSimulation gameTime simulationState

  // Mutate the current state
  gameState <- nextState

และในทำนองเดียวกันสำหรับการแสดงผล:

let render gameTime = 
  let nextState = 
    match gameState with
    | Menu menuState -> renderMenu menuState
    | Playing simulationState -> renderSimulation simulationState

ข้อดีอย่างหนึ่งของวิธีการนี้คือคุณสามารถจัดการกับสิ่งต่าง ๆ ข้ามรัฐ (เช่นทรัพยากร) ได้ง่ายขึ้นโดยไม่ต้องกลมกลืนหรือผ่านวัตถุ "บริการ"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.