From 3c1d94d87600b1b039109761be60158c47d6935e Mon Sep 17 00:00:00 2001 From: Vsevolod Kremianskii Date: Fri, 2 Oct 2020 14:27:33 +0700 Subject: [PATCH] refactor: Extract object selection into a separate class --- CMakeLists.txt | 10 +- src/game/area.cpp | 128 +++------------- src/game/area.h | 16 +- src/game/area_actions.cpp | 2 +- src/game/collisiondetect.cpp | 1 - src/game/game.h | 4 +- .../gui/{classsel.cpp => classselect.cpp} | 2 +- src/game/gui/{classsel.h => classselect.h} | 0 .../{portraitsel.cpp => portraitselect.cpp} | 2 +- .../gui/{portraitsel.h => portraitselect.h} | 0 src/game/module.cpp | 6 +- src/game/objectselect.cpp | 138 ++++++++++++++++++ src/game/objectselect.h | 54 +++++++ src/game/player.cpp | 2 +- 14 files changed, 234 insertions(+), 131 deletions(-) rename src/game/gui/{classsel.cpp => classselect.cpp} (99%) rename src/game/gui/{classsel.h => classselect.h} (100%) rename src/game/gui/{portraitsel.cpp => portraitselect.cpp} (99%) rename src/game/gui/{portraitsel.h => portraitselect.h} (100%) create mode 100644 src/game/objectselect.cpp create mode 100644 src/game/objectselect.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dd274eb..de57564a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,14 +66,14 @@ set(HEADERS src/game/console.h src/game/dialog.h src/game/game.h - src/game/gui/classsel.h + src/game/gui/classselect.h src/game/gui/container.h src/game/gui/debug.h src/game/gui/dialog.h src/game/gui/equip.h src/game/gui/hud.h src/game/gui/mainmenu.h - src/game/gui/portraitsel.h + src/game/gui/portraitselect.h src/game/gui/target.h src/game/module.h src/game/multiplayer/area.h @@ -93,6 +93,7 @@ set(HEADERS src/game/object/spatial.h src/game/object/trigger.h src/game/object/waypoint.h + src/game/objectselect.h src/game/pathfinder.h src/game/paths.h src/game/player.h @@ -199,7 +200,7 @@ set(SOURCES src/game/console.cpp src/game/dialog.cpp src/game/game.cpp - src/game/gui/classsel.cpp + src/game/gui/classselect.cpp src/game/gui/colors.cpp src/game/gui/container.cpp src/game/gui/debug.cpp @@ -207,7 +208,7 @@ set(SOURCES src/game/gui/equip.cpp src/game/gui/hud.cpp src/game/gui/mainmenu.cpp - src/game/gui/portraitsel.cpp + src/game/gui/portraitselect.cpp src/game/gui/target.cpp src/game/module.cpp src/game/multiplayer/area.cpp @@ -226,6 +227,7 @@ set(SOURCES src/game/object/spatial.cpp src/game/object/trigger.cpp src/game/object/waypoint.cpp + src/game/objectselect.cpp src/game/pathfinder.cpp src/game/paths.cpp src/game/player.cpp diff --git a/src/game/area.cpp b/src/game/area.cpp index ef78c66c..41575e85 100644 --- a/src/game/area.cpp +++ b/src/game/area.cpp @@ -56,13 +56,11 @@ namespace reone { namespace game { - static const float kDefaultFieldOfView = 75.0f; static const float kDrawDebugDistance = 64.0f; static const float kPartyMemberFollowDistance = 4.0f; static const float kMaxDistanceToTestCollision = 64.0f; static const float kElevationTestZ = 1024.0f; -static const float kSelectionDistance = 64.0f; static const char kPartyLeaderTag[] = "party-leader"; static const char kPartyMember1Tag[] = "party-member-1"; @@ -80,7 +78,8 @@ Area::Area( _objectFactory(objectFactory), _sceneGraph(sceneGraph), _opts(opts), - _collisionDetector(this) { + _collisionDetector(this), + _objectSelector(this) { _cameraAspect = opts.width / static_cast(opts.height); } @@ -149,7 +148,7 @@ void Area::loadPTH() { _sceneGraph->addRoot(aabb); } - _pathfinding.load(paths, pointZ); + _pathfinder.load(paths, pointZ); } void Area::loadARE(const GffStruct &are) { @@ -387,11 +386,11 @@ bool Area::handle(const SDL_Event &event) { bool Area::handleKeyDown(const SDL_KeyboardEvent &event) { switch (event.keysym.scancode) { case SDL_SCANCODE_Q: - selectNextObject(true); + _objectSelector.selectNext(true); return true; case SDL_SCANCODE_E: - selectNextObject(); + _objectSelector.selectNext(); return true; default: @@ -399,62 +398,6 @@ bool Area::handleKeyDown(const SDL_KeyboardEvent &event) { } } -void Area::selectNextObject(bool reverse) { - static vector selectables; - - selectables.clear(); - getSelectableObjects(selectables); - - if (selectables.empty()) { - _selectedObjectId = -1; - return; - } - if (_selectedObjectId == -1) { - _selectedObjectId = selectables.front(); - return; - } - if (reverse) { - auto selected = std::find(selectables.rbegin(), selectables.rend(), _selectedObjectId); - if (selected != selectables.rend()) { - selected++; - } - _selectedObjectId = selected != selectables.rend() ? *selected : selectables.back(); - - } else { - auto selected = std::find(selectables.begin(), selectables.end(), _selectedObjectId); - if (selected != selectables.end()) { - selected++; - } - _selectedObjectId = selected != selectables.end() ? *selected : selectables.front(); - } -} - -void Area::getSelectableObjects(vector &ids) const { - static vector> selectables; - - glm::vec3 origin(_player->position()); - selectables.clear(); - - for (auto &object : _objects) { - if (!object->isSelectable() || object.get() == _player.get()) continue; - - shared_ptr model(object->model()); - if (!model || !model->isVisible()) continue; - - float dist = object->distanceTo(origin); - if (dist > kSelectionDistance) continue; - - selectables.push_back(make_pair(object->id(), dist)); - } - - sort(selectables.begin(), selectables.end(), [](const pair &left, const pair &right) { - return left.second < right.second; - }); - for (auto &selectable : selectables) { - ids.push_back(selectable.first); - } -} - bool Area::getElevationAt(const glm::vec2 &position, Room *&room, float &z) const { RaycastProperties props; props.origin = glm::vec3(position, kElevationTestZ); @@ -490,7 +433,7 @@ void Area::update(const UpdateContext &updateCtx) { object->update(updateCtx); } - updateSelection(); + _objectSelector.update(); _sceneGraph->prepare(updateCtx.cameraPosition); } @@ -649,19 +592,6 @@ void Area::updateRoomVisibility() { } } -void Area::selectNearestObject() { - _selectedObjectId = -1; - selectNextObject(); -} - -void Area::hilight(uint32_t objectId) { - _hilightedObjectId = objectId; -} - -void Area::select(uint32_t objectId) { - _selectedObjectId = objectId; -} - SpatialObject *Area::getObjectAt(int x, int y) const { Camera *camera = getCamera(); shared_ptr sceneNode(camera->sceneNode()); @@ -685,50 +615,30 @@ SpatialObject *Area::getObjectAt(int x, int y) const { return nullptr; } -void Area::updateSelection() { - if (_hilightedObjectId != -1) { - shared_ptr object(find(_hilightedObjectId)); - if (!object || !object->isSelectable()) { - _hilightedObjectId = -1; - } - } - if (_selectedObjectId != -1) { - shared_ptr object(find(_selectedObjectId)); - if (!object || !object->isSelectable()) { - _selectedObjectId = -1; - } - } -} - void Area::fill(const UpdateContext &updateCtx, GuiContext &guiCtx) { addPartyMemberPortrait(_partyLeader, guiCtx); addPartyMemberPortrait(_partyMember1, guiCtx); addPartyMemberPortrait(_partyMember2, guiCtx); - if (_hilightedObjectId != -1) { - glm::vec3 coords(getSelectableScreenCoords(_hilightedObjectId, updateCtx)); + int hilightedObjectId = _objectSelector.hilightedObjectId(); + if (hilightedObjectId != -1) { + glm::vec3 coords(getSelectableScreenCoords(hilightedObjectId, updateCtx)); if (coords.z < 1.0f) { guiCtx.target.hasHilighted = true; guiCtx.target.hilightedScreenCoords = coords; } } - if (_selectedObjectId != -1) { - glm::vec3 coords(getSelectableScreenCoords(_selectedObjectId, updateCtx)); + int selectedObjectId = _objectSelector.selectedObjectId(); + if (selectedObjectId != -1) { + glm::vec3 coords(getSelectableScreenCoords(selectedObjectId, updateCtx)); if (coords.z < 1.0f) { guiCtx.target.hasSelected = true; guiCtx.target.selectedScreenCoords = coords; } } - addDebugInfo(updateCtx, guiCtx); } -void Area::addPartyMemberPortrait(const shared_ptr &object, GuiContext &ctx) { - if (object) { - ctx.hud.partyPortraits.push_back(static_cast(*object).portrait()); - } -} - glm::vec3 Area::getSelectableScreenCoords(uint32_t objectId, const UpdateContext &ctx) const { static glm::vec4 viewport(0.0f, 0.0f, 1.0f, 1.0f); @@ -738,6 +648,12 @@ glm::vec3 Area::getSelectableScreenCoords(uint32_t objectId, const UpdateContext return glm::project(position, ctx.view, ctx.projection, viewport); } +void Area::addPartyMemberPortrait(const shared_ptr &object, GuiContext &ctx) { + if (object) { + ctx.hud.partyPortraits.push_back(static_cast(*object).portrait()); + } +} + void Area::addDebugInfo(const UpdateContext &updateCtx, GuiContext &guiCtx) { if (getDebugMode() == DebugMode::GameObjects) { guiCtx.debug.objects.clear(); @@ -816,10 +732,6 @@ Camera *Area::getCamera() const { return _cameraType == CameraType::ThirdPerson ? _thirdPersonCamera.get() : static_cast(_firstPersonCamera.get()); } -uint32_t Area::selectedObjectId() const { - return _selectedObjectId; -} - const CameraStyle &Area::cameraStyle() const { return _cameraStyle; } @@ -848,6 +760,10 @@ ThirdPersonCamera *Area::thirdPersonCamera() { return _thirdPersonCamera.get(); } +ObjectSelector &Area::objectSelector() { + return _objectSelector; +} + shared_ptr Area::player() const { return _player; } diff --git a/src/game/area.h b/src/game/area.h index 3d9b2f86..78cb15de 100644 --- a/src/game/area.h +++ b/src/game/area.h @@ -34,6 +34,7 @@ #include "object/placeable.h" #include "object/trigger.h" #include "object/waypoint.h" +#include "objectselect.h" #include "pathfinder.h" #include "room.h" @@ -67,9 +68,6 @@ public: bool moveCreatureTowards(Creature &creature, const glm::vec2 &dest, bool run, float dt); void updateTriggers(const Creature &creature); void updateRoomVisibility(); - void selectNearestObject(); - void hilight(uint32_t objectId); - void select(uint32_t objectId); SpatialObject *getObjectAt(int x, int y) const; void update3rdPersonCameraTarget(); @@ -90,7 +88,6 @@ public: void loadState(const GameState &state); // General getters - uint32_t selectedObjectId() const; const CameraStyle &cameraStyle() const; CameraType cameraType() const; const std::string &music() const; @@ -98,6 +95,7 @@ public: const ObjectList &objects() const; const CollisionDetector &collisionDetector() const; ThirdPersonCamera *thirdPersonCamera(); + ObjectSelector &objectSelector(); // Party getters std::shared_ptr player() const; @@ -159,7 +157,8 @@ private: resources::GameVersion _version { resources::GameVersion::KotOR }; render::GraphicsOptions _opts; CollisionDetector _collisionDetector; - Pathfinder _pathfinding; + Pathfinder _pathfinder; + ObjectSelector _objectSelector; std::string _name; RoomMap _rooms; std::unique_ptr _visibility; @@ -169,8 +168,6 @@ private: std::list _delayed; std::map _events; int _eventCounter { 0 }; - int _hilightedObjectId { -1 }; - int _selectedObjectId { -1 }; // Callbacks std::function _onModuleTransition; @@ -184,12 +181,9 @@ private: void selectNextPathPoint(Creature::Path &path); void updateCreaturePath(Creature &creature, const glm::vec3 &dest); bool getElevationAt(const glm::vec2 &position, Room *&room, float &z) const; - void updateSelection(); void addPartyMemberPortrait(const std::shared_ptr &object, GuiContext &ctx); - glm::vec3 getSelectableScreenCoords(uint32_t objectId, const UpdateContext &ctx) const; void addDebugInfo(const UpdateContext &updateCtx, GuiContext &guiCtx); - void selectNextObject(bool reverse = false); - void getSelectableObjects(std::vector &ids) const; + glm::vec3 getSelectableScreenCoords(uint32_t objectId, const UpdateContext &ctx) const; // Loading diff --git a/src/game/area_actions.cpp b/src/game/area_actions.cpp index 205a821b..829ded75 100644 --- a/src/game/area_actions.cpp +++ b/src/game/area_actions.cpp @@ -141,7 +141,7 @@ void Area::selectNextPathPoint(Creature::Path &path) { void Area::updateCreaturePath(Creature &creature, const glm::vec3 &dest) { const glm::vec3 &origin = creature.position(); - vector points(_pathfinding.findPath(origin, dest)); + vector points(_pathfinder.findPath(origin, dest)); uint32_t now = SDL_GetTicks(); creature.setPath(dest, move(points), now); diff --git a/src/game/collisiondetect.cpp b/src/game/collisiondetect.cpp index 7bbd5d5f..3376af1a 100644 --- a/src/game/collisiondetect.cpp +++ b/src/game/collisiondetect.cpp @@ -107,7 +107,6 @@ bool CollisionDetector::rayTestRooms(const RaycastProperties &props, RaycastResu for (auto &pair : _area->rooms()) { Room &room = *pair.second; - if (!room.visible()) continue; const Walkmesh *walkmesh = room.walkmesh(); if (!walkmesh) continue; diff --git a/src/game/game.h b/src/game/game.h index 3f1c447b..c286cdce 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -24,14 +24,14 @@ #include "../render/window.h" #include "../resources/types.h" -#include "gui/classsel.h" +#include "gui/classselect.h" #include "gui/container.h" #include "gui/debug.h" #include "gui/dialog.h" #include "gui/equip.h" #include "gui/hud.h" #include "gui/mainmenu.h" -#include "gui/portraitsel.h" +#include "gui/portraitselect.h" #include "gui/target.h" #include "area.h" diff --git a/src/game/gui/classsel.cpp b/src/game/gui/classselect.cpp similarity index 99% rename from src/game/gui/classsel.cpp rename to src/game/gui/classselect.cpp index 58e8fde2..35a40706 100644 --- a/src/game/gui/classsel.cpp +++ b/src/game/gui/classselect.cpp @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -#include "classsel.h" +#include "classselect.h" #include "../../resources/resources.h" diff --git a/src/game/gui/classsel.h b/src/game/gui/classselect.h similarity index 100% rename from src/game/gui/classsel.h rename to src/game/gui/classselect.h diff --git a/src/game/gui/portraitsel.cpp b/src/game/gui/portraitselect.cpp similarity index 99% rename from src/game/gui/portraitsel.cpp rename to src/game/gui/portraitselect.cpp index 26ebde2e..1a72b82d 100644 --- a/src/game/gui/portraitsel.cpp +++ b/src/game/gui/portraitselect.cpp @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -#include "portraitsel.h" +#include "portraitselect.h" #include "../../core/random.h" #include "../../resources/resources.h" diff --git a/src/game/gui/portraitsel.h b/src/game/gui/portraitselect.h similarity index 100% rename from src/game/gui/portraitsel.h rename to src/game/gui/portraitselect.h diff --git a/src/game/module.cpp b/src/game/module.cpp index 3e58025f..7a930cb8 100644 --- a/src/game/module.cpp +++ b/src/game/module.cpp @@ -163,7 +163,7 @@ bool Module::handle(const SDL_Event &event) { bool Module::handleMouseMotion(const SDL_MouseMotionEvent &event) { const SpatialObject *object = _area->getObjectAt(event.x, event.y); - _area->hilight(object ? object->id() : -1); + _area->objectSelector().hilight(object ? object->id() : -1); return true; } @@ -175,9 +175,9 @@ bool Module::handleMouseButtonUp(const SDL_MouseButtonEvent &event) { } debug(boost::format("Object '%s' clicked on") % object->tag()); - uint32_t selectedObjectId = _area->selectedObjectId(); + uint32_t selectedObjectId = _area->objectSelector().selectedObjectId(); if (object->id() != selectedObjectId) { - _area->select(object->id()); + _area->objectSelector().select(object->id()); return true; } diff --git a/src/game/objectselect.cpp b/src/game/objectselect.cpp new file mode 100644 index 00000000..50dbf78d --- /dev/null +++ b/src/game/objectselect.cpp @@ -0,0 +1,138 @@ +/* + * 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 "objectselect.h" + +#include + +#include "glm/vec3.hpp" + +#include "area.h" + +using namespace std; + +using namespace reone::render; + +namespace reone { + +namespace game { + +static const float kSelectionDistance = 64.0f; + +ObjectSelector::ObjectSelector(Area *area) : _area(area) { + if (!area) { + throw invalid_argument("Area must not be null"); + } +} + +void ObjectSelector::update() { + if (_hilightedObjectId != -1) { + shared_ptr object(_area->find(_hilightedObjectId)); + if (!object || !object->isSelectable()) { + _hilightedObjectId = -1; + } + } + if (_selectedObjectId != -1) { + shared_ptr object(_area->find(_selectedObjectId)); + if (!object || !object->isSelectable()) { + _selectedObjectId = -1; + } + } +} + +void ObjectSelector::selectNext(bool reverse) { + static vector selectables; + + selectables.clear(); + getSelectableObjects(selectables); + + if (selectables.empty()) { + _selectedObjectId = -1; + return; + } + if (_selectedObjectId == -1) { + _selectedObjectId = selectables.front(); + return; + } + if (reverse) { + auto selected = std::find(selectables.rbegin(), selectables.rend(), _selectedObjectId); + if (selected != selectables.rend()) { + selected++; + } + _selectedObjectId = selected != selectables.rend() ? *selected : selectables.back(); + + } else { + auto selected = std::find(selectables.begin(), selectables.end(), _selectedObjectId); + if (selected != selectables.end()) { + selected++; + } + _selectedObjectId = selected != selectables.end() ? *selected : selectables.front(); + } +} + +void ObjectSelector::getSelectableObjects(vector &ids) const { + static vector> selectables; + + shared_ptr player(_area->player()); + + glm::vec3 origin(player->position()); + selectables.clear(); + + for (auto &object : _area->objects()) { + if (!object->isSelectable() || object.get() == player.get()) continue; + + shared_ptr model(object->model()); + if (!model || !model->isVisible()) continue; + + float dist = object->distanceTo(origin); + if (dist > kSelectionDistance) continue; + + selectables.push_back(make_pair(object->id(), dist)); + } + + sort(selectables.begin(), selectables.end(), [](const pair &left, const pair &right) { + return left.second < right.second; + }); + for (auto &selectable : selectables) { + ids.push_back(selectable.first); + } +} + +void ObjectSelector::selectNearest() { + _selectedObjectId = -1; + selectNext(); +} + +void ObjectSelector::hilight(uint32_t objectId) { + _hilightedObjectId = objectId; +} + +void ObjectSelector::select(uint32_t objectId) { + _selectedObjectId = objectId; +} + +int ObjectSelector::hilightedObjectId() const { + return _hilightedObjectId; +} + +int ObjectSelector::selectedObjectId() const { + return _selectedObjectId; +} + +} // namespace game + +} // namespace reone diff --git a/src/game/objectselect.h b/src/game/objectselect.h new file mode 100644 index 00000000..fe5300a6 --- /dev/null +++ b/src/game/objectselect.h @@ -0,0 +1,54 @@ +/* + * 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 +#include + +namespace reone { + +namespace game { + +class Area; + +class ObjectSelector { +public: + ObjectSelector(Area *area); + + void update(); + void selectNext(bool reverse = false); + void getSelectableObjects(std::vector &ids) const; + void selectNearest(); + void hilight(uint32_t objectId); + void select(uint32_t objectId); + + int hilightedObjectId() const; + int selectedObjectId() const; + +private: + Area *_area { nullptr }; + int _hilightedObjectId { -1 }; + int _selectedObjectId { -1 }; + + ObjectSelector(const ObjectSelector &) = delete; + ObjectSelector &operator=(const ObjectSelector &) = delete; +}; + +} // namespace game + +} // namespace reone diff --git a/src/game/player.cpp b/src/game/player.cpp index 19dd8a45..fbdd055b 100644 --- a/src/game/player.cpp +++ b/src/game/player.cpp @@ -131,7 +131,7 @@ void Player::update(float dt) { _creature->setMovementType(MovementType::Run); _module->area()->update3rdPersonCameraTarget(); _area->updateRoomVisibility(); - _area->selectNearestObject(); + _area->objectSelector().selectNearest(); } } else { _creature->setMovementType(MovementType::None);