ICT290 / src / scene / entities / player.cpp
player.cpp
Raw
#include "player.h"

#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

void Player::update(Object& playerObject,
                    Camera_& topDownCamera,
                    const float deltaTime) {
    size_t dirCount = 0;

    // save old rotation
    auto lastRotation = playerObject.rotation;
    // reset player rotation
    playerObject.rotation = glm::vec3{0, 0, 0};

    if (currentDirection.up) {
        auto direction = glm::normalize(topDownCamera.front)
                         * glm::vec3{1, 0, 1};
        playerObject.location += direction * speed
                                 * deltaTime;  // TODO: reduce coupling between
                                               // camera and player
        playerObject.rotation += glm::vec3{0,
                                           glm::degrees(
                                               atan2(direction.z, direction.x))
                                               + 90,
                                           0};
        ++dirCount;
    }
    if (currentDirection.left) {
        auto direction = glm::normalize(
                             glm::cross(topDownCamera.front, topDownCamera.up))
                         * glm::vec3{1, 0, 1};
        playerObject.location -= direction * speed * deltaTime;
        playerObject.rotation += glm::vec3{0,
                                           glm::degrees(
                                               atan2(direction.z, direction.x))
                                               + 90,
                                           0};
        ++dirCount;
    }
    if (currentDirection.down) {
        auto direction = glm::normalize(topDownCamera.front)
                         * glm::vec3{1, 0, 1};
        playerObject.location -= direction * speed * deltaTime;
        playerObject.rotation += glm::vec3{0,
                                           glm::degrees(
                                               atan2(direction.z, direction.x))
                                               - 90,
                                           0};
        ++dirCount;
    }
    if (currentDirection.right) {
        auto direction = glm::normalize(
                             glm::cross(topDownCamera.front, topDownCamera.up))
                         * glm::vec3{1, 0, 1};
        playerObject.location += direction * speed * deltaTime;
        playerObject.rotation += glm::vec3{0,
                                           glm::degrees(
                                               atan2(direction.z, direction.x))
                                               - 90,
                                           0};
        ++dirCount;
    }
    if (currentDirection.down
        && currentDirection.left) {  // TODO: trig cruft, shouldnt be needed
        playerObject.rotation.y += 315;
    }

    // average the rotation applied
    if (dirCount > 1) {
        playerObject.rotation /= dirCount;
    } else if (dirCount == 0) {
        playerObject.rotation = lastRotation;
    }

    topDownCamera.direction.x = glm::sin(glm::radians(topDownCamera.yaw))
                                * glm::cos(glm::radians(topDownCamera.pitch));
    topDownCamera.direction.y = -glm::sin(glm::radians(topDownCamera.pitch));
    topDownCamera.direction.z = -glm::cos(glm::radians(topDownCamera.yaw))
                                * glm::cos(glm::radians(topDownCamera.pitch));
    topDownCamera.front = glm::normalize(topDownCamera.direction);

    // Smooth zoom towards target over multiple frames
    if (glm::abs(zoom - targetZoom) > 0.1f) {
        const float zoomSpeed{5.f};
        zoom += (targetZoom < zoom) ? -zoomSpeed * deltaTime
                                    : zoomSpeed * deltaTime;
    }
    // Calculate new camera position relative to zoom and player
    glm::vec3 cameraZoom{zoom * topDownCamera.front};
    topDownCamera.position = glm::vec3{playerObject.location.x,
                                       1,
                                       playerObject.location.z}
                             - cameraZoom;

    topDownCamera.viewMatrix = glm::lookAt(topDownCamera.position,
                                           topDownCamera.position
                                               + topDownCamera.front,
                                           topDownCamera.up);

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(glm::value_ptr(topDownCamera.viewMatrix));

    // post-update steps
    currentDirection.up = false;
    currentDirection.down = false;
    currentDirection.left = false;
    currentDirection.right = false;
}

void Player::moveUp() {
    currentDirection.up = true;
}

void Player::moveDown() {
    currentDirection.down = true;
}

void Player::moveLeft() {
    currentDirection.left = true;
}

void Player::moveRight() {
    currentDirection.right = true;
}

void Player::setMoveSpeed(float incMoveSpeed) {
    if (incMoveSpeed >= 0) {
        speed = incMoveSpeed;
    } else {
        throw std::invalid_argument("Can't have negative speed");
    }
}

float Player::getMoveSpeed() const {
    return speed;
}

void Player::setZoom(float newZoom) {
    if (newZoom > 1 && newZoom < 10) {
        targetZoom = newZoom;
    }
}

float Player::getZoom() const {
    return zoom;
}