diff --git a/CMakeLists.txt b/CMakeLists.txt index 11813fd0..bc082274 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ set(HEADERS src/game/object/waypoint.h src/game/pathfinding.h src/game/paths.h + src/game/player.h src/game/room.h src/game/script/routines.h src/game/script/util.h @@ -225,6 +226,7 @@ set(SOURCES src/game/object/waypoint.cpp src/game/pathfinding.cpp src/game/paths.cpp + src/game/player.cpp src/game/room.cpp src/game/script/routines.cpp src/game/script/routines_common.cpp diff --git a/src/game/camera/camera.h b/src/game/camera/camera.h index 1ccf9500..25b17ddb 100644 --- a/src/game/camera/camera.h +++ b/src/game/camera/camera.h @@ -33,7 +33,8 @@ class Camera { public: virtual bool handle(const SDL_Event &event) = 0; virtual void update(float dt) = 0; - virtual void clearUserInput() = 0; + + virtual void stopMovement() = 0; float heading() const; std::shared_ptr sceneNode() const; diff --git a/src/game/camera/firstperson.cpp b/src/game/camera/firstperson.cpp index 60c93c6b..5ffbe942 100644 --- a/src/game/camera/firstperson.cpp +++ b/src/game/camera/firstperson.cpp @@ -152,7 +152,7 @@ void FirstPersonCamera::update(float dt) { } } -void FirstPersonCamera::clearUserInput() { +void FirstPersonCamera::stopMovement() { _moveForward = false; _moveLeft = false; _moveBackward = false; diff --git a/src/game/camera/firstperson.h b/src/game/camera/firstperson.h index 97dded7d..8763d1bb 100644 --- a/src/game/camera/firstperson.h +++ b/src/game/camera/firstperson.h @@ -29,7 +29,7 @@ public: bool handle(const SDL_Event &event) override; void update(float dt) override; - void clearUserInput() override; + void stopMovement() override; void setPosition(const glm::vec3 &position); void setHeading(float heading); diff --git a/src/game/camera/thirdperson.cpp b/src/game/camera/thirdperson.cpp index d0215140..6d12492a 100644 --- a/src/game/camera/thirdperson.cpp +++ b/src/game/camera/thirdperson.cpp @@ -121,7 +121,7 @@ void ThirdPersonCamera::updateSceneNode() { _sceneNode->setLocalTransform(transform); } -void ThirdPersonCamera::clearUserInput() { +void ThirdPersonCamera::stopMovement() { _rotateCCW = false; _rotateCW = false; } diff --git a/src/game/camera/thirdperson.h b/src/game/camera/thirdperson.h index acdda41f..af1e98f6 100644 --- a/src/game/camera/thirdperson.h +++ b/src/game/camera/thirdperson.h @@ -33,7 +33,7 @@ public: bool handle(const SDL_Event &event) override; void update(float dt) override; - void clearUserInput() override; + void stopMovement() override; void setTargetPosition(const glm::vec3 &position); void setHeading(float heading); diff --git a/src/game/module.cpp b/src/game/module.cpp index 69702990..8ac9cabb 100644 --- a/src/game/module.cpp +++ b/src/game/module.cpp @@ -57,6 +57,7 @@ void Module::load(const string &name, const GffStruct &ifo) { loadInfo(ifo); loadArea(ifo); loadCameras(); + loadPlayer(); _loaded = true; } @@ -127,6 +128,10 @@ void Module::loadCameras() { } } +void Module::loadPlayer() { + _player = make_unique(this, _area.get(), _thirdPersonCamera.get()); +} + bool Module::findObstacle(const glm::vec3 &from, const glm::vec3 &to, glm::vec3 &intersection) const { SpatialObject *obstacle = nullptr; if (_area->findObstacleByWalkmesh(from, to, kObstacleRoom | kObstacleDoor, intersection, &obstacle)) { @@ -146,6 +151,8 @@ void Module::loadParty(const PartyConfiguration &party, const string &entry) { _area->loadParty(_party, position, heading); _area->updateRoomVisibility(); + _player->setCreature(static_cast(_area->player().get())); + update3rdPersonCameraTarget(); update3rdPersonCameraHeading(); switchTo3rdPersonCamera(); @@ -199,7 +206,10 @@ void Module::switchTo3rdPersonCamera() { bool Module::handle(const SDL_Event &event) { if (!_loaded) return false; + if (getCamera()->handle(event)) return true; + if (_player->handle(event)) return true; + if (_area->handle(event)) return true; switch (event.type) { case SDL_MOUSEMOTION: @@ -208,16 +218,11 @@ bool Module::handle(const SDL_Event &event) { case SDL_MOUSEBUTTONUP: if (handleMouseButtonUp(event.button)) return true; break; - case SDL_KEYDOWN: - if (handleKeyDown(event.key)) return true; - break; case SDL_KEYUP: if (handleKeyUp(event.key)) return true; break; } - if (_area->handle(event)) return true; - return false; } @@ -280,8 +285,8 @@ bool Module::handleMouseButtonUp(const SDL_MouseButtonEvent &event) { Creature *creature = dynamic_cast(object); if (creature) { if (!creature->conversation().empty() && _startDialog) { - resetPlayerMovement(); - getCamera()->clearUserInput(); + _player->stopMovement(); + getCamera()->stopMovement(); if (_startDialog) { _startDialog(*creature, creature->conversation()); @@ -293,38 +298,6 @@ bool Module::handleMouseButtonUp(const SDL_MouseButtonEvent &event) { return true; } -void Module::resetPlayerMovement() { - _moveForward = false; - _moveLeft = false; - _moveBackward = false; - _moveRight = false; -} - -bool Module::handleKeyDown(const SDL_KeyboardEvent &event) { - switch (event.keysym.scancode) { - case SDL_SCANCODE_W: - _moveForward = true; - return true; - - case SDL_SCANCODE_Z: - _moveLeft = true; - return true; - - case SDL_SCANCODE_S: - _moveBackward = true; - return true; - - case SDL_SCANCODE_C: - _moveRight = true; - return true; - - default: - break; - } - - return false; -} - bool Module::handleKeyUp(const SDL_KeyboardEvent &event) { switch (event.keysym.scancode) { case SDL_SCANCODE_V: @@ -339,31 +312,9 @@ bool Module::handleKeyUp(const SDL_KeyboardEvent &event) { cycleDebugMode(true); return true; - case SDL_SCANCODE_W: - _moveForward = false; - return true; - - case SDL_SCANCODE_Z: - _moveLeft = false; - return true; - - case SDL_SCANCODE_S: - _moveBackward = false; - return true; - - case SDL_SCANCODE_C: - _moveRight = false; - return true; - - case SDL_SCANCODE_X: - static_cast(*_area->player()).playGreetingAnimation(); - return true; - default: - break; + return false; } - - return false; } void Module::toggleCameraType() { @@ -416,8 +367,9 @@ void Module::update(float dt, GuiContext &guiCtx) { shared_ptr camera(getCamera()); camera->update(dt); - updatePlayer(dt); - + if (_cameraType == CameraType::ThirdPerson) { + _player->update(dt); + } UpdateContext ctx; ctx.deltaTime = dt; ctx.cameraPosition = camera->sceneNode()->absoluteTransform()[3]; @@ -428,47 +380,6 @@ void Module::update(float dt, GuiContext &guiCtx) { _area->fill(ctx, guiCtx); } -void Module::updatePlayer(float dt) { - if (_cameraType != CameraType::ThirdPerson) return; - - ThirdPersonCamera &camera = static_cast(*_thirdPersonCamera); - shared_ptr playerObject(_area->player()); - if (!playerObject) return; - - Creature &player = static_cast(*playerObject); - - float heading = 0.0f; - bool movement = true; - - if (_moveForward) { - heading = camera.heading(); - } else if (_moveBackward) { - heading = camera.heading() + glm::pi(); - } else if (_moveLeft) { - heading = camera.heading() + glm::half_pi(); - } else if (_moveRight) { - heading = camera.heading() - glm::half_pi(); - } else { - movement = false; - } - - if (movement) { - glm::vec3 target(player.position()); - target.x -= 100.0f * glm::sin(heading); - target.y += 100.0f * glm::cos(heading); - - if (_area->moveCreatureTowards(player, target, dt)) { - player.setMovementType(MovementType::Run); - update3rdPersonCameraTarget(); - _area->updateRoomVisibility(); - _area->selectNearestObject(); - } - - } else { - player.setMovementType(MovementType::None); - } -} - void Module::saveTo(GameState &state) const { state.party = _party; _area->saveTo(state); diff --git a/src/game/module.h b/src/game/module.h index 16b14ef8..7782a85f 100644 --- a/src/game/module.h +++ b/src/game/module.h @@ -26,6 +26,7 @@ #include "area.h" #include "camera/firstperson.h" #include "camera/thirdperson.h" +#include "player.h" namespace reone { @@ -49,6 +50,7 @@ public: bool handle(const SDL_Event &event); void update(float dt, GuiContext &guiCtx); + void update3rdPersonCameraTarget(); void update3rdPersonCameraHeading(); void saveTo(GameState &state) const; @@ -82,10 +84,7 @@ private: CameraType _cameraType { CameraType::FirstPerson }; std::shared_ptr _firstPersonCamera; std::shared_ptr _thirdPersonCamera; - bool _moveForward { false }; - bool _moveLeft { false }; - bool _moveBackward { false }; - bool _moveRight { false }; + std::unique_ptr _player; // Callbacks std::function _onCameraChanged; @@ -95,12 +94,9 @@ private: void toggleCameraType(); void cycleDebugMode(bool forward); - void updatePlayer(float dt); bool findObstacle(const glm::vec3 &from, const glm::vec3 &to, glm::vec3 &intersection) const; void getEntryPoint(const std::string &waypoint, glm::vec3 &position, float &heading) const; - void update3rdPersonCameraTarget(); void switchTo3rdPersonCamera(); - void resetPlayerMovement(); SpatialObject *getObjectAt(int x, int y) const; // Loading @@ -108,6 +104,7 @@ private: void loadInfo(const resources::GffStruct &ifo); void loadArea(const resources::GffStruct &ifo); void loadCameras(); + void loadPlayer(); // END Loading @@ -115,7 +112,6 @@ private: bool handleMouseMotion(const SDL_MouseMotionEvent &event); bool handleMouseButtonUp(const SDL_MouseButtonEvent &event); - bool handleKeyDown(const SDL_KeyboardEvent &event); bool handleKeyUp(const SDL_KeyboardEvent &event); // END Events diff --git a/src/game/player.cpp b/src/game/player.cpp new file mode 100644 index 00000000..ca0cd2e9 --- /dev/null +++ b/src/game/player.cpp @@ -0,0 +1,154 @@ +/* + * Copyright © 2020 Vsevolod Kremianskii + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "player.h" + +#include + +#include "area.h" +#include "camera/camera.h" +#include "module.h" +#include "object/creature.h" + +using namespace std; + +namespace reone { + +namespace game { + +Player::Player(Module *module, Area *area, Camera *camera) : _module(module), _area(area), _camera(camera) { + if (!module) { + throw invalid_argument("Module must not be null"); + } + if (!area) { + throw invalid_argument("Area must not be null"); + } + if (!camera) { + throw invalid_argument("Camera must not be null"); + } +} + +bool Player::handle(const SDL_Event &event) { + if (!_creature) return false; + + switch (event.type) { + case SDL_KEYDOWN: + return handleKeyDown(event.key); + case SDL_KEYUP: + return handleKeyUp(event.key); + default: + return false; + } +} + +bool Player::handleKeyDown(const SDL_KeyboardEvent &event) { + switch (event.keysym.scancode) { + case SDL_SCANCODE_W: + _moveForward = true; + return true; + + case SDL_SCANCODE_Z: + _moveLeft = true; + return true; + + case SDL_SCANCODE_S: + _moveBackward = true; + return true; + + case SDL_SCANCODE_C: + _moveRight = true; + return true; + + default: + return false; + } +} + +bool Player::handleKeyUp(const SDL_KeyboardEvent &event) { + switch (event.keysym.scancode) { + case SDL_SCANCODE_W: + _moveForward = false; + return true; + + case SDL_SCANCODE_Z: + _moveLeft = false; + return true; + + case SDL_SCANCODE_S: + _moveBackward = false; + return true; + + case SDL_SCANCODE_C: + _moveRight = false; + return true; + + case SDL_SCANCODE_X: + _creature->playGreetingAnimation(); + return true; + + default: + return false; + } +} + +void Player::update(float dt) { + if (!_creature) return; + + float heading = 0.0f; + bool movement = true; + + if (_moveForward) { + heading = _camera->heading(); + } else if (_moveBackward) { + heading = _camera->heading() + glm::pi(); + } else if (_moveLeft) { + heading = _camera->heading() + glm::half_pi(); + } else if (_moveRight) { + heading = _camera->heading() - glm::half_pi(); + } else { + movement = false; + } + if (movement) { + glm::vec2 dest(_creature->position()); + dest.x -= 100.0f * glm::sin(heading); + dest.y += 100.0f * glm::cos(heading); + + if (_area->moveCreatureTowards(*_creature, dest, dt)) { + _creature->setMovementType(MovementType::Run); + _module->update3rdPersonCameraTarget(); + _area->updateRoomVisibility(); + _area->selectNearestObject(); + } + } else { + _creature->setMovementType(MovementType::None); + } +} + +void Player::stopMovement() { + _moveForward = false; + _moveLeft = false; + _moveBackward = false; + _moveRight = false; +} + +void Player::setCreature(Creature *creature) { + _creature = creature; +} + +} // namespace game + +} // namespace reone diff --git a/src/game/player.h b/src/game/player.h new file mode 100644 index 00000000..798f169d --- /dev/null +++ b/src/game/player.h @@ -0,0 +1,63 @@ +/* +* Copyright © 2020 Vsevolod Kremianskii +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#pragma once + +#include "SDL_events.h" + +namespace reone { + +namespace game { + +class Area; +class Camera; +class Creature; +class Module; + +/** + * Encapsulates third-person player controls. + */ +class Player { +public: + Player(Module *module, Area *area, Camera *camera); + + bool handle(const SDL_Event &event); + void update(float dt); + + void stopMovement(); + + void setCreature(Creature *creature); + + Module *_module { nullptr }; + Area *_area { nullptr }; + Camera *_camera { nullptr }; + Creature *_creature { nullptr }; + bool _moveForward { false }; + bool _moveLeft { false }; + bool _moveBackward { false }; + bool _moveRight { false }; + + Player(const Player &) = delete; + Player &operator=(const Player &) = delete; + + bool handleKeyDown(const SDL_KeyboardEvent &event); + bool handleKeyUp(const SDL_KeyboardEvent &event); +}; + +} // namespace game + +} // namespace reone