#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; }