게임 상태 관리 (게임, 메뉴, 타이틀 화면 등)


11

기본적으로 지금까지 만든 모든 단일 게임에는 항상 "current_state"와 같은 변수가 있습니다.이 변수는 "game", "titlescreen", "gameoverscreen"등이 될 수 있습니다.

그리고 내 업데이트 기능에 큰 것이 있습니다.

if current_state == "game" 
  game stuf
  ...
else if current_state == "titlescreen"
  ...

그러나 이것이 상태를 처리하는 전문적이고 깨끗한 방법이라고 생각하지 않습니다. 더 나은 방법 으로이 작업을 수행하는 방법에 대한 아이디어가 있습니까? 아니면 이것이 표준 방법입니까?


어떤 언어, 프레임 워크 등을 사용하고 있습니까?
Petr Abdulin

보통 루아 + 사랑. 또한 다른 프레임 워크가이를 처리하는 다른 방법이 있음을 발견했습니다. SFML에는 아주 멋진 Screen 클래스가있는 것 같습니다.
David Gomes

1
상태 머신을 조사 했습니까?
Darcara

1
오른쪽 상단의 검색 창에서 게임 상태를 찾을 수도 있습니다. 몇 가지 결과를 제공해야합니다.
TravisG

두 번째 Darcara가 있어야합니다-이것은 State Machines이 사용되는 것과 정확히 같습니다.
balajeerc

답변:


14

화면에 대해 이야기하고 있기 때문에 모든 논리를 다른 화면으로 분리하는 것이 가장 좋습니다. 내가 일반적으로하는 일 :

screen이라는 인터페이스를 정의하고 여러 화면으로 구현하십시오. LoadingScreen, MainMenuScreen, GameScreen, GameOverScreen, HighScoreScreen 등과 같이 게임에서 현재 화면을 유지하는 변수를 넣습니다. 각 루프에서 screen.update ()를 호출하고 현재 화면을 렌더링합니다. 상태가 현재 화면에 의해 정의되므로 이렇게하면 "이 상태를 수행하는 경우"가 많이 절약됩니다.

이것은 당신의 논리를 아주 잘 분리 할 것입니다.

예제 코드 :

### Screen interface ###
public interface Screen {

    public void show();

    public void update(float delta);

    public void render(float delta);

    public void hide ();
}

### An implementation of screen ###
public class MainMenuScreen implements Screen {

    private Game game;

    public MainMenuScreen(Game game) {
        this.game = game;
    }

    public void show() {
        // init stuff
    }

    public void update(float delta) {
        // react to clicks, update animations etc.
        if (buttonwasclicked) {
            game.setScreen(new GameScreen(game)); // change the screen
        }
    }

    public void render(float delta) {
        // draw everything
    }

    public void hide() {
        // release all resources, as the screen is being hidden
    }
}

### Game, drawing the appropriate screen ###
public class Game {

    public Screen screen;

    public void update() {
        screen.update(getDeltaTime);
        screen.render();
    }

    public void setScreen(Screen screen) {
        this.screen.hide();

        this.screen = screen;
        this.screen.show();
    }
}

또는 게임 설정에 따라 게임처럼 무한 루프가있을 수 있습니다.

while(true) {
    calculatetimesincelastframe()
    screen.update(time);
    screen.render(time);
}

5

이미 Middleclass를 사용하고 있다면 Statefull 이라는 훌륭한 상태 머신 라이브러리가 있습니다. 사용하기 쉽고 Matsemann이 제안한 것과 동일한 아이디어를 구성합니다.


2

귀하의 경우 current_state변수가 문자열, 다음이 루아 정말 간단합니다 :

game_states = {}
function game_states.game()
    -- game stuff
end
function game_states.titlescreen()
    -- title screen stuff
end

-- then, inside the Update function:
game_states[current_state]()

1

내가하는 일은 대략 다음과 같습니다.

I는이 방향성 비순환 그래프 본질적으로 서로 다른 점에서 노드 단지 무리 인 데이터 구조. 각 노드는 게임 시스템을 나타냅니다. 예를 들어 UI, 월드, 입력, 렌더링 그리고 각 노드는 이전 또는 이후의 다른 노드를 가리 킵니다. 모든 노드가 배치되면 간단한 목록으로 쉽게 전개 할 수 있습니다. 이 DAG를 설정하는 것이 게임 시작시 가장 먼저하는 일입니다. AI라고 말하면 새로운 시스템을 추가하고 싶을 때마다 코드를 작성하고 게임에 의존하고 무엇이 의존해야하는지 알려 주면됩니다.

내 주요 게임 루프가 그 뒤를 따라 각 시스템을 순서대로 실행합니다. 첫 번째 입력을 처리 한 다음 세계 업데이트를 수행 한 다음 다른 작업을 수행합니다. UI가 거의 끝 나가고 렌더링이 마지막입니다. 게임이 처음 시작되면 월드 나 물리 또는 AI가 없으므로 해당 단계를 건너 뛰고 타이틀 화면 만 표시됩니다. 게임을 올바르게 시작하면 UI가 월드 시스템에 메시지를 보내서 켜고 처리합니다. 게임 상태를 관리한다는 것은 다양한 시스템을 켜고 끄는 것을 의미합니다. 각 시스템에는 다른 모든 시스템과 독립적으로 처리되는 자체 상태 정보 세트가 있습니다 ( 완전히 그렇지는 않습니다)실제로 많은 시스템이 동일한 데이터 세트에서 작동합니다. 예를 들어 UI 시스템은 예를 들어 정보를 표시하기 위해 전 세계의 데이터를 가져옵니다. AI 시스템은 또한 세계의 엔티티를보고 메시지를 보내야합니다.


이 답변은 다른 질문에 대한 좋은 답변 입니다.
Matsemann

어떻게 요? 그는 다양한 게임 상태를 설정하는 방법을 물었고 현재 솔루션은 상태 머신을 사용하지 않고 대신 상태 머신이 아닌 DAG 인 다양한 시스템으로 비트를 분할합니다.
Alex Ames

1

Lua + Love2d에서 주를 구성하는 방법은 다음과 같습니다. 긴 if / then 문을 피합니다.

먼저 update (dt) 및 render () 메서드가 포함 된 기본 클래스를 만듭니다. onKeyDown (key)와 같은 이벤트 처리 방법을 제공 할 수도 있습니다. 이 클래스를 Stage라고하지만 메서드를 구현하는 모든 개체가 작동합니다. 그런 다음 각 게임 상태마다 해당 클래스의 인스턴스를 만들어 필요한 메소드를 구현합니다. 그런 다음 상태 이름과 상태 인스턴스가 포함 된 키 / 값 테이블을 만듭니다. 그런 다음 전역 조건에서 currentState를 추적하여 특정 조건이 충족 될 때 상태가 변경 될 수 있도록합니다.

states = {}
states["title"] = title   -- Where title implements Stage class.
states["game"] = game     -- You could create the instance of 'game' lazily too.
currentState = "title"

function love.update(dt)
    if states[currentState] ~= nil then
       states[currentState]:update(dt) 
    end
end

-1

글쎄요, IMO, 이런 식으로 상태를 처리하는 것은 괜찮습니다. 다음과 같이 각 상태에 대한 기능을 사용하여 훨씬 더 깨끗하게 만들 수 있습니다.

if current_state == "game" 
  game()
else if current_state == "titlescreen"
  titlescreen()

또는이 접근법에서 다른 귀찮은 점이 있습니다 (업데이트 방법이 매우 길다는 것을 제외하고는 말입니까?)

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