반응형
3D 게임 프로젝트 시작 (3)
어제는 3D 게임 프로젝트에 카메라 컨트롤과 조명을 추가하여 장면을 더욱 현실감 있게 만드는 방법을 학습했습니다. 오늘은 추가 기능을 구현하여 게임을 더욱 발전시키겠습니다. 적 캐릭터의 AI와 간단한 충돌 처리를 추가하겠습니다.
적 캐릭터 AI 구현
적 캐릭터는 플레이어를 추적하고 공격하는 간단한 AI를 가집니다. 이를 위해 적 캐릭터가 플레이어의 위치를 추적하고 일정 거리 안으로 들어오면 공격하는 동작을 구현합니다.
Enemy 클래스 작성
Enemy
클래스를 작성하여 적 캐릭터의 위치와 AI 동작을 관리합니다.
#ifndef ENEMY_H
#define ENEMY_H
#include <glm/glm.hpp>
class Enemy {
public:
glm::vec3 Position;
float Speed;
Enemy(glm::vec3 position, float speed) : Position(position), Speed(speed) {}
void moveTowards(glm::vec3 targetPosition, float deltaTime) {
glm::vec3 direction = glm::normalize(targetPosition - Position);
Position += direction * Speed * deltaTime;
}
bool isWithinAttackRange(glm::vec3 targetPosition, float range) {
return glm::distance(Position, targetPosition) <= range;
}
};
#endif
충돌 처리
플레이어와 적 캐릭터 간의 충돌 처리를 위해 간단한 충돌 감지 기능을 구현합니다.
충돌 감지 함수
bool checkCollision(glm::vec3 pos1, glm::vec3 pos2, float radius) {
return glm::distance(pos1, pos2) < radius;
}
main.cpp 수정
main.cpp
파일을 수정하여 적 캐릭터 AI와 충돌 처리를 추가합니다.
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "Shader.h"
#include "Camera.h"
#include "Enemy.h"
// 정점 셰이더 소스 코드
const char* vertexShaderSource = "path/to/vertex_shader.glsl";
const char* fragmentShaderSource = "path/to/fragment_shader.glsl";
// 카메라 설정
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = 400, lastY = 300;
bool firstMouse = true;
// 시간 설정
float deltaTime = 0.0f;
float lastFrame = 0.0f;
// 적 캐릭터 생성
Enemy enemy(glm::vec3(0.0f, 0.0f, -5.0f), 1.0f);
// 콜백 함수
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);
bool checkCollision(glm::vec3 pos1, glm::vec3 pos2, float radius);
int main() {
// GLFW 초기화
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
return -1;
}
// OpenGL 버전 설정 (3.3)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 창 생성
GLFWwindow* window = glfwCreateWindow(800, 600, "3D Game Project", NULL, NULL);
if (!window) {
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
// 마우스 캡처
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// GLEW 초기화
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialize GLEW" << std::endl;
return -1;
}
// 셰이더 프로그램 생성
Shader ourShader(vertexShaderSource, fragmentShaderSource);
// 정점 데이터
float vertices[] = {
// 위치 // 법선 // 텍스처 좌표
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
};
unsigned int indices[] = {
0, 1, 2, 2, 3, 0, // 앞
4, 5, 6, 6, 7, 4, // 뒤
0, 1, 5, 5, 4, 0, // 위
2, 3, 7, 7, 6, 2, // 아래
1, 2, 6, 6, 5, 1, // 왼쪽
0, 3, 7, 7, 4, 0 // 오른쪽
};
GLuint VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// 텍스처 로딩
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int width, height;
unsigned char* image = SOIL_load_image("path/to/your/texture.png", &width, &height, 0, SOIL_LOAD_RGB);
if (image) {
glTex
Image2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
} else {
std::cerr << "Failed to load texture" << std::endl;
}
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
// OpenGL 상태 설정
glEnable(GL_DEPTH_TEST);
// 조명 설정
glm::vec3 lightDir(0.2f, 1.0f, 0.3f);
glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
// 메인 루프
while (!glfwWindowShouldClose(window)) {
// 시간 계산
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
// 입력 처리
processInput(window);
// 적 캐릭터 이동
enemy.moveTowards(camera.Position, deltaTime);
// 적 캐릭터 공격 범위 확인
if (enemy.isWithinAttackRange(camera.Position, 1.0f)) {
std::cout << "Enemy is attacking!" << std::endl;
}
// 충돌 감지
if (checkCollision(camera.Position, enemy.Position, 0.5f)) {
std::cout << "Collision detected!" << std::endl;
}
// 화면 지우기
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 셰이더 프로그램 사용
ourShader.use();
// 카메라 변환 행렬 설정
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), 800.0f / 600.0f, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
GLint projectionLoc = glGetUniformLocation(ourShader.Program, "projection");
GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
// 모델 변환 행렬 설정
glm::mat4 model = glm::mat4(1.0f);
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
// 조명 설정
glUniform3f(glGetUniformLocation(ourShader.Program, "lightDir"), lightDir.x, lightDir.y, lightDir.z);
glUniform3f(glGetUniformLocation(ourShader.Program, "lightColor"), lightColor.r, lightColor.g, lightColor.b);
glUniform3f(glGetUniformLocation(ourShader.Program, "objectColor"), 1.0f, 0.5f, 0.31f);
// 텍스처 바인딩
glBindTexture(GL_TEXTURE_2D, texture);
// 객체 그리기
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// 적 캐릭터 그리기
model = glm::translate(glm::mat4(1.0f), enemy.Position);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
// 버퍼 교환
glfwSwapBuffers(window);
glfwPollEvents();
}
// 자원 해제
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glfwTerminate();
return 0;
}
// 창 크기 변경 시 호출되는 콜백 함수
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
// 마우스 이동 시 호출되는 콜백 함수
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
if (firstMouse) {
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos;
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
}
// 마우스 휠 사용 시 호출되는 콜백 함수
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
camera.ProcessMouseScroll(yoffset);
}
// 키보드 입력 처리
void processInput(GLFWwindow *window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
}
// 충돌 감지 함수
bool checkCollision(glm::vec3 pos1, glm::vec3 pos2, float radius) {
return glm::distance(pos1, pos2) < radius;
}
결론
오늘은 3D 게임 프로젝트에 적 캐릭터 AI와 충돌 처리를 추가하는 방법을 학습했습니다. 이를 통해 게임 플레이가 더욱 현실감 있고 동적인 경험이 되었습니다. 질문이나 추가적인 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "Day 27: 멀티플레이어 게임 개발 기초"에 대해 학습하겠습니다.
반응형
'-----ETC----- > C++ 게임 개발 시리즈' 카테고리의 다른 글
[C++ 게임 개발 시리즈] Day 28: 네트워크 동기화와 지연 처리 (0) | 2024.08.01 |
---|---|
[C++ 게임 개발 시리즈] Day 25: 3D 게임 프로젝트 시작 (2) (0) | 2024.08.01 |
[C++ 게임 개발 시리즈] Day 23: 3D 모델링과 텍스처링 (0) | 2024.08.01 |
[C++ 게임 개발 시리] Day 24: 3D 게임 프로젝트 시작 (1) (1) | 2024.08.01 |
[C++ 게임 개발 시리즈] Day 21: 적 캐릭터와 NPC의 AI 구현 (0) | 2024.08.01 |