본문 바로가기
-----ETC-----/C++로 배우는 게임 엔진 개발

[C++로 배우는 게임 엔진 개발] Day 29: 게임 씬 관리 시스템 구현

by cogito21_cpp 2024. 8. 1.
반응형

게임 씬 관리 시스템 구현

오늘은 게임 씬 관리 시스템을 구현하여 복잡한 게임 씬을 효과적으로 관리하는 방법을 학습하겠습니다. 씬 관리 시스템은 게임의 다양한 상태 (예: 메인 메뉴, 게임 플레이, 설정 화면 등)를 관리하고, 상태 전환을 처리하는 데 유용합니다.

1. 씬 관리 시스템 설계

씬 관리 시스템은 각 씬을 관리하고 전환하는 역할을 합니다. 이를 위해 Scene, SceneManager 클래스를 구현합니다.

 

헤더 파일 작성

include/Scene.h 파일을 생성하고 다음과 같이 작성합니다.

#ifndef SCENE_H
#define SCENE_H

class Scene {
public:
    virtual ~Scene() {}
    virtual void Initialize() = 0;
    virtual void Update(float deltaTime) = 0;
    virtual void Render() = 0;
    virtual void HandleEvents() = 0;
    virtual void Shutdown() = 0;
};

#endif // SCENE_H

include/SceneManager.h 파일을 생성하고 다음과 같이 작성합니다.

#ifndef SCENEMANAGER_H
#define SCENEMANAGER_H

#include "Scene.h"
#include <stack>

class SceneManager {
public:
    static SceneManager& Instance();

    void ChangeScene(Scene* scene);
    void PushScene(Scene* scene);
    void PopScene();

    void Update(float deltaTime);
    void Render();
    void HandleEvents();
    void Shutdown();

private:
    SceneManager() {}
    ~SceneManager() {}

    std::stack<Scene*> scenes;
};

#endif // SCENEMANAGER_H

 

소스 파일 작성

src/SceneManager.cpp 파일을 생성하고 다음과 같이 작성합니다.

#include "SceneManager.h"

SceneManager& SceneManager::Instance() {
    static SceneManager instance;
    return instance;
}

void SceneManager::ChangeScene(Scene* scene) {
    while (!scenes.empty()) {
        scenes.top()->Shutdown();
        delete scenes.top();
        scenes.pop();
    }
    scenes.push(scene);
    scenes.top()->Initialize();
}

void SceneManager::PushScene(Scene* scene) {
    if (!scenes.empty()) {
        scenes.top()->Shutdown();
    }
    scenes.push(scene);
    scenes.top()->Initialize();
}

void SceneManager::PopScene() {
    if (!scenes.empty()) {
        scenes.top()->Shutdown();
        delete scenes.top();
        scenes.pop();
    }
    if (!scenes.empty()) {
        scenes.top()->Initialize();
    }
}

void SceneManager::Update(float deltaTime) {
    if (!scenes.empty()) {
        scenes.top()->Update(deltaTime);
    }
}

void SceneManager::Render() {
    if (!scenes.empty()) {
        scenes.top()->Render();
    }
}

void SceneManager::HandleEvents() {
    if (!scenes.empty()) {
        scenes.top()->HandleEvents();
    }
}

void SceneManager::Shutdown() {
    while (!scenes.empty()) {
        scenes.top()->Shutdown();
        delete scenes.top();
        scenes.pop();
    }
}

2. 게임 엔진에 씬 관리 시스템 통합

이제 게임 엔진에 씬 관리 시스템을 통합하고, 다양한 씬을 관리하는 기능을 추가합니다.

 

헤더 파일 수정

include/GameEngine.h 파일을 수정하여 SceneManager 클래스를 포함합니다.

#ifndef GAMEENGINE_H
#define GAMEENGINE_H

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <GL/glew.h>
#include "ParticleSystem.h"
#include "UIManager.h"
#include "LuaManager.h"
#include "NetworkManager.h"
#include "TextureManager.h"
#include "Graphics3D.h"
#include "Model.h"
#include "Camera.h"
#include "PhysicsManager.h"
#include "Skybox.h"
#include "PostProcessing.h"
#include "Instancing.h"
#include "SceneManager.h"
#include "AudioManager.h"

