게임 상태 관리 기술?


24

우선, 저는 장면 관리를 언급하지 않습니다. 게임 입력을 게임에서 사용자 입력의 활성화 여부에 관계가 있거나 특정 액터가 일시적으로 비활성화해야하는 등의 의미로 느슨하게 정의하고 있습니다.

구체적인 예로, 고전적인 Battlechess 게임이라고 가정 해 봅시다. 다른 플레이어의 작품을 가져 오기 위해 이동 한 후 짧은 전투 시퀀스가 ​​재생됩니다. 이 순서 동안 플레이어는 조각을 움직일 수 없어야합니다. 그렇다면 이런 종류의 상태 전이를 어떻게 추적 할 수 있습니까? 유한 상태 기계? 간단한 부울 검사? 후자는 이런 종류의 상태 변화가 거의없는 게임에서만 잘 작동하는 것 같습니다.

유한 상태 머신을 사용하여 이것을 처리하는 많은 간단한 방법을 생각할 수 있지만 빠르게 벗어날 수 있습니다. 게임 상태 / 전환을 추적하는 더 우아한 방법이 있는지 궁금합니다.


gamedev.stackexchange.com/questions/1783/game-state-stackgamedev.stackexchange.com/questions/2423/… 을 확인 했습니까 ? 그것은 같은 개념을 뛰어 넘기는 것이지만 게임 상태에 대한 상태 머신보다 더 좋은 것은 생각할 수 없습니다.
michael.bartnett

답변:


18

한때 문제를 매우 우아하게 해결 하는 기사 를 보았습니다. 기본 루프에서 호출되는 기본 FSM 구현입니다. 이 답변의 나머지 부분에서 기사의 기본 요약을 설명했습니다.

기본 게임 상태는 다음과 같습니다 :

class CGameState
{
    public:
        // Setup and destroy the state
        void Init();
        void Cleanup();

        // Used when temporarily transitioning to another state
        void Pause();
        void Resume();

        // The three important actions within a game loop
        void HandleEvents();
        void Update();
        void Draw();
};

각 게임 상태는이 인터페이스의 구현으로 나타납니다. Battlechess 예제의 경우 다음 상태를 의미 할 수 있습니다.

  • 소개 애니메이션
  • 메인 메뉴
  • 체스 판 설정 애니메이션
  • 플레이어 이동 입력
  • 플레이어 이동 애니메이션
  • 상대 이동 애니메이션
  • 일시 정지 메뉴
  • 최종 게임 화면

상태 엔진에서 상태가 관리됩니다.

class CGameEngine
{
    public:
        // Creating and destroying the state machine
        void Init();
        void Cleanup();

        // Transit between states
        void ChangeState(CGameState* state);
        void PushState(CGameState* state);
        void PopState();

        // The three important actions within a game loop
        // (these will be handled by the top state in the stack)
        void HandleEvents();
        void Update();
        void Draw();

        // ...
};

각 상태는 어느 시점에서 CGameEngine에 대한 포인터가 필요하므로 상태 자체가 새로운 상태를 입력해야하는지 여부를 결정할 수 있습니다. 이 기사에서는 CEventEngine을 HandleEvents, Update 및 Draw에 대한 파라미터로 전달할 것을 제안합니다.

결국 메인 루프는 상태 엔진 만 처리합니다.

int main ( int argc, char *argv[] )
{
    CGameEngine game;

    // initialize the engine
    game.Init( "Engine Test v1.0" );

    // load the intro
    game.ChangeState( CIntroState::Instance() );

    // main loop
    while ( game.Running() )
    {
        game.HandleEvents();
        game.Update();
        game.Draw();
    }

    // cleanup the engine
    game.Cleanup();
    return 0;
}

17
수업 C? 으. 그러나 그것은 좋은 기사입니다-+1.
공산주의 오리

내가 수집 할 수있는 것에서, 이것은 질문이 명시 적으로 묻지 않는 일종의 것입니다. 그것은 당신이 확실히 할 수있는 것처럼,이 방법으로 처리 할 수 ​​없다고 말하는 것은 아니지만, 당신이하고 싶었던 모든 것이 입력을 일시적으로 비활성화하는 것이라면 유지 보수가 어려운 것으로 생각됩니다. 다른 서브 클래스와 99 % 동일해야합니다.
Kylotan

나는 이것이 코드가 어떻게 결합되어 있는지에 달려 있다고 생각합니다. 조각과 대상 선택 (주로 UI 표시기 및 입력 처리)과 해당 대상을 향한 체스 조각의 애니메이션 (다른 조각이 움직이지 않고 움직이는 부분과 상호 작용하는 전체 보드 애니메이션)을 명확하게 분리 할 수 ​​있습니다. 상태 등을 동일하게 만들 수 있습니다. 따라서 책임이 분리되어 유지 보수가 쉽고 재사용이 용이합니다 (인트로 데모, 재생 모드). FSM을 사용하는 것이 번거로울 필요가 없다는 것을 보여주는 질문에 대한 답변이라고 생각합니다.
유령

