From d82f3b7665435abefe84c8dbc16483acd235b478 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 25 Sep 2014 20:53:17 +0200 Subject: Move external entity state from Entity to Map --- src/CMakeLists.txt | 1 - src/control/MapContext.cpp | 8 ++-- src/control/MapContext.hpp | 2 +- src/model/CollisionType.hpp | 41 +++++++++++++++++++++ src/model/Entity.cpp | 68 ---------------------------------- src/model/Entity.hpp | 51 ++------------------------ src/model/Map.cpp | 59 +++++++++++++++++++++++++++++- src/model/Map.hpp | 89 +++++++++++++++++++++++++++++++++++++-------- src/model/Position.hpp | 29 +++++++++++++++ src/view/MapView.cpp | 10 ++--- src/view/MapView.hpp | 2 +- 11 files changed, 213 insertions(+), 147 deletions(-) create mode 100644 src/model/CollisionType.hpp delete mode 100644 src/model/Entity.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b2d55ac..54836d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,7 +5,6 @@ add_executable(rpgedit rpgedit.cpp control/MapContext.cpp control/RPGEdit.cpp - model/Entity.cpp model/Map.cpp view/MapView.cpp view/SpriteCache.cpp diff --git a/src/control/MapContext.cpp b/src/control/MapContext.cpp index acad969..8900298 100644 --- a/src/control/MapContext.cpp +++ b/src/control/MapContext.cpp @@ -35,9 +35,7 @@ MapContext::MapContext(EventBus *eventBus0, InputHandler *inputHandler0, const s : eventBus(eventBus0), inputHandler(inputHandler0), map(map0) { view = std::unique_ptr(new View::MapView(window, map.getTileset())); - map.getEntities().emplace_back("square"); - playerEntity = &map.getEntities().back(); - playerEntity->moveTo(&map, Model::Position{8, 8}); + playerEntity = map.addEntity("square", Model::Position{8, 8}); view->updateEntities(map.getEntities()); @@ -50,12 +48,12 @@ MapContext::MapContext(EventBus *eventBus0, InputHandler *inputHandler0, const s } void MapContext::movePlayer(Model::Direction dir, uint64_t time) { - if (!playerEntity->move(&map, dir, time, time+250)) + if (!map.moveEntity(playerEntity, dir, time, time+250)) return; eventBus->enqueue( [=] { - playerEntity->finishTransition(&map); + map.finishEntityTransition(playerEntity); movePlayerContinue(time+250); }, time+250 diff --git a/src/control/MapContext.hpp b/src/control/MapContext.hpp index a60bdfc..d9c34f3 100644 --- a/src/control/MapContext.hpp +++ b/src/control/MapContext.hpp @@ -54,7 +54,7 @@ private: void keyPressed(uint16_t key, uint64_t time); Model::Position getViewPosition(uint64_t time) { - return playerEntity->getPosition(time); + return map.getEntityPosition(playerEntity, time); } public: diff --git a/src/model/CollisionType.hpp b/src/model/CollisionType.hpp new file mode 100644 index 0000000..4877669 --- /dev/null +++ b/src/model/CollisionType.hpp @@ -0,0 +1,41 @@ +/* + Copyright (c) 2014, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + + +namespace RPGEdit { + +namespace Model { + +enum CollisionType { + BLOCKED = 0, + EMPTY, +}; + +} + +} diff --git a/src/model/Entity.cpp b/src/model/Entity.cpp deleted file mode 100644 index 71447e6..0000000 --- a/src/model/Entity.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright (c) 2014, Matthias Schiffer - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - - -#include "Entity.hpp" -#include "Map.hpp" - - -namespace RPGEdit { - -namespace Model { - -bool Entity::move(Map *map, Direction dir, uint64_t start, uint64_t end) { - if (hasTransition()) - return false; - - direction = dir; - - Position newPos = translate(dir, 1); - if (map->getCollisionAt(newPos.x, newPos.y) == Map::BLOCKED) - return false; - - map->setCollisionAt(newPos.x, newPos.y, Map::BLOCKED); - - transitionStart = start; - transitionEnd = end; - - return true; -} - -void Entity::moveTo(Map *map, Position newPos) { - map->setCollisionAt(pos.x, pos.y, Map::EMPTY); - map->setCollisionAt(newPos.x, newPos.y, Map::BLOCKED); - - pos = newPos; - transitionStart = transitionEnd = 0; -} - -void Entity::finishTransition(Map *map) { - if (hasTransition()) - moveTo(map, translate(direction, 1)); -} - -} - -} diff --git a/src/model/Entity.hpp b/src/model/Entity.hpp index 170f23a..eab6983 100644 --- a/src/model/Entity.hpp +++ b/src/model/Entity.hpp @@ -39,41 +39,12 @@ namespace RPGEdit { namespace Model { -class Map; - class Entity { private: - const std::string name; + std::string name; - Position pos; Direction direction; - uint64_t transitionStart = 0; - uint64_t transitionEnd = 0; - - Position translate(Direction dir, float amount) const { - Position p = pos; - - switch (dir) { - case NORTH: - p.y -= amount; - break; - - case EAST: - p.x += amount; - break; - - case SOUTH: - p.y += amount; - break; - - case WEST: - p.x -= amount; - } - - return p; - } - public: Entity(const std::string &name0) : name(name0), direction(NORTH) { @@ -83,29 +54,13 @@ public: return name; } - Position getPosition(uint64_t time) const { - if (hasTransition()) - if (time <= transitionStart) - return pos; - else if (time >= transitionEnd) - return translate(direction, 1); - else - return translate(direction, float(time-transitionStart)/float(transitionEnd-transitionStart)); - else - return pos; - } - Direction getDirection() const { return direction; } - bool hasTransition() const { - return transitionEnd; + void setDirection(Direction dir) { + direction = dir; } - - void moveTo(Map *map, Position newPos); - bool move(Map *map, Direction dir, uint64_t start, uint64_t end); - void finishTransition(Map *map); }; } diff --git a/src/model/Map.cpp b/src/model/Map.cpp index faead6d..a5b5ee9 100644 --- a/src/model/Map.cpp +++ b/src/model/Map.cpp @@ -31,6 +31,62 @@ namespace RPGEdit { namespace Model { +Position Map::getEntityPosition(const Entity *entity, uint64_t time) const { + const EntityState &state = entityStates.at(entity); + + if (state.transitionEnd) + if (time <= state.transitionStart) + return state.position; + else if (time >= state.transitionEnd) + return state.position + state.direction; + else + return state.position.translate(state.direction, + float(time-state.transitionStart)/ + float(state.transitionEnd-state.transitionStart)); + else + return state.position; +} + +bool Map::moveEntity(Entity *entity, Direction dir, uint64_t start, uint64_t end) { + EntityState &state = entityStates.at(entity); + + if (state.transitionEnd) + return false; + + entity->setDirection(dir); + + Position pos = state.position + dir; + + if (getCollisionAt(pos.x, pos.y) == BLOCKED) + return false; + + setCollisionAt(pos.x, pos.y, BLOCKED); + + state.transitionStart = start; + state.transitionEnd = end; + state.direction = dir; + + return true; +} + +void Map::moveEntityTo(Entity *entity, Position pos) { + EntityState &state = entityStates.at(entity); + + setCollisionAt(state.position.x, state.position.y, EMPTY); + setCollisionAt(pos.x, pos.y, BLOCKED); + + state.position = pos; + state.transitionStart = state.transitionEnd = 0; + +} + +void Map::finishEntityTransition(Entity *entity) { + EntityState &state = entityStates.at(entity); + + if (state.transitionEnd) + moveEntityTo(entity, state.position + state.direction); +} + std::unique_ptr Map::load(__attribute__((unused)) const std::string &name) { std::unique_ptr map(new Map(16, 16, 2)); @@ -54,8 +110,7 @@ std::unique_ptr Map::load(__attribute__((unused)) const std::string &name) } } - map->entities.emplace_back("square"); - map->entities.back().moveTo(map.get(), Model::Position{6, 6}); + map->addEntity("square", Model::Position{6, 6}); return map; } diff --git a/src/model/Map.hpp b/src/model/Map.hpp index abbf2f1..c7b9783 100644 --- a/src/model/Map.hpp +++ b/src/model/Map.hpp @@ -27,11 +27,12 @@ #pragma once #include -#include #include #include +#include #include +#include "CollisionType.hpp" #include "Entity.hpp" @@ -39,29 +40,77 @@ namespace RPGEdit { namespace Model { -class Map { -public: - enum CollisionType { - BLOCKED = 0, - EMPTY, - }; - -private: +class _Map { +protected: std::vector tileset; size_t width, height; std::vector collision; std::vector> tiles; - std::deque entities; - - Map(size_t width0, size_t height0, size_t layers) + _Map(size_t width0, size_t height0, size_t layers) : width(width0), height(height0), collision(width*height) { for (size_t i = 0; i < layers; i++) tiles.emplace_back(width*height); } +}; + +class Map : private _Map { +private: + struct EntityState { + Position position; + + Direction direction; + uint64_t transitionStart = 0; + uint64_t transitionEnd = 0; + + EntityState(const Position &position0) : position(position0) {} + }; + + std::vector> entities; + std::unordered_map entityStates; + + + void pushEntity(Entity *entity, EntityState &&state) { + entities.push_back(std::unique_ptr(entity)); + entityStates.emplace(entity, state); + } + + void copyEntities(const Map &other) { + for (auto &e : other.entities) + pushEntity(new Entity(*e), EntityState(other.entityStates.at(e.get()))); + } + + + Map(size_t width0, size_t height0, size_t layers) : _Map(width0, height0, layers) { + } public: + Map & operator=(const Map &other) { + static_cast<_Map>(*this) = other; + copyEntities(other); + + return *this; + } + + Map(const Map &other) : _Map(other) { + copyEntities(other); + } + + Map & operator=(Map &&other) { + static_cast<_Map>(*this) = std::move(other); + + entities = std::move(other.entities); + entityStates = std::move(other.entityStates); + + return *this; + } + + Map(Map &&other) : _Map(std::move(other)) { + entities = std::move(other.entities); + entityStates = std::move(other.entityStates); + } + std::vector & getTileset() { return tileset; } @@ -70,12 +119,15 @@ public: return tileset; } - std::deque & getEntities() { + const std::vector> & getEntities() const { return entities; } - const std::deque & getEntities() const { - return entities; + Entity * addEntity(const std::string &name, const Position &pos) { + Entity *e = new Entity(name); + pushEntity(e, EntityState(pos)); + setCollisionAt(pos.x, pos.y, BLOCKED); + return e; } size_t getWidth() const { @@ -92,7 +144,7 @@ public: void setCollisionAt(size_t x, size_t y, CollisionType value) { if (x >= width || y >= height) - throw std::range_error("Map::setTileAt: bad coordinates"); + throw std::range_error("Map::setCollisionAt: bad coordinates"); collision[y*width + x] = value; } @@ -119,6 +171,11 @@ public: return tiles[layer][y*width + x]; } + Position getEntityPosition(const Entity *entity, uint64_t time) const; + bool moveEntity(Entity *entity, Direction dir, uint64_t start, uint64_t end); + void moveEntityTo(Entity *entity, Position pos); + void finishEntityTransition(Entity *entity); + static std::unique_ptr load(const std::string &name); }; diff --git a/src/model/Position.hpp b/src/model/Position.hpp index b68476f..84044e6 100644 --- a/src/model/Position.hpp +++ b/src/model/Position.hpp @@ -26,6 +26,8 @@ #pragma once +#include "Direction.hpp" + namespace RPGEdit { @@ -33,6 +35,33 @@ namespace Model { struct Position { float x, y; + + Position translate(Direction dir, float amount) const { + Position p = *this; + + switch (dir) { + case NORTH: + p.y -= amount; + break; + + case EAST: + p.x += amount; + break; + + case SOUTH: + p.y += amount; + break; + + case WEST: + p.x -= amount; + } + + return p; + } + + Position operator+(Direction dir) const { + return translate(dir, 1); + } }; } diff --git a/src/view/MapView.cpp b/src/view/MapView.cpp index dbce5e4..4a6e552 100644 --- a/src/view/MapView.cpp +++ b/src/view/MapView.cpp @@ -76,11 +76,11 @@ MapView::~MapView() { clearEntities(); } -void MapView::updateEntities(const std::deque &entities) { +void MapView::updateEntities(const std::vector> &entities) { SpriteCache *spriteCache = window->getSpriteCache(); for (auto &entity : entities) { - const std::string &name = entity.getName(); + const std::string &name = entity->getName(); if (!entitySprites[name]) entitySprites[name] = SDL_CreateTextureFromSurface(window->getRenderer(), spriteCache->get("entity", name)); @@ -137,8 +137,8 @@ void MapView::render(const Model::Map *map, Model::Position center, uint64_t tim } for (auto &entity : map->getEntities()) { - Model::Position pos = entity.getPosition(time); - Model::Direction dir = entity.getDirection(); + Model::Position pos = map->getEntityPosition(entity.get(), time); + Model::Direction dir = entity->getDirection(); SDL_Rect src = { .x = getTileSize()*dir, @@ -154,7 +154,7 @@ void MapView::render(const Model::Map *map, Model::Position center, uint64_t tim .h = tilePixels, }; - SDL_RenderCopy(window->getRenderer(), entitySprites[entity.getName()], &src, &dst); + SDL_RenderCopy(window->getRenderer(), entitySprites[entity->getName()], &src, &dst); } } diff --git a/src/view/MapView.hpp b/src/view/MapView.hpp index f101c24..e813950 100644 --- a/src/view/MapView.hpp +++ b/src/view/MapView.hpp @@ -53,7 +53,7 @@ public: MapView(const std::shared_ptr &window0, const std::vector &tileset); ~MapView(); - void updateEntities(const std::deque &entities); + void updateEntities(const std::vector> &entities); void clearEntities(); void clear(); -- cgit v1.2.3