summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2014-09-26 00:58:27 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2014-09-26 00:58:27 +0200
commitc3e32345e53650a1c231f4e1a41d40c97955b893 (patch)
tree93b22aedbe355173510a04eafec9f14d7c4c3e0f
parent8b4ca336ce68cc17573115dd07eb1bfc6521b298 (diff)
downloadrpgedit-c3e32345e53650a1c231f4e1a41d40c97955b893.tar
rpgedit-c3e32345e53650a1c231f4e1a41d40c97955b893.zip
Collision rework
-rw-r--r--src/control/MapContext.cpp16
-rw-r--r--src/model/CollisionType.hpp2
-rw-r--r--src/model/Direction.hpp23
-rw-r--r--src/model/Entity.hpp2
-rw-r--r--src/model/Map.cpp21
-rw-r--r--src/model/Map.hpp82
-rw-r--r--src/model/Position.hpp31
-rw-r--r--src/view/MapView.cpp4
8 files changed, 135 insertions, 46 deletions
diff --git a/src/control/MapContext.cpp b/src/control/MapContext.cpp
index aa246a9..f5d4c05 100644
--- a/src/control/MapContext.cpp
+++ b/src/control/MapContext.cpp
@@ -62,32 +62,32 @@ void MapContext::movePlayer(Model::Direction dir, uint64_t time) {
void MapContext::movePlayerContinue(uint64_t time) {
if (inputHandler->isKeyPressed(SDL_SCANCODE_UP))
- movePlayer(Model::NORTH, time);
+ movePlayer(Model::Direction::NORTH, time);
else if (inputHandler->isKeyPressed(SDL_SCANCODE_RIGHT))
- movePlayer(Model::EAST, time);
+ movePlayer(Model::Direction::EAST, time);
else if (inputHandler->isKeyPressed(SDL_SCANCODE_DOWN))
- movePlayer(Model::SOUTH, time);
+ movePlayer(Model::Direction::SOUTH, time);
else if (inputHandler->isKeyPressed(SDL_SCANCODE_LEFT))
- movePlayer(Model::WEST, time);
+ movePlayer(Model::Direction::WEST, time);
}
void MapContext::keyPressed(uint16_t key, uint64_t time) {
switch (key) {
case SDL_SCANCODE_UP:
- movePlayer(Model::NORTH, time);
+ movePlayer(Model::Direction::NORTH, time);
break;
case SDL_SCANCODE_RIGHT:
- movePlayer(Model::EAST, time);
+ movePlayer(Model::Direction::EAST, time);
break;
case SDL_SCANCODE_DOWN:
- movePlayer(Model::SOUTH, time);
+ movePlayer(Model::Direction::SOUTH, time);
break;
case SDL_SCANCODE_LEFT:
- movePlayer(Model::WEST, time);
+ movePlayer(Model::Direction::WEST, time);
}
}
diff --git a/src/model/CollisionType.hpp b/src/model/CollisionType.hpp
index 4877669..50bb608 100644
--- a/src/model/CollisionType.hpp
+++ b/src/model/CollisionType.hpp
@@ -31,7 +31,7 @@ namespace RPGEdit {
namespace Model {
-enum CollisionType {
+enum class CollisionType {
BLOCKED = 0,
EMPTY,
};
diff --git a/src/model/Direction.hpp b/src/model/Direction.hpp
index db288f6..e817170 100644
--- a/src/model/Direction.hpp
+++ b/src/model/Direction.hpp
@@ -31,13 +31,32 @@ namespace RPGEdit {
namespace Model {
-enum Direction {
+enum class Direction {
NORTH,
EAST,
SOUTH,
- WEST,
+ WEST
};
+static inline Direction operator-(Direction dir) {
+ switch (dir) {
+ case Direction::NORTH:
+ return Direction::SOUTH;
+
+ case Direction::EAST:
+ return Direction::WEST;
+
+ case Direction::SOUTH:
+ return Direction::NORTH;
+
+ case Direction::WEST:
+ return Direction::EAST;
+
+ default:
+ __builtin_unreachable();
+ }
+}
+
}
}
diff --git a/src/model/Entity.hpp b/src/model/Entity.hpp
index eab6983..331cb4f 100644
--- a/src/model/Entity.hpp
+++ b/src/model/Entity.hpp
@@ -47,7 +47,7 @@ private:
public:
Entity(const std::string &name0)
- : name(name0), direction(NORTH) {
+ : name(name0), direction(Direction::NORTH) {
}
const std::string & getName() const {
diff --git a/src/model/Map.cpp b/src/model/Map.cpp
index b7b40f5..749b25f 100644
--- a/src/model/Map.cpp
+++ b/src/model/Map.cpp
@@ -57,13 +57,9 @@ bool Map::moveEntity(Entity *entity, Direction dir, uint64_t start, uint64_t end
entity->setDirection(dir);
- Position<int> pos = state.position + dir;
-
- if (getCollisionAt(pos.x, pos.y) == BLOCKED)
+ if (isBlocked(state.position + dir))
return false;
- setCollisionAt(pos.x, pos.y, BLOCKED);
-
state.transitionStart = start;
state.transitionEnd = end;
state.direction = dir;
@@ -74,12 +70,11 @@ bool Map::moveEntity(Entity *entity, Direction dir, uint64_t start, uint64_t end
void Map::moveEntityTo(Entity *entity, Position<int> pos) {
EntityState &state = entityStates.at(entity);
- setCollisionAt(state.position.x, state.position.y, EMPTY);
- setCollisionAt(pos.x, pos.y, BLOCKED);
+ removeEntityPosition(state.position, entity);
+ addEntityPosition(pos, entity);
state.position = pos;
state.transitionStart = state.transitionEnd = 0;
-
}
void Map::finishEntityTransition(Entity *entity) {
@@ -98,17 +93,17 @@ std::unique_ptr<Map> 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) {
- map->setTileAt(0, i, j, 1);
- map->setCollisionAt(i, j, EMPTY);
+ map->setTileAt(0, Position<int>{i, j}, 1);
+ map->setCollisionAt(Position<int>{i, j}, CollisionType::EMPTY);
}
else {
- map->setTileAt(0, i, j, 0);
+ map->setTileAt(0, Position<int>{i, j}, 0);
}
if (4 <= i && i < 12 && j == 8)
- map->setTileAt(1, i, j, 2);
+ map->setTileAt(1, Position<int>{i, j}, 2);
else
- map->setTileAt(1, i, j, 0);
+ map->setTileAt(1, Position<int>{i, j}, 0);
}
}
diff --git a/src/model/Map.hpp b/src/model/Map.hpp
index 4e434b1..0343709 100644
--- a/src/model/Map.hpp
+++ b/src/model/Map.hpp
@@ -30,6 +30,7 @@
#include <memory>
#include <stdexcept>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include "CollisionType.hpp"
@@ -68,12 +69,27 @@ private:
};
std::vector<std::unique_ptr<Entity>> entities;
+ std::unordered_map<Position<int>, std::unordered_set<Entity *>> positions;
std::unordered_map<const Entity *, EntityState> entityStates;
+ void addEntityPosition(const Position<int> &position, Entity *entity) {
+ positions[position].insert(entity);
+ }
+
+ void removeEntityPosition(const Position<int> &position, Entity *entity) {
+ auto it = positions.find(position);
+ it->second.erase(entity);
+
+ if (it->second.empty())
+ positions.erase(it);
+ }
+
+
void pushEntity(Entity *entity, EntityState &&state) {
entities.push_back(std::unique_ptr<Entity>(entity));
- entityStates.emplace(entity, state);
+ addEntityPosition(state.position, entity);
+ entityStates.emplace(entity, std::move(state));
}
void copyEntities(const Map &other) {
@@ -81,6 +97,37 @@ private:
pushEntity(new Entity(*e), EntityState(other.entityStates.at(e.get())));
}
+ bool hasTransitionTo(const Position<int> &p, Direction dir) const {
+ auto it = positions.find(p+dir);
+ if (it == positions.end())
+ return false;
+
+ for (const Entity *entity : it->second) {
+ const EntityState &state = entityStates.at(entity);
+
+ if (state.transitionEnd && (state.direction == -dir))
+ return true;
+ }
+
+ return false;
+ }
+
+ bool hasTransitionTo(const Position<int> &p) const {
+ if (hasTransitionTo(p, Direction::NORTH))
+ return true;
+
+ if (hasTransitionTo(p, Direction::EAST))
+ return true;
+
+ if (hasTransitionTo(p, Direction::SOUTH))
+ return true;
+
+ if (hasTransitionTo(p, Direction::WEST))
+ return true;
+
+ return false;
+ }
+
Map(size_t width0, size_t height0, size_t layers) : _Map(width0, height0, layers) {
}
@@ -126,7 +173,6 @@ public:
Entity * addEntity(const std::string &name, const Position<int> &pos) {
Entity *e = new Entity(name);
pushEntity(e, EntityState(pos));
- setCollisionAt(pos.x, pos.y, BLOCKED);
return e;
}
@@ -142,33 +188,39 @@ public:
return tiles.size();
}
- void setCollisionAt(size_t x, size_t y, CollisionType value) {
- if (x >= width || y >= height)
+ void setCollisionAt(const Position<int> &p, CollisionType value) {
+ if (p.x < 0 || size_t(p.x) >= width || p.y < 0 || size_t(p.y) >= height)
throw std::range_error("Map::setCollisionAt: bad coordinates");
- collision[y*width + x] = value;
+ collision[p.y*width + p.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;
+ bool isBlocked(const Position<int> &p) const {
+ if (p.x < 0 || size_t(p.x) >= width || p.y < 0 || size_t(p.y) >= height)
+ return true;
+
+ if (positions.find(p) != positions.end())
+ return true;
+
+ if (hasTransitionTo(p))
+ return true;
- return collision[y*width + x];
+ return collision[p.y*width + p.x] == CollisionType::BLOCKED;
}
- void setTileAt(size_t layer, size_t x, size_t y, uint32_t value) {
- if (layer >= tiles.size() || x >= width || y >= height)
+ void setTileAt(size_t layer, const Position<int> &p, uint32_t value) {
+ if (layer >= tiles.size() || p.x < 0 || size_t(p.x) >= width || p.y < 0 || size_t(p.y) >= height)
throw std::range_error("Map::setTileAt: bad coordinates");
- tiles[layer][y*width + x] = value;
+ tiles[layer][p.y*width + p.x] = value;
}
- uint32_t getTileAt(size_t layer, ssize_t x, ssize_t y) const {
- if (layer >= tiles.size() || x < 0 || (size_t)x >= width || y < 0 || (size_t)y >= height)
+ uint32_t getTileAt(size_t layer, const Position<int> &p) const {
+ if (layer >= tiles.size() || p.x < 0 || size_t(p.x) >= width || p.y < 0 || size_t(p.y) >= height)
return 0;
- return tiles[layer][y*width + x];
+ return tiles[layer][p.y*width + p.x];
}
Position<float> getEntityPosition(const Entity *entity, uint64_t time) const;
diff --git a/src/model/Position.hpp b/src/model/Position.hpp
index a88c151..c8fc477 100644
--- a/src/model/Position.hpp
+++ b/src/model/Position.hpp
@@ -28,6 +28,8 @@
#include "Direction.hpp"
+#include <functional>
+
namespace RPGEdit {
@@ -41,19 +43,19 @@ struct Position {
Position p = *this;
switch (dir) {
- case NORTH:
+ case Direction::NORTH:
p.y -= amount;
break;
- case EAST:
+ case Direction::EAST:
p.x += amount;
break;
- case SOUTH:
+ case Direction::SOUTH:
p.y += amount;
break;
- case WEST:
+ case Direction::WEST:
p.x -= amount;
}
@@ -64,6 +66,10 @@ struct Position {
return translate(dir, 1);
}
+ bool operator==(const Position<T> &p) const {
+ return (x == p.x) && (y == p.y);
+ }
+
template<typename T2>
explicit operator Position<T2>() const {
return Position<T2>{T2(x), T2(y)};
@@ -73,3 +79,20 @@ struct Position {
}
}
+
+namespace std {
+template<typename T> struct hash<RPGEdit::Model::Position<T>> {
+ typedef size_t result_type;
+ typedef RPGEdit::Model::Position<T> argument_type;
+
+ size_t operator()(const RPGEdit::Model::Position<T> &pos) const noexcept {
+ const int shift = 4*sizeof(size_t); // half the bit count of size_t
+
+ std::hash<T> hash;
+ size_t hash1 = hash(pos.x), hash2 = hash(pos.y);
+
+ return hash1 ^ ((hash2 << shift) | (hash2 >> shift));
+ }
+};
+
+}
diff --git a/src/view/MapView.cpp b/src/view/MapView.cpp
index 287fc87..78bc24c 100644
--- a/src/view/MapView.cpp
+++ b/src/view/MapView.cpp
@@ -113,7 +113,7 @@ void MapView::render(const Model::Map *map, Model::Position<float> center, uint6
for (size_t layer = 0; layer < map->getLayerCount(); layer++) {
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
- uint32_t tile = map->getTileAt(layer, x, y);
+ uint32_t tile = map->getTileAt(layer, Model::Position<int>{x, y});
if (!tile)
continue;
@@ -141,7 +141,7 @@ void MapView::render(const Model::Map *map, Model::Position<float> center, uint6
Model::Direction dir = entity->getDirection();
SDL_Rect src = {
- .x = getTileSize()*dir,
+ .x = getTileSize()*int(dir),
.y = 0,
.w = getTileSize(),
.h = getTileSize(),