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"
2023-03-21 11:03:20 +00:00
# include "scene_manager.hpp"
2023-01-05 13:21:33 +00:00
# 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-04-29 14:22:25 +00:00
void CameraControllerSystem : : OnUpdate ( float ts )
2022-11-07 20:15:26 +00:00
{
2023-02-09 20:44:37 +00:00
if ( t = = nullptr | | c = = nullptr | | col = = nullptr ) {
2023-04-29 14:22:25 +00:00
for ( uint32_t entity : entities_ ) {
t = scene_ - > GetComponent < engine : : TransformComponent > ( entity ) ;
col = scene_ - > GetComponent < engine : : ColliderComponent > ( entity ) ;
c = scene_ - > GetComponent < CameraControllerComponent > ( entity ) ;
2023-02-09 20:44:37 +00:00
break ;
}
if ( t = = nullptr ) return ;
if ( c = = nullptr ) return ;
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
constexpr float G = 9.8f ;
2023-02-13 11:27:18 +00:00
const float MAX_SLOPE_ANGLE = glm : : cos ( 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)
2023-01-28 00:24:04 +00:00
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-02-12 14:50:29 +00:00
glm : : vec3 norm = c - > lastCollisionNormal ;
2022-11-07 20:15:26 +00:00
2023-01-26 23:52:25 +00:00
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 ) ) ;
2023-02-13 11:27:18 +00:00
const float slope = glm : : dot ( dir , norm ) ;
2023-01-26 23:52:25 +00:00
bool isSliding = false ;
2023-02-12 14:50:29 +00:00
if ( c - > justCollided ) {
2023-01-28 00:24:04 +00:00
if ( slope > MAX_SLOPE_ANGLE ) {
2023-01-26 23:52:25 +00:00
// slide across wall
isSliding = true ;
2023-01-28 00:24:04 +00:00
} else {
if ( c - > dy < 0.0f & & c - > isGrounded = = false ) {
// in the ground, push up a bit
2023-02-12 14:50:29 +00:00
float floorY = c - > lastCollisionPoint . y ;
t - > position . y = floorY + 1.5f - FLOOR_SINK_LEVEL ;
2023-01-28 00:24:04 +00:00
c - > dy = 0.0f ;
c - > isGrounded = true ;
}
2023-01-22 18:20:10 +00:00
}
2022-11-07 20:15:26 +00:00
}
2023-01-28 00:24:04 +00:00
2023-02-12 14:50:29 +00:00
if ( c - > justCollided = = false & & slope < = MAX_SLOPE_ANGLE ) {
2023-01-28 00:24:04 +00:00
// 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);
2023-04-29 14:22:25 +00:00
if ( scene_ - > app ( ) - > input_manager ( ) - > GetButton ( " jump " ) & & c - > isGrounded = = true ) {
2023-01-28 00:24:04 +00:00
c - > dy = JUMPVEL ;
2023-01-22 18:20:10 +00:00
}
2022-11-07 20:15:26 +00:00
2023-04-29 14:22:25 +00:00
if ( scene_ - > app ( ) - > window ( ) - > getButton ( engine : : inputs : : MouseButton : : M_LEFT ) ) {
2023-01-05 13:21:33 +00:00
c - > dy + = dt * c - > thrust ;
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 ;
2023-04-29 14:22:25 +00:00
if ( scene_ - > app ( ) - > input_manager ( ) - > GetButton ( " sprint " ) ) SPEED * = 10.0f ;
2022-11-07 20:15:26 +00:00
2023-04-29 14:22:25 +00:00
float dx = scene_ - > app ( ) - > input_manager ( ) - > GetAxis ( " movex " ) ;
float dz = ( - scene_ - > app ( ) - > input_manager ( ) - > 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-04-29 14:22:25 +00:00
float dPitch = scene_ - > app ( ) - > input_manager ( ) - > GetAxis ( " looky " ) * - 1.0f * c - > m_cameraSensitivity ;
2023-01-05 13:21:33 +00:00
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-04-29 14:22:25 +00:00
c - > m_yaw + = scene_ - > app ( ) - > input_manager ( ) - > 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-12 14:50:29 +00:00
if ( isSliding ) {
2023-01-28 00:24:04 +00:00
hVel = glm : : vec3 { norm . z , 0.0f , - norm . x } ;
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
2023-02-19 13:55:08 +00:00
constexpr float MAX_DISTANCE_FROM_ORIGIN = 10000.0f ;
2022-11-23 15:40:10 +00:00
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 */
2023-04-29 14:22:25 +00:00
if ( 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-04-29 14:22:25 +00:00
//scene_->app()->window()->infoBox("POSITION", pos_string);
2023-03-12 16:14:55 +00:00
LOG_INFO ( " position: " + pos_string ) ;
2022-11-07 20:15:26 +00:00
}
2023-04-29 14:22:25 +00:00
if ( scene_ - > app ( ) - > window ( ) - > getKeyPress ( engine : : inputs : : Key : : K_R ) ) {
2023-03-21 11:03:20 +00:00
t - > position = { 0.0f , 5.0f , 0.0f } ;
c - > dy = 0.0f ;
}
2023-04-29 14:22:25 +00:00
if ( scene_ - > app ( ) - > input_manager ( ) - > GetButtonPress ( " fullscreen " ) ) {
scene_ - > app ( ) - > window ( ) - > toggleFullscreen ( ) ;
2023-01-05 13:21:33 +00:00
}
2023-04-29 14:22:25 +00:00
if ( scene_ - > app ( ) - > input_manager ( ) - > GetButtonPress ( " exit " ) ) {
scene_ - > app ( ) - > window ( ) - > setCloseFlag ( ) ;
2023-03-15 01:49:03 +00:00
}
2023-02-12 14:50:29 +00:00
c - > justCollided = false ;
2022-11-07 20:15:26 +00:00
}
2023-02-09 15:21:37 +00:00
2023-02-09 15:29:19 +00:00
// called once per frame
2023-04-29 14:22:25 +00:00
void CameraControllerSystem : : OnEvent ( engine : : PhysicsSystem : : CollisionEvent info )
2023-02-09 15:21:37 +00:00
{
2023-02-12 14:50:29 +00:00
c - > justCollided = info . isCollisionEnter ;
c - > lastCollisionNormal = info . normal ;
c - > lastCollisionPoint = info . point ;
2023-02-09 15:21:37 +00:00
}