Move external entity state from Entity to Map
This commit is contained in:
parent
eb40e3de72
commit
d82f3b7665
10 changed files with 177 additions and 111 deletions
|
@ -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
|
||||
|
|
|
@ -35,9 +35,7 @@ MapContext::MapContext(EventBus *eventBus0, InputHandler *inputHandler0, const s
|
|||
: eventBus(eventBus0), inputHandler(inputHandler0), map(map0) {
|
||||
view = std::unique_ptr<View::MapView>(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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -24,44 +24,17 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "Entity.hpp"
|
||||
#include "Map.hpp"
|
||||
#pragma once
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
enum CollisionType {
|
||||
BLOCKED = 0,
|
||||
EMPTY,
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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> Map::load(__attribute__((unused)) const std::string &name) {
|
||||
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->entities.back().moveTo(map.get(), Model::Position{6, 6});
|
||||
map->addEntity("square", Model::Position{6, 6});
|
||||
|
||||
return map;
|
||||
}
|
||||
|
|
|
@ -27,11 +27,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#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<std::string> tileset;
|
||||
|
||||
size_t width, height;
|
||||
std::vector<CollisionType> collision;
|
||||
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) {
|
||||
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<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:
|
||||
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() {
|
||||
return tileset;
|
||||
}
|
||||
|
@ -70,12 +119,15 @@ public:
|
|||
return tileset;
|
||||
}
|
||||
|
||||
std::deque<Entity> & getEntities() {
|
||||
const std::vector<std::unique_ptr<Entity>> & getEntities() const {
|
||||
return entities;
|
||||
}
|
||||
|
||||
const std::deque<Entity> & 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<Map> load(const std::string &name);
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -76,11 +76,11 @@ MapView::~MapView() {
|
|||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
MapView(const std::shared_ptr<Window> &window0, const std::vector<std::string> &tileset);
|
||||
~MapView();
|
||||
|
||||
void updateEntities(const std::deque<Model::Entity> &entities);
|
||||
void updateEntities(const std::vector<std::unique_ptr<Model::Entity>> &entities);
|
||||
void clearEntities();
|
||||
|
||||
void clear();
|
||||
|
|
Reference in a new issue