[C++] 1.1 실시간 상호 작용 어플리케이션의 구조
카테고리: C++ games
태그: Cpp Graphics OpenGL Programming
인프런에 있는 홍정모 교수님의 홍정모의 게임 만들기 연습 문제 패키지 강의를 듣고 정리한 필기입니다. 😀
🌜 공부에 사용된 홍정모 교수님의 코드들 보러가기
🌜 [홍정모의 게임 만들기 연습 문제 패키지] 강의 들으러 가기!
Chapter 1. 기본 기능 구현
1.1 실시간 상호 작용 어플리케이션의 구조
👱🏽♀️ 게임 엔진의 원리를 이해하기 좋은 코드들이다.
Game2D.h 설명
update
함수는 꼭 오버라이딩 해주어야 한다.
📃Game2D.h
#include "RGB.h" // 색을 결정. R,G,B 값을 받는 생성자 有
#include "Vector2.h" // 2차원 좌표
#include "Vector3.h" // 3차원 좌표
#include "Colors.h"
// 👆 RGB를 include하여 다양한 색상 이름의 RGB 객체들을 미리 정의해 둠. const RGB yellow(255, 255, 0) 이런식으로.
#include "Timer.h"
#include "DrawFunctions.h"
// 👆 원, 세모, 네모, 선분 등등 그림을 그리는 함수들을 모은 클래스. drawWLine, drawFilledBox 등등..
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <thread> // std::this_thread::sleep_for
#include <iostream>
#include <vector>
#include <string>
#include <map>
namespace jm
{
using vec2 = Vector2<float>;
using vec3 = Vector3<float>;
class Game2D
{
private:
/*게임 창 해상도*/
int width = 640;
int height = 480;
/*게임 창 화면의 포인터*/
GLFWwindow* glfw_window = nullptr;
Timer timer;
/*fps (프레임)의 역수*/
float spf = 1.0f / 60.0f; // second(s) per frame
/*키보드 입력을 받아서 그릴거냐(true) 말거냐(false) */
std::map<int, bool> key_status; // key_id, is_pressed
std::map<int, bool> mbtn_status; // mouse_button_id, is_pressed
bool draw_grid = false;
public: // 생성자
Game2D()
{}
/* 제목(title), 해상도(width, height), 풀스크린 사용여부, 어느 모니터에 출력할지
이렇게 4가지 설정 가능 */
Game2D(const std::string& _title, const int& _width, const int& _height,
const bool & use_full_screen = false, const int & display_ix = 0);
~Game2D();
Game2D & init(const std::string& _title, const int& _width, const int& _height,
const bool & use_full_screen = false, const int & display_ix = 0);
초기화 하는 과정에서의 에러 출력 (거의 볼 일 X)
void reportErrorAndExit(const std::string& function_name, const std::string& message);
bool isKeyPressed(const int& key);
bool isKeyReleased(const int & key);
bool isKeyPressedAndReleased(const int& key); // 사용자가 키를 눌렀다가 뗐는지를 확인하는 함수
bool isMouseButtonPressed(const int& mbtn);
bool isMouseButtonReleased(const int& mbtn);
bool isMouseButtonPressedAndReleased(const int& mbtn);
vec2 getCursorPos(const bool& screen_coordinates = true);
float getTimeStep(); // 한 프레임 당 시간이 얼마나 지났는지 측정해주는 함수
void drawGrid();
/*run과 update 아주 중요!*/
void run(); // Game2D.cpp 에 바디 있음
virtual void update() //가상함수인 이유 -> 꼭 오버라이딩 해서 사용하라는 의미 !
{
// 예시
// draw
// play sould
// physics update
// etc.
}
};
}
📜Game2D.cpp에서 void Game2D::run()
함수 부분 설명
while
부분이 제일 중요하다. 프로그램의 메인 Loop가 된다.
Game2D.cpp 中
void Game2D::run()
{
if (glfw_window == nullptr)
init("This is my digital canvas!", 1280, 960, false); // initialize with default setting
// 게임의 메인 루프
while (!glfwWindowShouldClose(glfw_window))// main loop
{
// 1. ESC 누르면 종료
if (isKeyPressed(GLFW_KEY_ESCAPE)) {
std::cout << "ESC key ends main loop" << std::endl;
break;
}
// 2. 타이머 start
timer.start();
// 3. 렌더링 시작 전 전처리
glfwMakeContextCurrent(glfw_window);
glClearColor(1, 1, 1, 1); // while background
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// 4. 격자 그리기
drawGrid();
// 5. ⭐update 함수 호출⭐
update(); // the major worker function
// 6. 렌더링 완료하고 마무리
glPopMatrix();
// post draw
glfwSwapBuffers(glfw_window); // double buffering
//glfwSetInputMode(glfw_window, GLFW_STICKY_KEYS, GLFW_FALSE); // not working
glfwPollEvents();
//const double dt = timer.stopAndGetElapsedMilli();
//Debugging
//std::cout << dt << std::endl;
//if (dt < spf) // to prevent too high fps
//{
// const auto time_to_sleep = static_cast<int>((spf - dt) * 1000.0f);
// std::this_thread::sleep_for(std::chrono::milliseconds(time_to_sleep));
//
// //Debugging
// //std::cout << "sleep " << time_to_sleep << std::endl;
//}
}
glfwTerminate();
}
내가 실습한 코드
1. 빈 화면만 출력하기
#include "Game2D.h"
#include "PrimitivesGallery.h"
#include "TankExample.h"
#include "FaceExample.h"
#include "WalkingPerson.h"
#include "SolarSystem.h"
namespace jm
{
class RotatingStarExample : public Game2D
{
public:
void update() override // Game2D의 update 함수 오버라이딩
{
}
};
}
int main(void)
{
jm::RotatingStarExample().run();
return 0;
}
2. 풀 스크린의 빈 스크린 출력하기
#include "Game2D.h"
#include "PrimitivesGallery.h"
#include "TankExample.h"
#include "FaceExample.h"
#include "WalkingPerson.h"
#include "SolarSystem.h"
namespace jm
{
class RotatingStarExample : public Game2D
{
public:
void update() override // Game2D의 update 함수 오버라이딩
{
}
};
}
int main(void)
{
/* 생성자 네번째 인수를 true로 바꿔 풀스크린
창 이름은 "This is my digital canvas!" */
jm::RotatingStarExample().init("This is my digital canvas!", 1280, 960, true).run();
return 0;
}
3. 별 그려보기
DrawFunction.h
의 drawFilledStar
함수 사용
#include "Game2D.h"
#include "PrimitivesGallery.h"
#include "TankExample.h"
#include "FaceExample.h"
#include "WalkingPerson.h"
#include "SolarSystem.h"
namespace jm
{
class RotatingStarExample : public Game2D
{
public:
void update() override // Game2D의 update 함수 오버라이딩
{
drawFilledStar(Colors::gold, 0.4f, 0.25f);
// 별의 바깥쪽 원의 반지름이 0.4f라는 의미, 별 안쪽의 원의 반지름이 0.25f라는 의미
}
};
}
int main(void)
{
jm::RotatingStarExample().init("This is my digital canvas!", 1280, 960, false).run();
return 0;
}
4. 회전하는 별 그려보기 (시간 개념 필요)
#include "Game2D.h"
#include "PrimitivesGallery.h"
#include "TankExample.h"
#include "FaceExample.h"
#include "WalkingPerson.h"
#include "SolarSystem.h"
namespace jm
{
class RotatingStarExample : public Game2D
{
float time = 0.0f; // 시간 0.0에서 시작
public:
void update() override // Game2D의 update 함수 오버라이딩
{
rotate(time * 180.0f); // 1초에 반바퀴 돌게끔
drawFilledStar(Colors::gold, 0.4f, 0.25f);
time += this->getTimeStep(); // 시간이 흘러야 함
}
};
}
int main(void)
{
jm::RotatingStarExample().init("This is my digital canvas!", 1280, 960, false).run();
return 0;
}
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기