refactor: Move player controls to the Player class

This commit is contained in:
Vsevolod Kremianskii 2020-10-01 19:47:56 +07:00
parent 252ab735cc
commit 11dc80a3aa
10 changed files with 245 additions and 118 deletions

View file

@ -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

View file

@ -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<render::CameraSceneNode> sceneNode() const;

View file

@ -152,7 +152,7 @@ void FirstPersonCamera::update(float dt) {
}
}
void FirstPersonCamera::clearUserInput() {
void FirstPersonCamera::stopMovement() {
_moveForward = false;
_moveLeft = false;
_moveBackward = false;

View file

@ -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);

View file

@ -121,7 +121,7 @@ void ThirdPersonCamera::updateSceneNode() {
_sceneNode->setLocalTransform(transform);
}
void ThirdPersonCamera::clearUserInput() {
void ThirdPersonCamera::stopMovement() {
_rotateCCW = false;
_rotateCW = false;
}

View file

@ -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);

View file

@ -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<Player>(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<Creature *>(_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<Creature *>(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<Creature &>(*_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> 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 &>(*_thirdPersonCamera);
shared_ptr<Object> playerObject(_area->player());
if (!playerObject) return;
Creature &player = static_cast<Creature &>(*playerObject);
float heading = 0.0f;
bool movement = true;
if (_moveForward) {
heading = camera.heading();
} else if (_moveBackward) {
heading = camera.heading() + glm::pi<float>();
} else if (_moveLeft) {
heading = camera.heading() + glm::half_pi<float>();
} else if (_moveRight) {
heading = camera.heading() - glm::half_pi<float>();
} 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);

View file

@ -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> _firstPersonCamera;
std::shared_ptr<ThirdPersonCamera> _thirdPersonCamera;
bool _moveForward { false };
bool _moveLeft { false };
bool _moveBackward { false };
bool _moveRight { false };
std::unique_ptr<Player> _player;
// Callbacks
std::function<void(CameraType)> _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

154
src/game/player.cpp Normal file
View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "player.h"
#include <stdexcept>
#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<float>();
} else if (_moveLeft) {
heading = _camera->heading() + glm::half_pi<float>();
} else if (_moveRight) {
heading = _camera->heading() - glm::half_pi<float>();
} 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

63
src/game/player.h Normal file
View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#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