게임 스테이트 시스템의 대안?


30

내가 알 수있는 한, 대부분의 게임에는 서로 다른 게임 상태를 전환하는 일종의 "게임 상태 시스템"이 있습니다. "Intro", "MainMenu", "CharacterSelect", "Loading"및 "Game"과 같은 것일 수 있습니다.

한편으로는 이것을 상태 시스템으로 분리하는 것이 전적으로 의미가 있습니다. 결국, 그들은 이질적이며 그렇지 않으면 큰 스위치 진술에 있어야 할 것입니다. 그것들은 확실히 국가 시스템으로 잘 대표됩니다. 그러나 동시에 "게임"상태를보고이 상태 시스템 접근 방식에 문제가 있는지 궁금합니다. 방 안에있는 코끼리와 같아서 거대하고 명백하지만 아무도 게임 상태 시스템 접근에 의문을 제기하지 않습니다.

"게임"이 "메인 메뉴"와 같은 수준에 놓인 것은 어리석은 것 같습니다. 그러나 "게임"상태를 해체 할 수있는 방법은 없습니다.

게임 상태 시스템이 가장 좋은 방법입니까? "게임 상태"를 관리 할 수있는 다른 기술이 있습니까? 영화를 그리고 들어가기를 듣는 인트로 (intro) 상태와 리소스 관리자를 반복하는 로딩 상태, 실질적으로 모든 것을 하는 게임 상태를 갖는 것이 괜찮 습니까? 이것도 당신에게 균형이 맞지 않습니까? 뭔가 빠졌습니까?

답변:


30

나는 당신이 여기서 의미론을 주장하고 있다고 생각합니다. Finite State Machine 처럼 동작하기 때문에 Game State라고 불립니다 . 유한 한 수의 상태와 그 사이의 전환이 있습니다. 'Game State System'에서 'Game'은 전체 시스템을 의미하며 'Loading', 'MainMenu'등이 게임 상태입니다. 이를 '씬'또는 '스크린'또는 '레벨'이라고 쉽게 부를 수 있습니다. 그냥 의미론입니다.

엄격한 FSM이 더 이상 적용되는지 확실하지 않습니다. 내 구현에서는 상태를 'Screens'라고 부르고 쌓을 수있게합니다. 화면을 다른 화면 위에 그릴 수 있으며 그 아래에있는 화면을 업데이트하거나 그릴 지 여부를 제어합니다. 이러한 방식으로 다른 화면에 대해 걱정할 필요없이 자체 포함 된 논리 및 해당 화면에 특정한 코드를 사용하여 여러 화면을 동시에 활성화 할 수 있습니다.

예를 들어, 일시 중지 화면은 기본 게임 플레이 화면 위에 열리면 업데이트가 허용되지 않지만 자체적으로 그릴 수 있습니다. 캐릭터 인벤토리 화면은 드로잉과 업데이트를 모두 허용하므로 인벤토리에서 작업하는 동안 게임이 계속 재생됩니다.


이것이 정확히 어떻게 수행되어야 하는가입니다. 스크린은 트리와 같은 아키텍처로 여러 개의 다른 스크린을 포함 할 수 있어야합니다. 따라서 프로그램에는 오디오 설정 화면과 게임 설정 화면이 포함 된 일시 중지 메뉴 화면이 포함 된 게임 화면이 있습니다. 기타
Iain

1
이에 대한 예제 소스 코드를보고 싶습니다! (바람직하게는 C ++ / C # / Java에서)
Zolomon

1
불행히도, 현재는 프로덕션 코드 만 있지만 XNA Game State 샘플에는 비슷한 개념이 있습니다. creators.xna.com/en-GB/samples/gamestatemanagement
DrDeth

7

물론 게임 상태는 크 겠지만 게임 상태 자체가 데이터를 관리하기위한 상태 머신을 포함 할 수있는 이유는 없습니다. 계층 적 상태 머신이 유용합니다.


4

저는 항상 각 "상태"를 "장면"으로 생각하고 싶습니다. 오프닝 비디오는 하나의 정적 인 장면입니다. 크레딧은 장면입니다. 메뉴는 장면입니다. 그들 사이의 유일한 차이점은 상호 작용 수준과 게임 논리입니다.


3

사실 저도 문제가 있습니다.

게임이 있다고 가정 해 봅시다.

'Game'을 'Loading', 'Main Menu'등과 같은 상태로 만드는 대신-IMO : Game 여러 상태 를 두는 것이 좋습니다 .

"로드 중" - "메뉴 표시" - "일시 중지됨"

게임은 여전히 ​​실행 중이지만 주 메뉴가 표시되면 '메뉴 표시'모드에 있습니다.

게임이 특정 상태가 아닌 경우에는 실행 중입니다.

적어도 나에게는 훨씬 더 의미가 있습니다. :)


동의한다. 아무도 Pause-State 를 입력하기 위해 Game-State 를 종료하고 싶지 않습니다 . 반면에 : 그것은 여전히 ​​상태 시스템입니다 .. 그냥 중첩 :)
bummzack

2

온라인 프로그램 (온라인의 전통적인 의미, 즉 인터넷에 연결된 의미가 아니라 지속적으로 입력에 응답)은 일반적으로 3 가지로 구성됩니다.

  • 입력 수집 및 처리
  • 논리 업데이트
  • 산출

일반적으로 말해서,이 3 개는 관련이 있고 동시에 변경됩니다. 예를 들어, 스플래시 화면을 표시 할 때 모든 키를 '화면 닫기'명령에 매핑 할 수 있으며 업데이트는 해당 그래픽 만 보여주는 출력으로 그래픽이 천천히 희미해질 수 있습니다. 그러나 게임을 할 때 키는 모두 다른 명령에 매핑 될 수 있으며 업데이트는 많은 게임 내 오브젝트의 속성을 변경합니다.

