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


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.