class GameEngine {
public:
    GameEngine();
    ~GameEngine();
    bool Initialize(const char* title, int width, int height);
    void Run();
    void Shutdown();

private:
    SDL_Window* window;
    SDL_GLContext glContext;
    SDL_Renderer* renderer;
    GLuint shaderProgram;
    ParticleSystem* particleSystem;
    UIManager* uiManager;
    LuaManager* luaManager;
    NetworkManager* networkManager;
    Graphics3D* graphics3D;
    Model* model;
    Camera* camera;
    PhysicsManager* physicsManager;
    Skybox* skybox;
    PostProcessing* postProcessing;
    Instancing* instancing;
    SceneManager& sceneManager;
    bool isRunning;
    Uint32 frameStart;
    int frameTime;

    bool InitializeOpenGL();
    GLuint LoadShader(const std::string& vertexPath, const std::string& fragmentPath);
    void HandleEvents();
    void Update();
    void Render();
};

#endif // GAMEENGINE_H

 

소스 파일 수정

src/GameEngine.cpp 파일을 다음과 같이 수정합니다.

#include "GameEngine.h"
#include "SceneManager.h"
#include "ExampleScene.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

const int FPS = 60;
const int FRAME_DELAY = 1000 / FPS;

float lastX = 400, lastY = 300;
bool firstMouse = true;

GameEngine::GameEngine()
    : window(nullptr), glContext(nullptr), renderer(nullptr), shaderProgram(0), 
      particleSystem(nullptr), uiManager(nullptr), luaManager(nullptr), networkManager(nullptr),
      graphics3D(nullptr), model(nullptr), camera(nullptr), physicsManager(nullptr), skybox(nullptr),
      postProcessing(nullptr), instancing(nullptr), sceneManager(SceneManager::Instance()), 
      isRunning(false), frameStart(0), frameTime(0) {}

GameEngine::~GameEngine() {
    Shutdown();
}

bool GameEngine::Initialize(const char* title, int width, int height) {
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        std::cerr << "SDL_Init Error: " << SDL_GetError() << std::endl;
        return false;
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    if (window == nullptr) {
        std::cerr << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
        return false;
    }

    glContext = SDL_GL_CreateContext(window);
    if (glContext == nullptr) {
        std::cerr << "SDL_GL_CreateContext Error: " << SDL_GetError() << std::endl;
        return false;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (renderer == nullptr) {
        std::cerr << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
        return false;
    }

    if (glewInit() != GLEW_OK) {
        std::cerr << "GLEW Initialization failed!" << std::endl;
        return false;
    }

    shaderProgram = LoadShader("shaders/vertex_shader_3d.glsl", "shaders/fragment_shader_3d.glsl");
    if (shaderProgram == 0) {
        return false;
    }

    particleSystem = new ParticleSystem(500);

    uiManager = new UIManager(renderer);
    if (!uiManager->Initialize()) {
        return false;
    }

    uiManager->RenderText("Hello, Game Engine!", 10, 10, 24, { 255, 255, 255, 255 });

    luaManager = new LuaManager();
    if (!luaManager->Initialize()) {
        return false;
    }

    luaManager->LoadScript("path/to/your/script.lua");

    if (!TextureManager::Instance().Load("path/to/your/texture.png", "example", renderer)) {
        return false;
    }

    networkManager = new NetworkManager();
    if (!networkManager->Initialize()) {
        return false;
    }

    graphics3D = new Graphics3D();
    if (!graphics3D->Initialize()) {
        return false;
    }

    model = new Model("path/to/your/model.obj");
    camera = new Camera(glm::vec3(0.0f, 0.0f, 3.0f));
    physicsManager = new PhysicsManager();
    physicsManager->Initialize();

    std::vector<std::string> faces{
        "path/to/right.jpg",
        "path/to/left.jpg",
        "path/to/top.jpg",
        "path/to/bottom.jpg",
        "path/to/front.jpg",
        "path/to/back.jpg"
    };
    skybox = new Skybox();
    if (!skybox->Initialize(faces)) {
        return false;
    }

    postProcessing = new PostProcessing();
    if (!postProcessing->Initialize(width, height)) {
        return false;
    }

    instancing = new Instancing();
    if (!instancing->Initialize())

 {
        return false;
    }

    // 물리 엔진에 오브젝트 추가
    btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0, 1, 0), 1);
    btCollisionShape* fallShape = new btSphereShape(1);

    btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, -1, 0)));
    btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0, groundMotionState, groundShape, btVector3(0, 0, 0));
    btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);
    physicsManager->GetDynamicsWorld()->addRigidBody(groundRigidBody);

    btDefaultMotionState* fallMotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 50, 0)));
    btScalar mass = 1;
    btVector3 fallInertia(0, 0, 0);
    fallShape->calculateLocalInertia(mass, fallInertia);
    btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass, fallMotionState, fallShape, fallInertia);
    btRigidBody* fallRigidBody = new btRigidBody(fallRigidBodyCI);
    physicsManager->GetDynamicsWorld()->addRigidBody(fallRigidBody);

    // 기본 씬 설정
    Scene* exampleScene = new ExampleScene();
    sceneManager.ChangeScene(exampleScene);

    isRunning = true;
    return true;
}

