133 lines
3.7 KiB
C++
133 lines
3.7 KiB
C++
#include "defaultplayercontroller.h"
|
|
|
|
#include "internal.h"
|
|
#include "internal/physics.h"
|
|
|
|
#include <glm/gtx/vector_angle.hpp>
|
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
|
|
|
namespace kek {
|
|
|
|
static bool castPlayer(glm::vec3 pos, glm::vec3 delta, const btCollisionObject **outBody, float *outFrac, glm::vec3 *outPoint, glm::vec3 *outNormal) {
|
|
btTransform from;
|
|
from.setIdentity();
|
|
from.setOrigin(Physics::fromGLM(pos));
|
|
|
|
btTransform to;
|
|
to.setIdentity();
|
|
to.setOrigin(Physics::fromGLM(pos + delta));
|
|
|
|
ClosestNotSelfConvexResultCallback cb = ClosestNotSelfConvexResultCallback(from.getOrigin(), to.getOrigin(), kekData.player->physics->body);
|
|
cb.m_collisionFilterGroup = -1;
|
|
cb.m_collisionFilterMask = -1;
|
|
kekData.physics->world->convexSweepTest((btConvexShape *) kekData.player->physics->body->getCollisionShape(), from, to, cb);
|
|
if(!cb.m_hitCollisionObject) return false;
|
|
|
|
if(outBody) *outBody = cb.m_hitCollisionObject;
|
|
if(outFrac) *outFrac = cb.m_closestHitFraction;
|
|
if(outPoint) *outPoint = Physics::toGLM(cb.m_hitPointWorld);
|
|
if(outNormal) *outNormal = Physics::toGLM(cb.m_hitNormalWorld);
|
|
return true;
|
|
}
|
|
|
|
bool DefaultPlayerController::checkPlayerGrounded() {
|
|
glm::vec3 groundDir = glm::vec3(0,-groundDistance,0);
|
|
|
|
glm::vec3 point;
|
|
glm::vec3 normal;
|
|
bool onGround = castPlayer(kekData.player->getPosition(), groundDir, nullptr, nullptr, &point, &normal);
|
|
if(!onGround) return false;
|
|
|
|
normal = glm::normalize(normal);
|
|
|
|
float angle = 180.0f - glm::angle(normal, glm::normalize(groundDir)) / M_PI * 180.0f;
|
|
if(angle > maxWalkAngle) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
DefaultPlayerController::DefaultPlayerController() {
|
|
|
|
}
|
|
|
|
DefaultPlayerController::~DefaultPlayerController() {
|
|
|
|
}
|
|
|
|
glm::vec3 DefaultPlayerController::move(glm::vec3 movement) {
|
|
glm::vec3 pos = kekData.player->getPosition();
|
|
glm::vec3 totalMovement = glm::vec3(0);
|
|
|
|
int count = 0;
|
|
while (count < 3) {
|
|
float frac;
|
|
glm::vec3 normal;
|
|
bool collision = castPlayer(pos + totalMovement, movement, nullptr, &frac, nullptr, &normal);
|
|
if(!collision) {
|
|
totalMovement += movement;
|
|
break;
|
|
}
|
|
|
|
normal = glm::normalize(normal);
|
|
|
|
totalMovement += movement * frac;
|
|
|
|
float angle = 180.0f - glm::angle(normal, glm::normalize(movement)) / M_PI * 180.0f;
|
|
if(angle < minSlideAngle) break;
|
|
|
|
totalMovement += normal * 0.001f;
|
|
|
|
glm::vec3 remainingProjected = glm::normalize(glm::cross(normal, glm::cross(movement, normal))) * glm::length(movement) * (1 - frac);
|
|
movement = remainingProjected;
|
|
count++;
|
|
}
|
|
|
|
kekData.player->translate(totalMovement);
|
|
return totalMovement;
|
|
}
|
|
|
|
void DefaultPlayerController::update() {
|
|
bool onGround = checkPlayerGrounded();
|
|
kekData.player->onGround = onGround;
|
|
|
|
if(!onGround) {
|
|
velocity += gravity * kekData.lastFrameTime;
|
|
}else{
|
|
velocity = glm::vec3(0);
|
|
}
|
|
|
|
glm::vec3 direction = glm::vec3(0);
|
|
|
|
if(Input::getKeyState(keyForward) == GLFW_PRESS) {
|
|
direction += kekData.activeCamera->direction;
|
|
}
|
|
|
|
if(Input::getKeyState(keyBackward) == GLFW_PRESS) {
|
|
direction += -kekData.activeCamera->direction;
|
|
}
|
|
|
|
if(Input::getKeyState(keyLeft) == GLFW_PRESS) {
|
|
direction += -glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
|
|
}
|
|
|
|
if(Input::getKeyState(keyRight) == GLFW_PRESS) {
|
|
direction += glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
|
|
}
|
|
|
|
if(Input::getKeyState(keyJump) == GLFW_PRESS && kekData.player->onGround) {
|
|
velocity += glm::vec3(0, jumpVelocity, 0);
|
|
}
|
|
|
|
direction = glm::vec3(direction.x, 0, direction.z);
|
|
|
|
glm::vec3 move = velocity;
|
|
if(glm::length2(direction) > 0) {
|
|
direction = glm::normalize(direction) * walkSpeed;
|
|
move += direction;
|
|
}
|
|
|
|
kekData.player->controller->move(move * (kekData.lastFrameTime));
|
|
}
|
|
|
|
}
|