engine/test/src/camera_controller.cpp

176 lines
5.0 KiB
C++
Raw Normal View History

2022-11-07 20:15:26 +00:00
#include "camera_controller.hpp"
2023-01-05 13:21:33 +00:00
#include "application.hpp"
2022-11-07 20:15:26 +00:00
#include "window.hpp"
2023-01-05 13:21:33 +00:00
#include "input_manager.hpp"
#include "scene.hpp"
#include "components/transform.hpp"
2023-01-22 18:20:10 +00:00
#include "components/collider.hpp"
2022-11-07 20:15:26 +00:00
#include <glm/trigonometric.hpp>
#include <glm/gtc/constants.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <log.hpp>
2023-01-05 13:21:33 +00:00
CameraControllerSystem::CameraControllerSystem(engine::Scene* scene)
: System(scene, { typeid(engine::TransformComponent).hash_code(), typeid(CameraControllerComponent).hash_code() })
2022-11-07 20:15:26 +00:00
{
}
2023-01-05 13:21:33 +00:00
void CameraControllerSystem::onUpdate(float ts)
2022-11-07 20:15:26 +00:00
{
2023-01-05 13:21:33 +00:00
engine::TransformComponent* t = nullptr;
2023-01-22 18:20:10 +00:00
engine::ColliderComponent* col = nullptr;
2023-01-05 13:21:33 +00:00
CameraControllerComponent* c = nullptr;
for (uint32_t entity : m_entities) {
t = m_scene->getComponent<engine::TransformComponent>(entity);
2023-01-22 18:20:10 +00:00
col = m_scene->getComponent<engine::ColliderComponent>(entity);
2023-01-05 13:21:33 +00:00
c = m_scene->getComponent<CameraControllerComponent>(entity);
break;
}
if (t == nullptr) return;
if (c == nullptr) return;
2023-01-22 18:20:10 +00:00
if (col == nullptr) return;
2023-01-05 13:21:33 +00:00
2022-11-07 20:15:26 +00:00
// calculate new position
// use one unit per meter
2023-01-05 13:21:33 +00:00
const float dt = ts;
2022-11-07 20:15:26 +00:00
2023-02-02 17:32:19 +00:00
/*
2022-11-07 20:15:26 +00:00
constexpr float G = 9.8f;
// constexpr float MAX_SLOPE_ANGLE = glm::radians(20.0f);
constexpr float MAX_SLOPE_ANGLE = glm::radians(1000.0f); // treat every collider as a floor, (TODO: get wall collisions working so this can be removed)
constexpr float FLOOR_SINK_LEVEL = 0.05f; // how far into the floor to ground the player
2022-11-07 20:15:26 +00:00
2023-01-26 23:52:25 +00:00
glm::vec3 norm = col->getLastCollisionNormal();
2022-11-07 20:15:26 +00:00
2023-01-26 23:52:25 +00:00
norm.y = 0.0f;
glm::vec3 dir = glm::normalize(glm::rotateY(glm::vec3{ 1.0f, 0.0f, 0.0f }, c->m_yaw) + glm::rotateY(glm::vec3{ 0.0f, 0.0f, 1.0f }, c->m_yaw));
const float slope = glm::length(glm::half_pi<float>() - glm::acos(glm::dot(dir, norm)));
2023-01-26 23:52:25 +00:00
bool isSliding = false;
if (col->getIsColliding()) {
if (slope > MAX_SLOPE_ANGLE) {
2023-01-26 23:52:25 +00:00
// slide across wall
isSliding = true;
} else {
if (c->dy < 0.0f && c->isGrounded == false) {
// in the ground, push up a bit
float floorY = col->getLastCollisionPoint().y;
t->position.y = floorY + col->colliders.sphereCollider.r - FLOOR_SINK_LEVEL;
c->dy = 0.0f;
c->isGrounded = true;
}
2023-01-22 18:20:10 +00:00
}
2022-11-07 20:15:26 +00:00
}
if (col->getJustUncollided() && slope <= MAX_SLOPE_ANGLE) {
// just stopped colliding with a floor collider
c->isGrounded = false;
}
if (c->isGrounded == false)
c->dy -= G * dt;
2023-01-26 23:52:25 +00:00
// jumping
constexpr float JUMPVEL = (float)2.82231110971133017648; //std::sqrt(2 * G * JUMPHEIGHT);
if (m_scene->app()->inputManager()->getButton("jump") && c->isGrounded == true) {
c->dy = JUMPVEL;
2023-01-22 18:20:10 +00:00
}
2022-11-07 20:15:26 +00:00
2023-01-05 13:21:33 +00:00
if (m_scene->app()->window()->getButton(engine::inputs::MouseButton::M_LEFT)) {
c->dy += dt * c->thrust;
2022-11-07 20:15:26 +00:00
}
2023-02-02 17:32:19 +00:00
*/
2022-11-07 20:15:26 +00:00
// in metres per second
2023-01-05 13:21:33 +00:00
float SPEED = c->walk_speed;
if (m_scene->app()->inputManager()->getButton("sprint")) SPEED *= 10.0f;
2022-11-07 20:15:26 +00:00
2023-02-02 17:32:19 +00:00
if (m_scene->app()->inputManager()->getButton("fire")) t->position.y += dt * SPEED;
if (m_scene->app()->inputManager()->getButton("aim")) t->position.y -= dt * SPEED;
2023-01-26 23:52:25 +00:00
float dx = m_scene->app()->inputManager()->getAxis("movex");
float dz = (-m_scene->app()->inputManager()->getAxis("movey"));
2022-11-07 20:15:26 +00:00
// calculate new pitch and yaw
constexpr float MAX_PITCH = glm::half_pi<float>();
constexpr float MIN_PITCH = -MAX_PITCH;
2023-01-05 13:21:33 +00:00
float dPitch = m_scene->app()->inputManager()->getAxis("looky") * -1.0f * c->m_cameraSensitivity;
c->m_pitch += dPitch;
if (c->m_pitch <= MIN_PITCH || c->m_pitch >= MAX_PITCH) {
c->m_pitch -= dPitch;
2022-11-07 20:15:26 +00:00
}
2023-01-05 13:21:33 +00:00
c->m_yaw += m_scene->app()->inputManager()->getAxis("lookx") * -1.0f * c->m_cameraSensitivity;
2022-11-07 20:15:26 +00:00
// update position relative to camera direction in xz plane
2023-01-05 13:21:33 +00:00
const glm::vec3 d2xRotated = glm::rotateY(glm::vec3{ dx, 0.0f, 0.0f }, c->m_yaw);
const glm::vec3 d2zRotated = glm::rotateY(glm::vec3{ 0.0f, 0.0f, dz }, c->m_yaw);
2023-01-26 23:52:25 +00:00
glm::vec3 hVel = (d2xRotated + d2zRotated);
2023-02-02 17:32:19 +00:00
/* if (isSliding) {
hVel = glm::vec3{norm.z, 0.0f, -norm.x};
2023-01-26 23:52:25 +00:00
}
2023-02-02 17:32:19 +00:00
*/
2023-01-26 23:52:25 +00:00
hVel *= SPEED;
t->position += hVel * dt;
2023-01-05 13:21:33 +00:00
t->position.y += c->dy * dt;
2022-11-07 20:15:26 +00:00
2022-11-23 15:40:10 +00:00
constexpr float MAX_DISTANCE_FROM_ORIGIN = 1000.0f;
2023-01-05 13:21:33 +00:00
if (glm::length(t->position) > MAX_DISTANCE_FROM_ORIGIN) {
2023-01-22 18:20:10 +00:00
t->position = { 0.0f, 5.0f, 0.0f };
2023-01-05 13:21:33 +00:00
c->dy = 0.0f;
2022-11-23 15:40:10 +00:00
}
/* ROTATION STUFF */
2022-11-07 20:15:26 +00:00
// pitch quaternion
2023-01-05 13:21:33 +00:00
const float halfPitch = c->m_pitch / 2.0f;
2022-11-07 20:15:26 +00:00
glm::quat pitchQuat{};
pitchQuat.x = glm::sin(halfPitch);
pitchQuat.y = 0.0f;
pitchQuat.z = 0.0f;
pitchQuat.w = glm::cos(halfPitch);
// yaw quaternion
2023-01-05 13:21:33 +00:00
const float halfYaw = c->m_yaw / 2.0f;
2022-11-07 20:15:26 +00:00
glm::quat yawQuat{};
yawQuat.x = 0.0f;
yawQuat.y = glm::sin(halfYaw);
yawQuat.z = 0.0f;
yawQuat.w = glm::cos(halfYaw);
// update rotation
2023-01-05 13:21:33 +00:00
t->rotation = yawQuat * pitchQuat;
2022-11-07 20:15:26 +00:00
2023-01-05 13:21:33 +00:00
/* user interface inputs */
if (m_scene->app()->window()->getKeyPress(engine::inputs::Key::K_P)) {
2022-11-07 20:15:26 +00:00
std::string pos_string{
2023-01-05 13:21:33 +00:00
"x: " + std::to_string(t->position.x) +
" y: " + std::to_string(t->position.y) +
" z: " + std::to_string(t->position.z)
2022-11-07 20:15:26 +00:00
};
2023-02-02 17:32:19 +00:00
m_scene->app()->window()->infoBox("POSITION", pos_string);
2022-11-07 20:15:26 +00:00
INFO("position: " + pos_string);
}
2023-01-05 13:21:33 +00:00
if (m_scene->app()->inputManager()->getButtonPress("fullscreen")) {
m_scene->app()->window()->toggleFullscreen();
}
2022-11-07 20:15:26 +00:00
}