summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/entity.h3
-rw-r--r--src/grid_cache.h59
-rw-r--r--src/level.h2
-rw-r--r--src/main.cpp27
-rw-r--r--src/schedule.h44
-rw-r--r--src/simulation.cpp128
-rw-r--r--src/simulation.h13
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
8template <typename T>
9class GridCache {
10public:
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
46private:
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
4class Schedule {
5public:
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
36private:
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
6Simulation::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
6void Simulation::tick( 59void 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
144void 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
159const 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
167bool Simulation::moveEntityOnGrid( 223bool 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
12class Level; 12class 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
54private: 52private:
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 */