From eb40e3de7226d0005ce0a41c67c9355e675a489b Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 25 Sep 2014 18:39:03 +0200 Subject: Add collision layer to maps and prevent movement into blocked areas --- src/CMakeLists.txt | 1 + src/control/MapContext.cpp | 8 ++---- src/model/Entity.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++ src/model/Entity.hpp | 26 ++++-------------- src/model/Map.cpp | 9 ++++-- src/model/Map.hpp | 24 +++++++++++++++- 6 files changed, 107 insertions(+), 29 deletions(-) create mode 100644 src/model/Entity.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 54836d0..b2d55ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ 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 1904db4..acad969 100644 --- a/src/control/MapContext.cpp +++ b/src/control/MapContext.cpp @@ -37,7 +37,7 @@ MapContext::MapContext(EventBus *eventBus0, InputHandler *inputHandler0, const s map.getEntities().emplace_back("square"); playerEntity = &map.getEntities().back(); - playerEntity->moveTo(Model::Position{8, 8}); + playerEntity->moveTo(&map, Model::Position{8, 8}); view->updateEntities(map.getEntities()); @@ -50,14 +50,12 @@ MapContext::MapContext(EventBus *eventBus0, InputHandler *inputHandler0, const s } void MapContext::movePlayer(Model::Direction dir, uint64_t time) { - if (playerEntity->hasTransition()) + if (!playerEntity->move(&map, dir, time, time+250)) return; - playerEntity->move(dir, time, time+250); - eventBus->enqueue( [=] { - playerEntity->finishTransition(); + playerEntity->finishTransition(&map); movePlayerContinue(time+250); }, time+250 diff --git a/src/model/Entity.cpp b/src/model/Entity.cpp new file mode 100644 index 0000000..71447e6 --- /dev/null +++ b/src/model/Entity.cpp @@ -0,0 +1,68 @@ +/* + 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 1ff444a..170f23a 100644 --- a/src/model/Entity.hpp +++ b/src/model/Entity.hpp @@ -39,6 +39,8 @@ namespace RPGEdit { namespace Model { +class Map; + class Entity { private: const std::string name; @@ -97,29 +99,13 @@ public: return direction; } - void moveTo(Position newPos) { - pos = newPos; - transitionStart = transitionEnd = 0; - } - - void move(Direction dir, uint64_t start, uint64_t end) { - if (hasTransition()) - return; - - direction = dir; - - transitionStart = start; - transitionEnd = end; - } - - void finishTransition() { - if (hasTransition()) - moveTo(translate(direction, 1)); - } - bool hasTransition() const { return transitionEnd; } + + 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 21fbe00..faead6d 100644 --- a/src/model/Map.cpp +++ b/src/model/Map.cpp @@ -39,10 +39,13 @@ std::unique_ptr Map::load(__attribute__((unused)) const std::string &name) for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { - if (4 <= i && i < 12 && 4 <= j && j < 12) + if (4 <= i && i < 12 && 4 <= j && j < 12) { map->setTileAt(0, i, j, 1); - else + map->setCollisionAt(i, j, EMPTY); + } + else { map->setTileAt(0, i, j, 0); + } if (4 <= i && i < 12 && j == 8) map->setTileAt(1, i, j, 2); @@ -52,7 +55,7 @@ std::unique_ptr Map::load(__attribute__((unused)) const std::string &name) } map->entities.emplace_back("square"); - map->entities.back().moveTo(Model::Position{6, 6}); + map->entities.back().moveTo(map.get(), Model::Position{6, 6}); return map; } diff --git a/src/model/Map.hpp b/src/model/Map.hpp index 421b487..abbf2f1 100644 --- a/src/model/Map.hpp +++ b/src/model/Map.hpp @@ -40,16 +40,23 @@ namespace RPGEdit { namespace Model { class Map { +public: + enum CollisionType { + BLOCKED = 0, + EMPTY, + }; + private: 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) - : width(width0), height(height0) { + : width(width0), height(height0), collision(width*height) { for (size_t i = 0; i < layers; i++) tiles.emplace_back(width*height); } @@ -83,6 +90,21 @@ public: return tiles.size(); } + void setCollisionAt(size_t x, size_t y, CollisionType value) { + if (x >= width || y >= height) + throw std::range_error("Map::setTileAt: bad coordinates"); + + collision[y*width + x] = value; + } + + CollisionType getCollisionAt(ssize_t x, ssize_t y) const { + if (x < 0 || (size_t)x >= width || y < 0 || (size_t)y >= height) + return BLOCKED; + + return collision[y*width + x]; + } + + void setTileAt(size_t layer, size_t x, size_t y, uint32_t value) { if (layer >= tiles.size() || x >= width || y >= height) throw std::range_error("Map::setTileAt: bad coordinates"); -- cgit v1.2.3