diff options
-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 */ |