GLuint GameEngine::LoadShader(const std::string& vertexPath, const std::string& fragmentPath) {
    std::string vertexCode;
    std::string fragmentCode;
    std::ifstream vShaderFile;
    std::ifstream fShaderFile;

    vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);

    try {
        vShaderFile.open(vertexPath);
        fShaderFile.open(fragmentPath);
        std::stringstream vShaderStream, fShaderStream;

        vShaderStream << vShaderFile.rdbuf();
        fShaderStream << fShaderFile.rdbuf();

        vShaderFile.close();
        fShaderFile.close();

        vertexCode = vShaderStream.str();
        fragmentCode = fShaderStream.str();
    }
    catch (std::ifstream::failure& e) {
        std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
        return 0;
    }

    const char* vShaderCode = vertexCode.c_str();
    const char* fShaderCode = fragmentCode.c_str();

    GLuint vertexShader, fragmentShader;
    GLint success;
    GLchar infoLog[512];

    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vShaderCode, nullptr);
    glCompileShader(vertexShader);

    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
        std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
        return 0;
    }

    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fShaderCode, nullptr);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
        std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
        return 0;
    }

    GLuint program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);

    glGetProgramiv(program, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(program, 512, nullptr, infoLog);
        std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
        return 0;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return program;
}

void GameEngine::Run() {
    while (isRunning) {
        frameStart = SDL_GetTicks();

        HandleEvents();
        Update();

        postProcessing->BeginRender();
        Render();
        postProcessing->EndRender();

        postProcessing->Render(camera->GetViewMatrix(), glm::perspective(glm::radians(camera->Zoom), (float)800 / (float)600, 0.1f, 100.0f));

        frameTime = SDL_GetTicks() - frameStart;
        if (FRAME_DELAY > frameTime) {
            SDL_Delay(FRAME_DELAY - frameTime);
        }
    }
}

void GameEngine::HandleEvents() {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        if (event.type == SDL_QUIT) {
            isRunning = false;
        }
        if (event.type == SDL_KEYDOWN) {
            switch (event.key.keysym.sym) {
                case SDLK_ESCAPE:
                    isRunning = false;
                    break;
                case SDLK_w:
                    camera->ProcessKeyboard(FORWARD, frameTime / 1000.0f);
                    break;
                case SDLK_s:
                    camera->ProcessKeyboard(BACKWARD, frameTime / 1000.0f);
                    break;
                case SDLK_a:
                    camera->ProcessKeyboard(LEFT, frameTime / 1000.0f);
                    break;
                case SDLK_d:
                    camera->ProcessKeyboard(RIGHT, frameTime / 1000.0f);
                    break;
                default:
                    break;
            }
        }
        if (event.type == SDL_MOUSEMOTION) {
            float xpos = static_cast<float>(event.motion.x);
            float ypos = static_cast<float>(event.motion.y);

            if (firstMouse) {
                lastX = xpos;
                lastY = ypos;
                firstMouse = false;
            }

            float xoffset = xpos - lastX;
            float yoffset = lastY - ypos;

            lastX = xpos;
            lastY = ypos;

            camera->ProcessMouseMovement(xoffset, yoffset);
        }
        if (event.type == SDL_MOUSEWHEEL) {
            camera->ProcessMouseScroll(static_cast<float>(event.wheel.y));
        }
    }

    sceneManager.HandleEvents();
}

void GameEngine::Update() {
    float deltaTime = frameTime / 1000.0f;
    particleSystem->Update(deltaTime);
    physicsManager->Update(deltaTime);

    luaManager->ExecuteFunction("update", deltaTime);

    networkManager->Service();

    sceneManager.Update(deltaTime);
}