정말 대단합니다. 감사합니다. 가장 최근의 의견에서 "FSM을 사용하는 것이 번거로울 필요는 없습니다." FSM을 사용하면 switch 문을 사용해야한다고 잘못 생각했습니다. 반드시 그런 것은 아닙니다. 또 다른 주요 확인 사항은 각 상태는 게임 엔진에 대한 참조가 필요하다는 것입니다. 이것이 어떻게 작동하는지 궁금했습니다.
vargonian

2

이런 종류의 일을 가능한 가장 간단한 방법으로 처리하는 것으로 시작합니다.

bool isPieceMoving;

그런 다음 해당 부울 플래그에 대한 검사를 관련 장소에 추가합니다.

나중에 내가 이것보다 더 특별한 경우가 필요하다는 것을 알게되면 더 좋은 것으로 리팩토링합니다. 내가 취할 3 가지 접근법이 있습니다 :

  • 배타적 하위 상태를 나타내는 플래그를 열거 형으로 리팩터링하십시오. 예. enum { PRE_MOVE, MOVE, POST_MOVE }필요할 때마다 전환 효과를 추가하십시오. 그런 다음 부울 플래그를 확인하는 데 사용되는이 열거 형을 확인할 수 있습니다. 이것은 간단한 변경이지만 확인해야 할 사항의 수를 줄이며 switch 문을 사용하여 동작을 효과적으로 관리 할 수 ​​있습니다.
  • 필요에 따라 개별 서브 시스템을 끕니다. 배틀 시퀀스 중 유일한 차이점은 조각을 이동할 수 없다는 것 pieceSelectionManager->disable()입니다. 시퀀스 시작시 또는를 호출 할 수 있습니다 pieceSelectionManager->enable(). 여전히 기본적으로 플래그가 있지만 이제는 제어하는 ​​오브젝트에 더 가깝게 저장되므로 게임 코드에서 추가 상태를 유지할 필요가 없습니다.
  • 이전 부분은 PieceSelectionManager가 있음을 의미합니다.보다 일반적으로 게임 상태와 동작의 일부를 전체 상태의 하위 집합을 일관된 방식으로 처리하는 작은 개체로 분해 할 수 있습니다. 이러한 각 개체에는 자체 상태가있어 동작을 결정하지만 다른 개체와 격리되어있어 관리하기 쉽습니다. 게임 스테이트 오브젝트 또는 메인 루프가 의사-글로벌의 덤핑 그라운드가되고 그러한 요소를 제거하도록 촉구하십시오!

일반적으로 말하자면 특수 사례 하위 상태에 관해서는 이것보다 더 이상 갈 필요가 없으므로 '빠르게 손을 getting'질 위험이 없다고 생각합니다.


1
그렇습니다. 국가와의 만남과 적절한 경우 bool / enum을 사용하는 것 사이에 선이 있다고 생각합니다. 그러나 나의 농담 적 경향을 알면 아마도 거의 모든 주를 자신의 계급으로 만들게 될 것입니다.
vargonian

수업이 대안보다 더 정확하다고 들리지만 주관적이라는 것을 기억하십시오. 다른 언어 구조로보다 쉽게 ​​표현할 수있는 작은 클래스를 너무 많이 만들면 코드의 의도가 모호해질 수 있습니다.
Kylotan

1

http://www.ai-junkie.com/architecture/state_driven/tut_state1.html 은 게임 상태 관리를위한 멋진 튜토리얼입니다! 게임 엔터 티나 위와 같은 메뉴 시스템에 사용할 수 있습니다.

그는 State Design Pattern 에 대해 가르치기 시작한 다음을 계속 구현하고 State Machine이를 계속해서 확장합니다. 아주 잘 읽었습니다! 전체 개념의 작동 방식과 새로운 유형의 문제에 적용하는 방법에 대한 확실한 이해를 제공합니다!


1

두 가지 모두 확장 가능하지 않기 때문에 상태 머신과 부울을 사용하지 마십시오. 상태 수가 증가하면 둘 다 혼란스러워집니다.

나는 보통 게임 플레이를 일련의 행동과 결과로 디자인한다. 어떤 게임 상태도 따로 정의 할 필요없이 자연스럽게 온다.

예를 들어 플레이어 입력을 비활성화하는 경우 : 일부 사용자 입력 처리기와 게임 내에서 입력이 비활성화되었다는 시각적 표시가 있으므로 입력을 비활성화하려면 입력을 비활성화해야합니다. 따라서 입력을 비활성화하려면 전체 객체를 비활성화하면됩니다. 일부 상태 머신에서 동기화하거나 부울 표시기에 반응합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.