본문 바로가기
-----ETC-----/C++ 게임 개발 시리즈

[C++ 게임 개발 시리즈] Day 17: 게임 상태 관리

by cogito21_cpp 2024. 8. 1.
반응형

게임 상태 관리

게임 상태 관리는 게임이 다양한 상태(예: 메인 메뉴, 게임 플레이, 일시 정지, 게임 오버 등)를 가질 수 있도록 하는 중요한 개념입니다. 상태 패턴(State Pattern)을 사용하여 이러한 상태 전환을 관리할 수 있습니다.

상태 패턴(State Pattern)

상태 패턴은 객체의 상태에 따라 다른 동작을 수행하도록 하는 디자인 패턴입니다. 이를 통해 상태 전환을 간단하고 명확하게 관리할 수 있습니다.

게임 상태 인터페이스 정의

먼저, 게임 상태 인터페이스를 정의합니다. 이 인터페이스는 각 상태에서 필요한 공통 메서드를 선언합니다.

class GameState {
public:
    virtual ~GameState() {}
    virtual void handleEvent(sf::Event& event) = 0;
    virtual void update(float deltaTime) = 0;
    virtual void render(sf::RenderWindow& window) = 0;
};

구체적인 상태 클래스 정의

그 다음, 메인 메뉴 상태와 게임 플레이 상태와 같은 구체적인 상태 클래스를 정의합니다.

class MainMenuState : public GameState {
public:
    MainMenuState(Game* game) : game(game) {}

    void handleEvent(sf::Event& event) override {
        if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Enter) {
            game->changeState(game->getPlayState());
        }
    }

    void update(float deltaTime) override {}

    void render(sf::RenderWindow& window) override {
        window.clear(sf::Color::Blue);
        // 메인 메뉴 렌더링 로직
        window.display();
    }

private:
    Game* game;
};

class PlayState : public GameState {
public:
    PlayState(Game* game) : game(game) {}

    void handleEvent(sf::Event& event) override {
        if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
            game->changeState(game->getMainMenuState());
        }
    }

    void update(float deltaTime) override {
        // 게임 플레이 업데이트 로직
    }

    void render(sf::RenderWindow& window) override {
        window.clear(sf::Color::Green);
        // 게임 플레이 렌더링 로직
        window.display();
    }

private:
    Game* game;
};

게임 상태 관리 클래스 정의

게임 상태를 관리하는 Game 클래스를 정의합니다. 이 클래스는 현재 상태를 보관하고, 상태 전환을 처리합니다.

class Game {
public:
    Game() : window(sf::VideoMode(800, 600), "State Pattern Example"),
             mainMenuState(this), playState(this), currentState(&mainMenuState) {}

    void run() {
        sf::Clock clock;
        while (window.isOpen()) {
            sf::Event event;
            while (window.pollEvent(event)) {
                if (event.type == sf::Event::Closed)
                    window.close();
                currentState->handleEvent(event);
            }

            float deltaTime = clock.restart().asSeconds();
            currentState->update(deltaTime);
            currentState->render(window);
        }
    }

    void changeState(GameState* state) {
        currentState = state;
    }

    GameState* getMainMenuState() { return &mainMenuState; }
    GameState* getPlayState() { return &playState; }

private:
    sf::RenderWindow window;
    GameState* currentState;
    MainMenuState mainMenuState;
    PlayState playState;
};

전체 코드

다음은 전체 코드입니다. 이 코드는 게임 상태 관리를 위해 상태 패턴을 사용합니다.

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include <iostream>

class GameState;

class Game {
public:
    Game();
    void run();
    void changeState(GameState* state);

    GameState* getMainMenuState();
    GameState* getPlayState();

private:
    sf::RenderWindow window;
    GameState* currentState;
    MainMenuState mainMenuState;
    PlayState playState;
};

class GameState {
public:
    virtual ~GameState() {}
    virtual void handleEvent(sf::Event& event) = 0;
    virtual void update(float deltaTime) = 0;
    virtual void render(sf::RenderWindow& window) = 0;
};

class MainMenuState : public GameState {
public:
    MainMenuState(Game* game) : game(game) {}

    void handleEvent(sf::Event& event) override {
        if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Enter) {
            game->changeState(game->getPlayState());
        }
    }

    void update(float deltaTime) override {}

    void render(sf::RenderWindow& window) override {
        window.clear(sf::Color::Blue);
        window.display();
    }

private:
    Game* game;
};

class PlayState : public GameState {
public:
    PlayState(Game* game) : game(game) {}

    void handleEvent(sf::Event& event) override {
        if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
            game->changeState(game->getMainMenuState());
        }
    }

    void update(float deltaTime) override {}

    void render(sf::RenderWindow& window) override {
        window.clear(sf::Color::Green);
        window.display();
    }

private:
    Game* game;
};

Game::Game() : window(sf::VideoMode(800, 600), "State Pattern Example"),
               mainMenuState(this), playState(this), currentState(&mainMenuState) {}

void Game::run() {
    sf::Clock clock;
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed)
                window.close();
            currentState->handleEvent(event);
        }

        float deltaTime = clock.restart().asSeconds();
        currentState->update(deltaTime);
        currentState->render(window);
    }
}

void Game::changeState(GameState* state) {
    currentState = state;
}

GameState* Game::getMainMenuState() { return &mainMenuState; }
GameState* Game::getPlayState() { return &playState; }

int main() {
    Game game;
    game.run();
    return 0;
}

결론

오늘은 상태 패턴을 사용하여 게임 상태를 관리하는 방법을 학습했습니다. 상태 패턴을 사용하면 다양한 게임 상태 간의 전환을 쉽게 관리할 수 있습니다. 질문이나 추가적인 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "Day 18: 간단한 AI 기초 (상태 머신)"에 대해 학습하겠습니다.

반응형