void GameEngine::Render() {
    // 화면을 검은색으로 지우기
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(shaderProgram);

    // 카메라 뷰 및 프로젝션 설정
    glm::mat4 view = camera->GetViewMatrix();
    glm::mat4 projection = glm::perspective(glm::radians(camera->Zoom), (float)800 / (float)600, 0.1f, 100.0f);

    GLuint viewLoc = glGetUniformLocation(shaderProgram, "view");
    GLuint projLoc = glGetUniformLocation(shaderProgram, "projection");
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    // 3D 모델 렌더링
    model->Render(shaderProgram);

    // 인스턴스 렌더링
    instancing->Render(view, projection);

    // 스카이박스 렌더링
    skybox->Render(view, projection);

    // 씬 렌더링
    sceneManager.Render();

    // SDL 렌더러 사용하여 텍스처 렌더링
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
    TextureManager::Instance().Draw("example", 100, 100, 64, 64, renderer);
    uiManager->Render();
    SDL_RenderPresent(renderer);

    SDL_GL_SwapWindow(window);
}

void GameEngine::Shutdown() {
    sceneManager.Shutdown();

    if (particleSystem) {
        delete particleSystem;
        particleSystem = nullptr;
    }
    if (uiManager) {
        uiManager->Shutdown();
        delete uiManager;
        uiManager = nullptr;
    }
    if (luaManager) {
        luaManager->Shutdown();
        delete luaManager;
        luaManager = nullptr;
    }
    if (networkManager) {
        networkManager->Shutdown();
        delete networkManager;
        networkManager = nullptr;
    }
    if (graphics3D) {
        graphics3D->Shutdown();
        delete graphics3D;
        graphics3D = nullptr;
    }
    if (model) {
        delete model;
        model = nullptr;
    }
    if (camera) {
        delete camera;
        camera = nullptr;
    }
    if (physicsManager)

 {
        physicsManager->Shutdown();
        delete physicsManager;
        physicsManager = nullptr;
    }
    if (skybox) {
        delete skybox;
        skybox = nullptr;
    }
    if (postProcessing) {
        delete postProcessing;
        postProcessing = nullptr;
    }
    if (instancing) {
        delete instancing;
        instancing = nullptr;
    }
    TextureManager::Instance().ClearTextureMap();
    if (shaderProgram) {
        glDeleteProgram(shaderProgram);
        shaderProgram = 0;
    }
    if (renderer) {
        SDL_DestroyRenderer(renderer);
        renderer = nullptr;
    }
    if (glContext) {
        SDL_GL_DeleteContext(glContext);
        glContext = nullptr;
    }
    if (window) {
        SDL_DestroyWindow(window);
        window = nullptr;
    }
    SDL_Quit();
}

 

예제 씬 작성

간단한 예제 씬을 작성합니다.

include/ExampleScene.h 파일을 생성하고 다음과 같이 작성합니다.

#ifndef EXAMPLESCENE_H
#define EXAMPLESCENE_H

#include "Scene.h"
#include "Camera.h"
#include "Model.h"
#include <glm/glm.hpp>

class ExampleScene : public Scene {
public:
    ExampleScene();
    ~ExampleScene();

    void Initialize() override;
    void Update(float deltaTime) override;
    void Render() override;
    void HandleEvents() override;
    void Shutdown() override;

private:
    Camera* camera;
    Model* model;
    glm::mat4 projection;
    GLuint shaderProgram;
};

#endif // EXAMPLESCENE_H

src/ExampleScene.cpp 파일을 생성하고 다음과 같이 작성합니다.

#include "ExampleScene.h"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>

ExampleScene::ExampleScene() : camera(nullptr), model(nullptr), shaderProgram(0) {}

ExampleScene::~ExampleScene() {
    Shutdown();
}

void ExampleScene::Initialize() {
    camera = new Camera(glm::vec3(0.0f, 0.0f, 3.0f));
    model = new Model("path/to/your/model.obj");

    // 셰이더 프로그램 로드
    shaderProgram = LoadShader("shaders/vertex_shader_3d.glsl", "shaders/fragment_shader_3d.glsl");
    if (shaderProgram == 0) {
        std::cerr << "Failed to load shaders." << std::endl;
        return;
    }

    projection = glm::perspective(glm::radians(camera->Zoom), (float)800 / (float)600, 0.1f, 100.0f);
}

void ExampleScene::Update(float deltaTime) {
    // 카메라 업데이트
    camera->ProcessKeyboard(FORWARD, deltaTime);
}

void ExampleScene::Render() {
    glUseProgram(shaderProgram);

    glm::mat4 view = camera->GetViewMatrix();

    GLuint viewLoc = glGetUniformLocation(shaderProgram, "view");
    GLuint projLoc = glGetUniformLocation(shaderProgram, "projection");
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    model->Render(shaderProgram);
}

