Diggler/LocalPlayer.cpp
Dorian Wouters 3c0ae6f49e Init commit
2016-01-02 20:00:07 +01:00

255 lines
6.7 KiB
C++

#include "LocalPlayer.hpp"
#include "Game.hpp"
#include <cstdio>
#include <glm/gtx/rotate_vector.hpp>
#include <sstream>
#include "Audio.hpp"
#include "network/NetHelper.hpp"
// I'm shit at player physics, so I kinda copied jMonkey
// https://github.com/jMonkeyEngine/jmonkeyengine/blob/1b0f6d0f59650772bac4588d1733c061ff50d8c8/jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java
namespace Diggler {
static float Acceleration = 24.0f;
static float MvmtDamping = 1/24.0f;
static float Gravity = 18.0f; // -Y acceleration (blocks/sec/sec)
static float JumpForce = Gravity/2.8f;
static float MaxSpeed = 6.f;
static float RoadMaxSpeed = 12.f;
static int i(const float &f) {
if (f >= 0)
return (int)f;
return ((int)f)-1;
}
LocalPlayer::LocalPlayer(Game *G) : Player(G), goingForward(false), goingBackward(false), goingLeft(false), goingRight(false),
hasGravity(true), hasNoclip(false), t(nullptr) {
size = glm::vec3(0.3f, 1.9f, 0.3f);
eyesPos = glm::vec3(0.f, 1.7f, 0.f);
velocity = position = glm::vec3(0.f);
}
void LocalPlayer::special1() {
}
// thx http://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/
inline double fpow(double a, double b) {
union {
double d;
int x[2];
} u = { a };
u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447);
u.x[0] = 0;
return u.d;
}
void LocalPlayer::lookAt(const glm::vec3& at) {
camera.lookAt(at);
G->A->updateAngle();
}
void LocalPlayer::update(const float &delta) {
bool moving = goingForward || goingBackward || goingLeft || goingRight;
glm::vec3 initialVel = velocity;
if (!moving) {
float finalDamp = fpow(MvmtDamping, delta);
velocity.x *= finalDamp;
velocity.z *= finalDamp;
if (!this->hasGravity)
velocity.y *= finalDamp;
}
// Apply player's will movement
glm::vec3 normMove = glm::normalize(glm::vec3(camera.m_lookAt.x, camera.m_lookAt.y * !hasGravity, camera.m_lookAt.z));
float acceleration = Acceleration*delta;
if (goingForward) {
velocity += acceleration * normMove;
}
if (goingBackward) {
velocity -= acceleration * normMove;
}
if (goingLeft) {
velocity += acceleration * glm::rotateY(glm::normalize(glm::vec3(normMove.x, 0, normMove.z)), (float)M_PI/2);
}
if (goingRight) {
velocity -= acceleration * glm::rotateY(glm::normalize(glm::vec3(normMove.x, 0, normMove.z)), (float)M_PI/2);
}
// Apply gravity
if (hasGravity) {
if (onGround) {
BlockType b = G->SC->get(position.x, position.y-1, position.z);
onRoad = (b == BlockType::Road);
onGround = !Blocks::canGoThrough(b, team);
}
if (!onGround)
velocity.y -= Gravity * delta;
}
if (!hasNoclip) {
glm::vec3 velXZ(velocity.x, 0, velocity.z);
int maxSpeed = (onRoad ? RoadMaxSpeed : MaxSpeed);
if (glm::length(velXZ) > maxSpeed) {
velXZ = glm::normalize(velXZ);
velocity.x = velXZ.x * maxSpeed;
velocity.z = velXZ.z * maxSpeed;
}
}
if (velocity.x > -0.001f && velocity.x < 0.001f) velocity.x = 0.f;
if (velocity.y > -0.001f && velocity.y < 0.001f) velocity.y = 0.f;
if (velocity.z > -0.001f && velocity.z < 0.001f) velocity.z = 0.f;
glm::vec3 destPos = position + velocity * delta;
accel = velocity - initialVel;
if (velocity != glm::vec3(0.f)) { // avoids useless calculus
if (hasNoclip) {
position = destPos;
} else {
float x = destPos.x, y = destPos.y, z = destPos.z;
BlockType bTop = G->SC->get(x, y+size.y, z),
bBottom = G->SC->get(x, y, z);
if (velocity.y > 0.f)
if (!Blocks::canGoThrough(bTop, team)) {
velocity.y = 0.f;
position.y = (int)(position.y+size.y+1)-size.y;
}
if (velocity.y < 0.f)
if (!Blocks::canGoThrough(bBottom, team)) {
velocity.y = 0.f;
y = position.y = (int)(position.y);
onGround = 1;
}
bTop = G->SC->get(x, y+size.y, z);
bBottom = G->SC->get(x, y-onGround, z);
BlockType bNTop = G->SC->get(x+size.x, y+size.y, z),
bNBottom = G->SC->get(x+size.x, y, z),
bSTop = G->SC->get(x-size.x, y+size.y, z),
bSBottom = G->SC->get(x-size.x, y, z),
bETop = G->SC->get(x, y+size.y, z+size.z),
bEBottom = G->SC->get(x, y, z+size.z),
bWTop = G->SC->get(x, y+size.y, z-size.z),
bWBottom = G->SC->get(x, y, z-size.z);
if (velocity.x > 0.f)
if (!Blocks::canGoThrough(bNTop, team) || !Blocks::canGoThrough(bNBottom, team)) {
if (bNTop == BlockType::Lava || bNBottom == BlockType::Lava) {
kill(DeathReason::Lava);
return;
}
velocity.x = 0.f;
}
if (velocity.x < 0.f)
if (!Blocks::canGoThrough(bSTop, team) || !Blocks::canGoThrough(bSBottom, team)) {
if (bSTop == BlockType::Lava || bSBottom == BlockType::Lava) {
kill(DeathReason::Lava);
return;
}
velocity.x = 0.f;
}
if (velocity.z > 0.f)
if (!Blocks::canGoThrough(bETop, team) || !Blocks::canGoThrough(bEBottom, team)) {
if (bETop == BlockType::Lava || bEBottom == BlockType::Lava) {
kill(DeathReason::Lava);
return;
}
velocity.z = 0.f;
}
if (velocity.z < 0.f)
if (!Blocks::canGoThrough(bWTop, team) || !Blocks::canGoThrough(bWBottom, team)) {
if (bWTop == BlockType::Lava || bWBottom == BlockType::Lava) {
kill(DeathReason::Lava);
return;
}
velocity.z = 0.f;
}
switch (bTop) {
case BlockType::Lava:
kill(DeathReason::Lava);
return;
case BlockType::Shock:
kill(DeathReason::Shock);
return;
default:
break;
}
switch (bBottom) {
case BlockType::Jump:
if (G->Time - lastJumpTime > 0.2) {
velocity.y = JumpForce * 2;
NetHelper::SendEvent(G, Net::EventType::PlayerJumpOnPad);
lastJumpTime = G->Time;
}
break;
case BlockType::Lava:
kill(DeathReason::Lava);
return;
default:
break;
}
position += velocity * delta;
}
camera.setPosition(position + eyesPos);
if (t != nullptr) {
std::ostringstream oss;
oss << G->LP->position.y << std::endl << i(G->LP->position.y) << std::endl <<
G->LP->velocity.x << " " << G->LP->velocity.y << " " << G->LP->velocity.z;
t->setText(oss.str());
}
G->A->updatePos();
}
}
void LocalPlayer::forceCameraUpdate() {
camera.setPosition(position + eyesPos);
}
void LocalPlayer::kill(Player::DeathReason dr) {
getDebugStream() << "Pretend you're dead" << std::endl;
}
void LocalPlayer::goForward(bool enable) {
goingForward = enable;
}
void LocalPlayer::goBackward(bool enable) {
goingBackward = enable;
}
void LocalPlayer::goLeft(bool enable) {
goingLeft = enable;
}
void LocalPlayer::goRight(bool enable) {
goingRight = enable;
}
void LocalPlayer::setHasGravity(bool fall) {
hasGravity = fall;
onGround = false;
}
void LocalPlayer::setHasNoclip(bool fly) {
hasNoclip = fly;
setHasGravity(!fly);
}
void LocalPlayer::jump() {
if (!onGround)
return;
onGround = false;
velocity.y += JumpForce;
}
}