diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/entity.h | 3 | ||||
| -rw-r--r-- | src/grid_cache.h | 59 | ||||
| -rw-r--r-- | src/level.h | 2 | ||||
| -rw-r--r-- | src/main.cpp | 27 | ||||
| -rw-r--r-- | src/schedule.h | 44 | ||||
| -rw-r--r-- | src/simulation.cpp | 128 | ||||
| -rw-r--r-- | src/simulation.h | 13 |
7 files changed, 213 insertions, 63 deletions
| diff --git a/src/entity.h b/src/entity.h index b606b43..a69c612 100644 --- a/src/entity.h +++ b/src/entity.h | |||
| @@ -21,6 +21,7 @@ public: | |||
| 21 | vec2s destPos; | 21 | vec2s destPos; |
| 22 | double movementTween = 0.0; | 22 | double movementTween = 0.0; |
| 23 | double speed = 0.0; // Tiles per second | 23 | double speed = 0.0; // Tiles per second |
| 24 | Direction moveDir = Direction::none; | ||
| 24 | 25 | ||
| 25 | // Player | 26 | // Player |
| 26 | bool controllable = false; | 27 | bool controllable = false; |
| @@ -32,6 +33,8 @@ public: | |||
| 32 | // Temp | 33 | // Temp |
| 33 | int colorVal = 25; | 34 | int colorVal = 25; |
| 34 | 35 | ||
| 36 | bool scheduled = false; | ||
| 37 | |||
| 35 | }; | 38 | }; |
| 36 | 39 | ||
| 37 | #endif /* end of include guard: ENTITY_H_0D6CB29A */ | 40 | #endif /* end of include guard: ENTITY_H_0D6CB29A */ |
| diff --git a/src/grid_cache.h b/src/grid_cache.h new file mode 100644 index 0000000..e837f55 --- /dev/null +++ b/src/grid_cache.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | #ifndef GRID_CACHE_H_67BBE74D | ||
| 2 | #define GRID_CACHE_H_67BBE74D | ||
| 3 | |||
| 4 | #include <unordered_map> | ||
| 5 | #include <unordered_set> | ||
| 6 | #include "level.h" | ||
| 7 | |||
| 8 | template <typename T> | ||
| 9 | class GridCache { | ||
| 10 | public: | ||
| 11 | |||
| 12 | explicit GridCache(const Level& level) : width_(level.getSize().w()) | ||
| 13 | { | ||
| 14 | } | ||
| 15 | |||
| 16 | void set(T value, vec2s pos) | ||
| 17 | { | ||
| 18 | if (reverse_.count(value)) | ||
| 19 | { | ||
| 20 | size_t oldPosIndex = reverse_.at(value); | ||
| 21 | lookup_[oldPosIndex].erase(value); | ||
| 22 | } | ||
| 23 | |||
| 24 | size_t newPosIndex = getIndex(pos); | ||
| 25 | lookup_[newPosIndex].insert(value); | ||
| 26 | reverse_[value] = newPosIndex; | ||
| 27 | } | ||
| 28 | |||
| 29 | void remove(T value) | ||
| 30 | { | ||
| 31 | if (reverse_.count(value)) | ||
| 32 | { | ||
| 33 | size_t index = reverse_.at(value); | ||
| 34 | lookup_[index].erase(value); | ||
| 35 | reverse_.erase(value); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | const std::unordered_set<T>& at(vec2s pos) const | ||
| 40 | { | ||
| 41 | size_t index = getIndex(pos); | ||
| 42 | |||
| 43 | return lookup_[index]; | ||
| 44 | } | ||
| 45 | |||
| 46 | private: | ||
| 47 | |||
| 48 | inline size_t getIndex(const vec2s& pos) const | ||
| 49 | { | ||
| 50 | return pos.x() + pos.y() * width_; | ||
| 51 | } | ||
| 52 | |||
| 53 | size_t width_; | ||
| 54 | |||
| 55 | mutable std::unordered_map<size_t, std::unordered_set<T>> lookup_; | ||
| 56 | std::unordered_map<T, size_t> reverse_; | ||
| 57 | }; | ||
| 58 | |||
| 59 | #endif /* end of include guard: GRID_CACHE_H_67BBE74D */ | ||
| diff --git a/src/level.h b/src/level.h index 6224c15..1ca4970 100644 --- a/src/level.h +++ b/src/level.h | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #ifndef LEVEL_H_678CFCCF | 1 | #ifndef LEVEL_H_678CFCCF |
| 2 | #define LEVEL_H_678CFCCF | 2 | #define LEVEL_H_678CFCCF |
| 3 | 3 | ||
| 4 | #include <vector> | ||
| 5 | #include "vector.h" | ||
| 4 | #include "consts.h" | 6 | #include "consts.h" |
| 5 | #include "tileset.h" | 7 | #include "tileset.h" |
| 6 | 8 | ||
| diff --git a/src/main.cpp b/src/main.cpp index c77d25b..c0ba15f 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -13,33 +13,6 @@ int main(int, char**) | |||
| 13 | Level level; | 13 | Level level; |
| 14 | Simulation sim(level); | 14 | Simulation sim(level); |
| 15 | 15 | ||
| 16 | Simulation::id_type player = sim.emplaceEntity(); | ||
| 17 | Entity& entity = sim.getEntity(player); | ||
| 18 | entity.size = TILE_SIZE; | ||
| 19 | entity.speed = 3.0; | ||
| 20 | entity.controllable = true; | ||
| 21 | entity.colliderType = ColliderType::player; | ||
| 22 | entity.colorVal = 180; | ||
| 23 | sim.setGridPos(player, vec2s { 1, 5 } ); | ||
| 24 | |||
| 25 | Simulation::id_type crateId = sim.emplaceEntity(); | ||
| 26 | Entity& crate = sim.getEntity(crateId); | ||
| 27 | crate.size = TILE_SIZE; | ||
| 28 | crate.speed = 4.0; | ||
| 29 | crate.colliderType = ColliderType::crate; | ||
| 30 | crate.canBePushedBy.insert(ColliderType::player); | ||
| 31 | crate.canBePushedBy.insert(ColliderType::crate); | ||
| 32 | sim.setGridPos(crateId, vec2s { 4, 5 } ); | ||
| 33 | |||
| 34 | Simulation::id_type crateId2 = sim.emplaceEntity(); | ||
| 35 | Entity& crate2 = sim.getEntity(crateId2); | ||
| 36 | crate2.size = TILE_SIZE; | ||
| 37 | crate2.speed = 4.0; | ||
| 38 | crate2.colliderType = ColliderType::crate; | ||
| 39 | crate2.canBePushedBy.insert(ColliderType::player); | ||
| 40 | crate2.canBePushedBy.insert(ColliderType::crate); | ||
| 41 | sim.setGridPos(crateId2, vec2s { 6, 7 } ); | ||
| 42 | |||
| 43 | bool quit = false; | 16 | bool quit = false; |
| 44 | 17 | ||
| 45 | SDL_Event e; | 18 | SDL_Event e; |
| diff --git a/src/schedule.h b/src/schedule.h new file mode 100644 index 0000000..5d77761 --- /dev/null +++ b/src/schedule.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #ifndef SCHEDULE_H_EF7B9D12 | ||
| 2 | #define SCHEDULE_H_EF7B9D12 | ||
| 3 | |||
| 4 | class Schedule { | ||
| 5 | public: | ||
| 6 | |||
| 7 | explicit Schedule( | ||
| 8 | size_t bpm) : | ||
| 9 | bpm_(bpm), | ||
| 10 | tick_(60.0 / static_cast<double>(bpm_)) | ||
| 11 | { | ||
| 12 | } | ||
| 13 | |||
| 14 | size_t getBPM() const | ||
| 15 | { | ||
| 16 | return bpm_; | ||
| 17 | } | ||
| 18 | |||
| 19 | void accumulate(double dt) | ||
| 20 | { | ||
| 21 | accum_ += dt; | ||
| 22 | } | ||
| 23 | |||
| 24 | bool step() | ||
| 25 | { | ||
| 26 | if (accum_ > tick_) | ||
| 27 | { | ||
| 28 | accum_ -= tick_; | ||
| 29 | |||
| 30 | return true; | ||
| 31 | } else { | ||
| 32 | return false; | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | private: | ||
| 37 | |||
| 38 | size_t bpm_; | ||
| 39 | double tick_; | ||
| 40 | double accum_ = 0.0; | ||
| 41 | |||
| 42 | }; | ||
| 43 | |||
| 44 | #endif /* end of include guard: SCHEDULE_H_EF7B9D12 */ | ||
| diff --git a/src/simulation.cpp b/src/simulation.cpp index 912f7f0..1379c34 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp | |||
| @@ -3,15 +3,68 @@ | |||
| 3 | #include "consts.h" | 3 | #include "consts.h" |
| 4 | #include "level.h" | 4 | #include "level.h" |
| 5 | 5 | ||
| 6 | Simulation::Simulation( | ||
| 7 | const Level& level) : | ||
| 8 | level_(level) | ||
| 9 | { | ||
| 10 | id_type player = emplaceEntity(); | ||
| 11 | Entity& entity = getEntity(player); | ||
| 12 | entity.size = TILE_SIZE; | ||
| 13 | entity.speed = 3.0; | ||
| 14 | entity.controllable = true; | ||
| 15 | entity.colliderType = ColliderType::player; | ||
| 16 | entity.colorVal = 180; | ||
| 17 | entity.gridPos = vec2s { 1, 5 }; | ||
| 18 | |||
| 19 | id_type crateId = emplaceEntity(); | ||
| 20 | Entity& crate = getEntity(crateId); | ||
| 21 | crate.size = TILE_SIZE; | ||
| 22 | crate.speed = static_cast<double>(schedule_.getBPM()) / 30.0; | ||
| 23 | crate.colliderType = ColliderType::crate; | ||
| 24 | crate.canBePushedBy.insert(ColliderType::player); | ||
| 25 | crate.canBePushedBy.insert(ColliderType::crate); | ||
| 26 | crate.canBePushedBy.insert(ColliderType::train); | ||
| 27 | crate.gridPos = vec2s { 4, 5 }; | ||
| 28 | |||
| 29 | id_type crateId2 = emplaceEntity(); | ||
| 30 | Entity& crate2 = getEntity(crateId2); | ||
| 31 | crate2.size = TILE_SIZE; | ||
| 32 | crate2.speed = static_cast<double>(schedule_.getBPM()) / 30.0; | ||
| 33 | crate2.colliderType = ColliderType::crate; | ||
| 34 | crate2.canBePushedBy.insert(ColliderType::player); | ||
| 35 | crate2.canBePushedBy.insert(ColliderType::crate); | ||
| 36 | crate2.canBePushedBy.insert(ColliderType::train); | ||
| 37 | crate2.gridPos = vec2s { 6, 7 }; | ||
| 38 | |||
| 39 | id_type trainId = emplaceEntity(); | ||
| 40 | Entity& train = getEntity(trainId); | ||
| 41 | train.size = TILE_SIZE; | ||
| 42 | train.speed = static_cast<double>(schedule_.getBPM()) / 30.0; | ||
| 43 | train.colliderType = ColliderType::train; | ||
| 44 | train.scheduled = true; | ||
| 45 | train.colorVal = 90; | ||
| 46 | train.gridPos = vec2s { 6, 1 }; | ||
| 47 | |||
| 48 | |||
| 49 | |||
| 50 | |||
| 51 | for (id_type id : active_) | ||
| 52 | { | ||
| 53 | Entity& entity = entities_.at(id); | ||
| 54 | |||
| 55 | posCache_.set(id, entity.gridPos); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 6 | void Simulation::tick( | 59 | void Simulation::tick( |
| 7 | double dt, | 60 | double dt, |
| 8 | const Uint8* keystate) | 61 | const Uint8* keystate) |
| 9 | { | 62 | { |
| 63 | // Control | ||
| 10 | for (id_type id : active_) | 64 | for (id_type id : active_) |
| 11 | { | 65 | { |
| 12 | Entity& entity = entities_.at(id); | 66 | Entity& entity = entities_.at(id); |
| 13 | 67 | ||
| 14 | // Control | ||
| 15 | if (entity.controllable && | 68 | if (entity.controllable && |
| 16 | !entity.moving) | 69 | !entity.moving) |
| 17 | { | 70 | { |
| @@ -38,7 +91,7 @@ void Simulation::tick( | |||
| 38 | 91 | ||
| 39 | vec2s lookPos = posInDir(entity.gridPos, lookDir); | 92 | vec2s lookPos = posInDir(entity.gridPos, lookDir); |
| 40 | 93 | ||
| 41 | for (id_type blockId : getGridEntities(lookPos)) | 94 | for (id_type blockId : posCache_.at(lookPos)) |
| 42 | { | 95 | { |
| 43 | Entity& block = entities_.at(blockId); | 96 | Entity& block = entities_.at(blockId); |
| 44 | 97 | ||
| @@ -79,16 +132,40 @@ void Simulation::tick( | |||
| 79 | } | 132 | } |
| 80 | } | 133 | } |
| 81 | } | 134 | } |
| 135 | } | ||
| 136 | |||
| 137 | // Schedule | ||
| 138 | schedule_.accumulate(dt); | ||
| 139 | |||
| 140 | if (schedule_.step()) | ||
| 141 | { | ||
| 142 | for (id_type id : active_) | ||
| 143 | { | ||
| 144 | Entity& entity = entities_.at(id); | ||
| 145 | |||
| 146 | if (entity.scheduled && !entity.moving) | ||
| 147 | { | ||
| 148 | moveEntityOnGrid(id, Direction::down); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 82 | 153 | ||
| 83 | 154 | ||
| 84 | 155 | ||
| 85 | 156 | ||
| 86 | // Collision | ||
| 87 | 157 | ||
| 88 | 158 | ||
| 159 | // Collision | ||
| 89 | 160 | ||
| 90 | 161 | ||
| 91 | // Movement | 162 | |
| 163 | |||
| 164 | // Movement | ||
| 165 | for (id_type id : active_) | ||
| 166 | { | ||
| 167 | Entity& entity = entities_.at(id); | ||
| 168 | |||
| 92 | if (entity.moving) | 169 | if (entity.moving) |
| 93 | { | 170 | { |
| 94 | entity.movementTween += entity.speed * dt; | 171 | entity.movementTween += entity.speed * dt; |
| @@ -96,7 +173,9 @@ void Simulation::tick( | |||
| 96 | if (entity.movementTween >= 1.0) | 173 | if (entity.movementTween >= 1.0) |
| 97 | { | 174 | { |
| 98 | entity.moving = false; | 175 | entity.moving = false; |
| 99 | setGridPos(id, entity.destPos); | 176 | entity.gridPos = entity.destPos; |
| 177 | posCache_.set(id, entity.gridPos); | ||
| 178 | moveToCache_.remove(id); | ||
| 100 | } | 179 | } |
| 101 | } | 180 | } |
| 102 | 181 | ||
| @@ -141,29 +220,6 @@ void Simulation::deleteEntity(id_type id) | |||
| 141 | active_.erase(id); | 220 | active_.erase(id); |
| 142 | } | 221 | } |
| 143 | 222 | ||
| 144 | void Simulation::setGridPos(id_type id, vec2s pos) | ||
| 145 | { | ||
| 146 | Entity& entity = entities_.at(id); | ||
| 147 | |||
| 148 | size_t oldPosIndex = | ||
| 149 | entity.gridPos.x() + entity.gridPos.y() * level_.getSize().w(); | ||
| 150 | gridCache_[oldPosIndex].erase(id); | ||
| 151 | |||
| 152 | entity.gridPos = pos; | ||
| 153 | |||
| 154 | size_t newPosIndex = | ||
| 155 | entity.gridPos.x() + entity.gridPos.y() * level_.getSize().w(); | ||
| 156 | gridCache_[newPosIndex].insert(id); | ||
| 157 | } | ||
| 158 | |||
| 159 | const std::unordered_set<Simulation::id_type>& | ||
| 160 | Simulation::getGridEntities(vec2s pos) const | ||
| 161 | { | ||
| 162 | size_t posIndex = pos.x() + pos.y() * level_.getSize().w(); | ||
| 163 | |||
| 164 | return gridCache_[posIndex]; | ||
| 165 | } | ||
| 166 | |||
| 167 | bool Simulation::moveEntityOnGrid( | 223 | bool Simulation::moveEntityOnGrid( |
| 168 | id_type id, | 224 | id_type id, |
| 169 | Direction moveDir, | 225 | Direction moveDir, |
| @@ -225,7 +281,13 @@ bool Simulation::moveEntityOnGrid( | |||
| 225 | return false; | 281 | return false; |
| 226 | } | 282 | } |
| 227 | 283 | ||
| 228 | for (id_type blockId : getGridEntities(shouldMoveTo)) | 284 | // Can't move into a space that something else is already moving into. |
| 285 | if (!moveToCache_.at(shouldMoveTo).empty()) | ||
| 286 | { | ||
| 287 | return false; | ||
| 288 | } | ||
| 289 | |||
| 290 | for (id_type blockId : posCache_.at(shouldMoveTo)) | ||
| 229 | { | 291 | { |
| 230 | Entity& block = entities_.at(blockId); | 292 | Entity& block = entities_.at(blockId); |
| 231 | 293 | ||
| @@ -240,6 +302,11 @@ bool Simulation::moveEntityOnGrid( | |||
| 240 | { | 302 | { |
| 241 | return false; | 303 | return false; |
| 242 | } | 304 | } |
| 305 | } else if (block.moveDir != moveDir) | ||
| 306 | { | ||
| 307 | // Can't move perpendicularly into a space that something else is moving | ||
| 308 | // out of. | ||
| 309 | return false; | ||
| 243 | } | 310 | } |
| 244 | 311 | ||
| 245 | double entityTimeLeft = 1.0 / entity.speed; | 312 | double entityTimeLeft = 1.0 / entity.speed; |
| @@ -260,6 +327,9 @@ bool Simulation::moveEntityOnGrid( | |||
| 260 | entity.moving = true; | 327 | entity.moving = true; |
| 261 | entity.destPos = shouldMoveTo; | 328 | entity.destPos = shouldMoveTo; |
| 262 | entity.movementTween = 0.0; | 329 | entity.movementTween = 0.0; |
| 330 | entity.moveDir = moveDir; | ||
| 331 | |||
| 332 | moveToCache_.set(id, entity.destPos); | ||
| 263 | } | 333 | } |
| 264 | 334 | ||
| 265 | return true; | 335 | return true; |
| diff --git a/src/simulation.h b/src/simulation.h index 4d41b49..f86d513 100644 --- a/src/simulation.h +++ b/src/simulation.h | |||
| @@ -3,11 +3,11 @@ | |||
| 3 | 3 | ||
| 4 | #include "entity.h" | 4 | #include "entity.h" |
| 5 | #include "renderer.h" | 5 | #include "renderer.h" |
| 6 | #include "schedule.h" | ||
| 7 | #include "grid_cache.h" | ||
| 6 | #include <vector> | 8 | #include <vector> |
| 7 | #include <deque> | 9 | #include <deque> |
| 8 | #include <set> | 10 | #include <set> |
| 9 | #include <unordered_map> | ||
| 10 | #include <unordered_set> | ||
| 11 | 11 | ||
| 12 | class Level; | 12 | class Level; |
| 13 | 13 | ||
| @@ -17,7 +17,7 @@ public: | |||
| 17 | using id_type = std::vector<Entity>::size_type; | 17 | using id_type = std::vector<Entity>::size_type; |
| 18 | 18 | ||
| 19 | // Constructor | 19 | // Constructor |
| 20 | explicit Simulation(const Level& level) : level_(level) {} | 20 | explicit Simulation(const Level& level); |
| 21 | 21 | ||
| 22 | void tick( | 22 | void tick( |
| 23 | double dt, | 23 | double dt, |
| @@ -47,15 +47,12 @@ public: | |||
| 47 | return level_; | 47 | return level_; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | void setGridPos(id_type id, vec2s pos); | ||
| 51 | |||
| 52 | static vec2s posInDir(vec2s orig, Direction dir); | 50 | static vec2s posInDir(vec2s orig, Direction dir); |
| 53 | 51 | ||
| 54 | private: | 52 | private: |
| 55 | 53 | ||
| 56 | 54 | ||
| 57 | 55 | ||
| 58 | const std::unordered_set<id_type>& getGridEntities(vec2s pos) const; | ||
| 59 | 56 | ||
| 60 | bool moveEntityOnGrid( | 57 | bool moveEntityOnGrid( |
| 61 | id_type id, | 58 | id_type id, |
| @@ -63,12 +60,14 @@ private: | |||
| 63 | bool validate = false); | 60 | bool validate = false); |
| 64 | 61 | ||
| 65 | const Level& level_; | 62 | const Level& level_; |
| 63 | Schedule schedule_ { 120 }; | ||
| 66 | 64 | ||
| 67 | std::vector<Entity> entities_; | 65 | std::vector<Entity> entities_; |
| 68 | std::deque<id_type> available_; | 66 | std::deque<id_type> available_; |
| 69 | std::set<id_type> active_; | 67 | std::set<id_type> active_; |
| 70 | 68 | ||
| 71 | mutable std::unordered_map<size_t, std::unordered_set<id_type>> gridCache_; | 69 | mutable GridCache<id_type> posCache_ { level_ }; |
| 70 | mutable GridCache<id_type> moveToCache_ { level_ }; | ||
| 72 | }; | 71 | }; |
| 73 | 72 | ||
| 74 | #endif /* end of include guard: SIMULATION_H_7BF6EEA4 */ | 73 | #endif /* end of include guard: SIMULATION_H_7BF6EEA4 */ |
