Files
ghostland-game/player.cpp
2025-08-03 11:15:54 -04:00

328 lines
7.8 KiB
C++

#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "player.h"
Player::Player(glm::vec3 startpos, float startyaw) {
position = startpos;
yaw = startyaw;
pitch = 0.0f;
first_mouse = false;
first_frame = false;
light_xpersist = 0.0f;
light_ypersist = 0.0f;
armlength = 0.5f;
camera_offset = glm::vec3(0.0f, 2.5f, 0.0f);
camera_up = glm::vec3(0.0f, 1.0f, 0.0f);
fov = 60.0f;
velocity = glm::vec3(0.0f, 0.0f, 0.0f);
}
glm::vec3 Player::get_pos() const {
return position;
}
glm::vec3 Player::get_camera_front() const {
return camera_front;
}
glm::vec3 Player::get_camera_up() const {
return camera_up;
}
glm::vec3 Player::get_camera_pos() const {
return position + camera_offset;
}
glm::vec3 Player::get_light_pos() const {
return get_camera_pos() + get_light_front() * armlength;
}
glm::vec3 Player::get_light_front() const {
float yawp = yaw + light_xpersist;
float pitchp = pitch + light_ypersist;
glm::vec3 front;
front.x = cos(glm::radians(yawp)) * cos(glm::radians(pitchp));
front.y = sin(glm::radians(pitchp));
front.z = sin(glm::radians(yawp)) * cos(glm::radians(pitchp));
return normalize(front);
}
float Player::get_yaw() {
return yaw;
}
float Player::get_pitch() {
return pitch;
}
float Player::get_fov() {
return fov;
}
void Player::mouse_callback(GLFWwindow* window, double xposI, double yposI) {
float xpos = static_cast<float>(xposI);
float ypos = static_cast<float>(yposI);
if (first_mouse) {
prevx = xpos;
prevy = ypos;
first_mouse = false;
}
float xoffset = xpos - prevx;
float yoffset = prevy - ypos;
prevx = xpos;
prevy = ypos;
float sensitivity = 0.1f;
xoffset *= sensitivity;
yoffset *= sensitivity;
float prev_yaw = yaw;
yaw += xoffset;
pitch += yoffset;
if (pitch > 89.0f) {
pitch = 89.0f;
}
if (pitch < -89.0f) {
pitch = -89.0f;
}
mouse_xoffset = xoffset;
mouse_yoffset = yoffset;
}
void Player::process_input(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
bool W, A, S, D, space;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
W = true;
} else {
W = false;
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
S = true;
} else {
S = false;
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
A = true;
} else {
A = false;
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
D = true;
} else {
D = false;
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
space = true;
} else {
space = false;
}
if (!is_in_air()) {
glm::vec3 relvel;
if (space) {
velocity.y = jumpvelocity;
return;
} else {
velocity.y = 0.0;
}
// intentionally don't update velocity if contradictory keys are pressed
if (!W && !S) {
relvel.z = 0.0;
} else if (W) {
relvel.z = 1.0;
} else if (S) {
relvel.z = -1.0;
}
if (!A && !D) {
relvel.x = 0.0;
} else if (A) {
relvel.x = -1.0;
} else if (D) {
relvel.x = 1.0;
}
if (relvel.x == 0.0 && relvel.z == 0.0) {
velocity.x = 0.0;
velocity.z = 0.0;
return;
}
relvel = glm::normalize(relvel);
relvel *= hvelocity;
float yawr = glm::radians(yaw);
velocity.z = relvel.x * cos(yawr) + relvel.z * sin(yawr);
velocity.x = -relvel.x * sin(yawr) + relvel.z * cos(yawr);
}
}
bool Player::is_in_air() {
return position.y > 0.0;
}
void Player::set_light_offset(float xoffset, float yoffset) {
xoffset *= light_movement_multiplier;
yoffset *= light_movement_multiplier;
light_xpersist = light_xpersist * light_persist_factor + xoffset * light_offset_factor;
if (light_xpersist > lightoffsetmax) {
light_xpersist = lightoffsetmax;
} else if (light_xpersist < -lightoffsetmax) {
light_xpersist = -lightoffsetmax;
}
light_ypersist = light_ypersist * light_persist_factor + yoffset * light_offset_factor;
if (light_ypersist > lightoffsetmax) {
light_ypersist = lightoffsetmax;
} else if (light_ypersist < -lightoffsetmax) {
light_ypersist = -lightoffsetmax;
}
}
void Player::apply_movement(float timed) {
// mouse movement
glm::vec3 front;
front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
front.y = sin(glm::radians(pitch));
front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
camera_front = normalize(front);
// light movement;
set_light_offset(mouse_xoffset, mouse_yoffset);
mouse_xoffset = 0.0;
mouse_yoffset = 0.0;
// positional movement
glm::vec3 movement = velocity;
movement *= timed;
glm::vec3 intersected = check_intersection(movement);
if (is_in_air()) {
if (intersected.x == 0.0) {
velocity.x = 0.0;
}
if (intersected.z == 0.0) {
velocity.z = 0.0;
}
} else { // not in air
if (intersected.x != movement.x) {
intersected.x = -movement.x;
}
if (intersected.z != movement.z) {
intersected.z = -movement.z;
}
}
position.y += intersected.y;
if (position.y <= 0.0f) {
position.y = 0.0f;
velocity.y = 0.0f;
} else {
velocity.y += timed * vacceleration;
}
position.x += intersected.x;
position.z += intersected.z;
}
void Player::reset_position(glm::vec3 startpos, float startyaw) {
position = startpos;
yaw = startyaw;
velocity = glm::vec3(0.0f, 0.0f, 0.0f);
}
glm::vec3 Player::get_normal_from_index(int ix) {
return glm::vec3(
wall_vertices[ix * 6 * 6 + 3],
wall_vertices[ix * 6 * 6 + 4],
wall_vertices[ix * 6 * 6 + 5]
);
}
glm::vec3 Player::get_vec3_from_indices(int ix, int jx) {
return glm::vec3(
wall_vertices[ix * 6 * 6 + jx * 6],
wall_vertices[ix * 6 * 6 + jx * 6 + 1],
wall_vertices[ix * 6 * 6 + jx * 6 + 2]
);
}
glm::vec3 Player::check_intersection(glm::vec3 movement) {
glm::vec3 vec_start, vec_stop, p1, p2, p3, res;
bool gotX = false, gotZ = false;
vec_start = get_camera_pos();
vec_stop = vec_start + movement * 20.0f;
res.x = movement.x;
res.y = movement.y;
res.z = movement.z;
for (int ix = 0; ix < num_walls; ix++) {
if (gotX && gotZ) {
break;
}
glm::vec3 norm = get_normal_from_index(ix);
if (!gotX) {
if ((movement.x > 0 && norm.x < 0) || (movement.x < 0 && norm.x > 0)) {
p1 = get_vec3_from_indices(ix, 1);
p2 = get_vec3_from_indices(ix, 0);
p3 = get_vec3_from_indices(ix, 2);
if (get_intersection(vec_start, vec_stop, p1, p2, p3)) {
gotX = true;
res.x = 0.0;
}
}
}
if (!gotZ) {
if ((movement.z > 0 && norm.z < 0) || (movement.z < 0 && norm.z > 0)) {
p1 = get_vec3_from_indices(ix, 1);
p2 = get_vec3_from_indices(ix, 0);
p3 = get_vec3_from_indices(ix, 2);
if (get_intersection(vec_start, vec_stop, p1, p2, p3)) {
gotZ = true;
res.z = 0.0;
}
}
}
}
return res;
}
void Player::scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
fov -= (float)yoffset;
if (fov < 1.0f) {
fov = 1.0f;
}
if (fov > 90.0f) {
fov = 90.0f;
}
}