Move external entity state from Entity to Map

This commit is contained in:
Matthias Schiffer 2014-09-25 20:53:17 +02:00
parent eb40e3de72
commit d82f3b7665
10 changed files with 177 additions and 111 deletions

View file

@ -5,7 +5,6 @@ add_executable(rpgedit
rpgedit.cpp rpgedit.cpp
control/MapContext.cpp control/MapContext.cpp
control/RPGEdit.cpp control/RPGEdit.cpp
model/Entity.cpp
model/Map.cpp model/Map.cpp
view/MapView.cpp view/MapView.cpp
view/SpriteCache.cpp view/SpriteCache.cpp

View file

@ -35,9 +35,7 @@ MapContext::MapContext(EventBus *eventBus0, InputHandler *inputHandler0, const s
: eventBus(eventBus0), inputHandler(inputHandler0), map(map0) { : eventBus(eventBus0), inputHandler(inputHandler0), map(map0) {
view = std::unique_ptr<View::MapView>(new View::MapView(window, map.getTileset())); view = std::unique_ptr<View::MapView>(new View::MapView(window, map.getTileset()));
map.getEntities().emplace_back("square"); playerEntity = map.addEntity("square", Model::Position{8, 8});
playerEntity = &map.getEntities().back();
playerEntity->moveTo(&map, Model::Position{8, 8});
view->updateEntities(map.getEntities()); 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) { 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; return;
eventBus->enqueue( eventBus->enqueue(
[=] { [=] {
playerEntity->finishTransition(&map); map.finishEntityTransition(playerEntity);
movePlayerContinue(time+250); movePlayerContinue(time+250);
}, },
time+250 time+250

View file

@ -54,7 +54,7 @@ private:
void keyPressed(uint16_t key, uint64_t time); void keyPressed(uint16_t key, uint64_t time);
Model::Position getViewPosition(uint64_t time) { Model::Position getViewPosition(uint64_t time) {
return playerEntity->getPosition(time); return map.getEntityPosition(playerEntity, time);
} }
public: public:

View file

@ -24,44 +24,17 @@
*/ */
#include "Entity.hpp" #pragma once
#include "Map.hpp"
namespace RPGEdit { namespace RPGEdit {
namespace Model { namespace Model {
bool Entity::move(Map *map, Direction dir, uint64_t start, uint64_t end) { enum CollisionType {
if (hasTransition()) BLOCKED = 0,
return false; EMPTY,
};
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));
}
} }

View file

@ -39,41 +39,12 @@ namespace RPGEdit {
namespace Model { namespace Model {
class Map;
class Entity { class Entity {
private: private:
const std::string name; std::string name;
Position pos;
Direction direction; 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: public:
Entity(const std::string &name0) Entity(const std::string &name0)
: name(name0), direction(NORTH) { : name(name0), direction(NORTH) {
@ -83,29 +54,13 @@ public:
return name; 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 { Direction getDirection() const {
return direction; return direction;
} }
bool hasTransition() const { void setDirection(Direction dir) {
return transitionEnd; direction = dir;
} }
void moveTo(Map *map, Position newPos);
bool move(Map *map, Direction dir, uint64_t start, uint64_t end);
void finishTransition(Map *map);
}; };
} }

View file

@ -31,6 +31,62 @@ namespace RPGEdit {
namespace Model { 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> Map::load(__attribute__((unused)) const std::string &name) { std::unique_ptr<Map> Map::load(__attribute__((unused)) const std::string &name) {
std::unique_ptr<Map> map(new Map(16, 16, 2)); std::unique_ptr<Map> map(new Map(16, 16, 2));
@ -54,8 +110,7 @@ std::unique_ptr<Map> Map::load(__attribute__((unused)) const std::string &name)
} }
} }
map->entities.emplace_back("square"); map->addEntity("square", Model::Position{6, 6});
map->entities.back().moveTo(map.get(), Model::Position{6, 6});
return map; return map;
} }

View file

@ -27,11 +27,12 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <deque>
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
#include <unordered_map>
#include <vector> #include <vector>
#include "CollisionType.hpp"
#include "Entity.hpp" #include "Entity.hpp"
@ -39,29 +40,77 @@ namespace RPGEdit {
namespace Model { namespace Model {
class Map { class _Map {
public: protected:
enum CollisionType {
BLOCKED = 0,
EMPTY,
};
private:
std::vector<std::string> tileset; std::vector<std::string> tileset;
size_t width, height; size_t width, height;
std::vector<CollisionType> collision; std::vector<CollisionType> collision;
std::vector<std::vector<uint32_t>> tiles; std::vector<std::vector<uint32_t>> tiles;
std::deque<Entity> 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) { : width(width0), height(height0), collision(width*height) {
for (size_t i = 0; i < layers; i++) for (size_t i = 0; i < layers; i++)
tiles.emplace_back(width*height); 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<std::unique_ptr<Entity>> entities;
std::unordered_map<const Entity *, EntityState> entityStates;
void pushEntity(Entity *entity, EntityState &&state) {
entities.push_back(std::unique_ptr<Entity>(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: 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<std::string> & getTileset() { std::vector<std::string> & getTileset() {
return tileset; return tileset;
} }
@ -70,12 +119,15 @@ public:
return tileset; return tileset;
} }
std::deque<Entity> & getEntities() { const std::vector<std::unique_ptr<Entity>> & getEntities() const {
return entities; return entities;
} }
const std::deque<Entity> & getEntities() const { Entity * addEntity(const std::string &name, const Position &pos) {
return entities; Entity *e = new Entity(name);
pushEntity(e, EntityState(pos));
setCollisionAt(pos.x, pos.y, BLOCKED);
return e;
} }
size_t getWidth() const { size_t getWidth() const {
@ -92,7 +144,7 @@ public:
void setCollisionAt(size_t x, size_t y, CollisionType value) { void setCollisionAt(size_t x, size_t y, CollisionType value) {
if (x >= width || y >= height) 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; collision[y*width + x] = value;
} }
@ -119,6 +171,11 @@ public:
return tiles[layer][y*width + x]; 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<Map> load(const std::string &name); static std::unique_ptr<Map> load(const std::string &name);
}; };

View file

@ -26,6 +26,8 @@
#pragma once #pragma once
#include "Direction.hpp"
namespace RPGEdit { namespace RPGEdit {
@ -33,6 +35,33 @@ namespace Model {
struct Position { struct Position {
float x, y; 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);
}
}; };
} }

View file

@ -76,11 +76,11 @@ MapView::~MapView() {
clearEntities(); clearEntities();
} }
void MapView::updateEntities(const std::deque<Model::Entity> &entities) { void MapView::updateEntities(const std::vector<std::unique_ptr<Model::Entity>> &entities) {
SpriteCache *spriteCache = window->getSpriteCache(); SpriteCache *spriteCache = window->getSpriteCache();
for (auto &entity : entities) { for (auto &entity : entities) {
const std::string &name = entity.getName(); const std::string &name = entity->getName();
if (!entitySprites[name]) if (!entitySprites[name])
entitySprites[name] = SDL_CreateTextureFromSurface(window->getRenderer(), spriteCache->get("entity", 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()) { for (auto &entity : map->getEntities()) {
Model::Position pos = entity.getPosition(time); Model::Position pos = map->getEntityPosition(entity.get(), time);
Model::Direction dir = entity.getDirection(); Model::Direction dir = entity->getDirection();
SDL_Rect src = { SDL_Rect src = {
.x = getTileSize()*dir, .x = getTileSize()*dir,
@ -154,7 +154,7 @@ void MapView::render(const Model::Map *map, Model::Position center, uint64_t tim
.h = tilePixels, .h = tilePixels,
}; };
SDL_RenderCopy(window->getRenderer(), entitySprites[entity.getName()], &src, &dst); SDL_RenderCopy(window->getRenderer(), entitySprites[entity->getName()], &src, &dst);
} }
} }

View file

@ -53,7 +53,7 @@ public:
MapView(const std::shared_ptr<Window> &window0, const std::vector<std::string> &tileset); MapView(const std::shared_ptr<Window> &window0, const std::vector<std::string> &tileset);
~MapView(); ~MapView();
void updateEntities(const std::deque<Model::Entity> &entities); void updateEntities(const std::vector<std::unique_ptr<Model::Entity>> &entities);
void clearEntities(); void clearEntities();
void clear(); void clear();