이런 방식으로 볼 때 인트로를 캐릭터 생성과 게임에서 분리하는 것이 합리적입니다. 각각 고유 한 입력, 업데이트 및 출력 규칙을 가지고 있습니다. 그것들은 데이터와 라이브러리 코드를 공유하는 자체 포함 된 프로그램과 거의 같습니다. 그리고이를 염두에두고 게임 플레이는 전체적으로 상당히 균일하므로 일반적으로 하나의 게임 상태를 갖는 것이 좋습니다.

물론 실제로 입력, 업데이트 및 출력이 다른 별도의 유형의 게임 플레이 (예 : RPG 예-세계지도, 도시지도, 컷신, 전투)가있는 경우 여러 상태를 가질 수있는 이유가 없습니다 단지 1 게임 상태 대신에. 그러나 그것은 당신의 게임에 달려 있습니다.


1

다른 방법으로 봅니다. '메뉴', '고득점', '신용'또는 귀하의 행동은 다른 수준으로 간주 될 수 있으며 그 상태가 반드시 '게임'상태보다 가벼울 필요는 없습니다 (게임 상태는 일반적으로 더 많은 엔티티를 가짐, 다른 것들이지만, 결국 엔 실체가 더 예측하기 어려운 행동을 보이고 '지도'가 일반적으로 덜 복잡 해지는 또 다른 수준 일뿐입니다).
당신의 생각에서 그 스위치를 만드는 것은 분명히 "지루한 메뉴"증후군에서 당신을 끌어냅니다.


나는 똑같은 말을하려고했는데 ... 모든 메뉴, 화면 등은 다른 수준에 불과합니다
speeder

1

내 게임에는 다음이 있습니다.

응용 프로그램 (게임)을 초기화하고, 리소스를로드하고, 응용 프로그램 종료시 리소스를 해제하는 등의 실행 관리자 . Application Engine, GameViewEngine, GameLogicEngine을 초기화합니다.

GameLogicEngine에 상주하는 Game State Manager 는 충돌 감지, 물리 계산, 키보드 읽기, 수학 연산 등 게임 메인 루프와 관련된 사항을 제어합니다.

처음에는 GameLogicEngine의 일부인 Game State Manager가 하나만있는 경향이있었습니다. 그러나 주요 하위 시스템 (GameLogic, ApplicationEngine, ...)의 초기화를 제어하는 ​​데 어려움이있었습니다. 할 수 있었지만 더 지저분했습니다.

이제 상황이 더 투명 해졌으며 디자인에 만족합니다.


0

'Game'상태를 'Gameplay'와 같은 이름으로 바꿉니다. 그렇다면 당신의 논리는 더 좋아 보인다; 당신은 메뉴로 이동 재생을 중지 : 당신은 MainMenu 상태로 이동하기 위해 게임 플레이 상태를 종료합니다.

또한 게임을 일시 중지했을 때와 같은 상태에 있어야하는 일시 중지와 같은 것은 별도의 상태가 아니어야한다고 생각합니다. 아마도 어린이 상태와 중첩? 게임 플레이에는 일시 정지 메뉴가 있습니다.


0

게임 상태 스택이라는 좋은 방법이 있다고 생각합니다. 나는 그것에 관한 논문이나 기사를 보지 못했지만 조금씩 목소리로 퍼지고 있습니다. 기본적으로 스택의 최상위 게임 상태가 먼저 호출되고 입력 / 렌더링 등 원하는 작업을 수행합니다. 최상위 게임 상태는 푸시 또는 팝 상태를 허용하는 유일한 것입니다.

내 엔진에서 게임 상태는 실제로 게임 엔터티의 목록입니다. 그런 다음 메뉴로 작동하는 엔티티가 있습니다. 내 메뉴 상태는 (스택의 다음 항목을 업데이트하지 않음) 게임을 일시 중지하지만 다른 상태는 모델을 렌더러로 푸시하여 일시 정지 메뉴 (전체 화면을 덮지 않음)가 계속 유지되도록합니다. 뒷면에 게임 렌더링이 있습니다.

상태 머신을 기반으로하지 않는 약간 다른 시스템에 대한 아이디어를 제공하기를 바랍니다.


0

영화를 그리고 들어가기를 듣는 인트로 (intro) 상태와 리소스 관리자를 반복하는 로딩 상태, 실질적으로 모든 것을하는 게임 상태를 갖는 것이 괜찮습니까? 이것도 당신에게 균형이 맞지 않습니까? 뭔가 빠졌습니까?

이것은 완벽합니다. 또는 적어도 "게임 상태에 따라 큰 못생긴 스위치를 갖는 것"보다 개선 된 것입니다.

나는 대부분의 게임에서 간단한 엔티티 AI를 처리하기 위해 이미 유한 상태 머신이 필요하다는 것을 지적하고 싶습니다. 일반적인 예는 유휴 상태, 공격 또는 죽어있는 적입니다.

Finite State Machine이 충분히 추상화 된 경우 게임 오브젝트와 AI 모두에 재사용 할 수 있습니다. 갑자기 게임 상태에 많은 노력을 "투자"하지 않고 어쨌든 사용한 코드를 재사용하고 있습니다.

뻔뻔한 자체 연결이 계속됩니다. Lua 게임 라이브러리 인 MiddleClass (구체적으로 MindState라고하는 애드온)에서 이러한 유한 상태 머신을 구현했습니다 . 여기에 Game State 일을하는 방법이 있습니다 .


0

이에 대한 다른 접근 방식은 차별적 연합 (Discriminated Union) 이라는 기능적 프로그래밍 세계의 개념을 사용하는 것입니다 . 이러한 언어 는 일반적으로 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.