void ExampleScene::HandleEvents() {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        if (event.type == SDL_QUIT) {
            exit(0);
        }
        if (event.type == SDL_KEYDOWN) {
            switch (event.key.keysym.sym) {
                case SDLK_ESCAPE:
                    exit(0);
                    break;
                case SDLK_w:
                    camera->ProcessKeyboard(FORWARD, 0.1f);
                    break;
                case SDLK_s:
                    camera->ProcessKeyboard(BACKWARD, 0.1f);
                    break;
                case SDLK_a:
                    camera->ProcessKeyboard(LEFT, 0.1f);
                    break;
                case SDLK_d:
                    camera->ProcessKeyboard(RIGHT, 0.1f);
                    break;
                default:
                    break;
            }
        }
        if (event.type == SDL_MOUSEMOTION) {
            float xpos = static_cast<float>(event.motion.x);
            float ypos = static_cast<float>(event.motion.y);

            float xoffset = xpos - lastX;
            float yoffset = lastY - ypos;

            lastX = xpos;
            lastY = ypos;

            camera->ProcessMouseMovement(xoffset, yoffset);
        }
        if (event.type == SDL_MOUSEWHEEL) {
            camera->ProcessMouseScroll(static_cast<float>(event.wheel.y));
        }
    }
}

void ExampleScene::Shutdown() {
    if (camera) {
        delete camera;
        camera = nullptr;
    }
    if (model) {
        delete model;
        model = nullptr;
    }
    if (shaderProgram) {
        glDeleteProgram(shaderProgram);
        shaderProgram = 0;
    }
}

GLuint ExampleScene::LoadShader(const std::string& vertexPath, const std::string& fragmentPath) {
    std::string vertexCode;
    std::string fragmentCode;
    std::ifstream vShaderFile;
    std::ifstream fShaderFile;

    vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);

    try {
        vShaderFile.open(vertexPath);
        fShaderFile.open(fragmentPath);
        std::stringstream vShaderStream, fShaderStream;

        vShaderStream << vShaderFile.rdbuf();
        fShaderStream << fShaderFile.rdbuf();

        vShaderFile.close();
        fShaderFile.close();

        vertexCode = vShaderStream.str();
        fragmentCode = fShaderStream.str();
    }
    catch (std::ifstream::failure& e) {
        std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
        return 0;
    }

    const char* vShaderCode = vertexCode.c_str();
    const char* fShaderCode = fragmentCode.c_str();

    GLuint vertexShader, fragmentShader;
    GLint success;
    GLchar infoLog[512];

    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vShaderCode, nullptr);
    glCompileShader(vertexShader);

    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
        std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
        return 0;
    }

    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fShaderCode, nullptr);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
        std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
        return 0;
    }

    GLuint program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);

    glGetProgramiv(program, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(program, 512, nullptr, infoLog);
        std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
        return 0;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return program;
}

3. 프로젝트 빌드 및 실행

  1. Visual Studio에서 CMake 프로젝트 열기:
    • Visual Studio를 실행하고, File -> Open -> CMake...를 선택합니다.
    • GameEngine 디렉토리를 선택하여 프로젝트를 엽니다.
  2. 프로젝트 빌드:
    • Visual Studio 상단의 Build 메뉴에서 Build All을 선택하여 프로젝트를 빌드합니다.
  3. 프로젝트 실행:
    • Debug 메뉴에서 Start Without Debugging을 선택하여 프로그램을 실행합니다.
    • 윈도우 창이 생성되고, 씬 관리 시스템을 통해 다양한 씬을 관리할 수 있습니다.

마무리

오늘은 게임 씬 관리 시스템을 구현하여 복잡한 게임 씬을 효과적으로 관리하는 방법을 학습했습니다. 이를 통해 다양한 상태의 씬을 관리하고 전환할 수 있게 되었습니다. 다음 단계에서는 게임 엔진을 배포하고 다음 단계로 나아가는 방법을 배우겠습니다.

질문이나 추가적인 피드백이 있으면 언제든지 댓글로 남겨 주세요.

Day 30 예고

다음 날은 "게임 엔진 배포 및 다음 단계"에 대해 다룰 것입니다. 게임 엔진을 배포하고, 이후 개발자 커뮤니티와 협력하여 프로젝트를 더욱 발전시키는 방법을 배워보겠습니다.

반응형