summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/algorithms.h12
-rw-r--r--src/component.h7
-rw-r--r--src/components/ai.cpp142
-rw-r--r--src/components/ai.h73
-rw-r--r--src/components/animatable.cpp27
-rw-r--r--src/components/animatable.h31
-rw-r--r--src/components/controllable.cpp71
-rw-r--r--src/components/controllable.h36
-rw-r--r--src/components/droppable.cpp11
-rw-r--r--src/components/droppable.h15
-rw-r--r--src/components/map_collision.cpp241
-rw-r--r--src/components/map_collision.h47
-rw-r--r--src/components/map_render.cpp40
-rw-r--r--src/components/map_render.h19
-rw-r--r--src/components/physics_body.cpp66
-rw-r--r--src/components/physics_body.h20
-rw-r--r--src/components/player_physics.cpp118
-rw-r--r--src/components/player_physics.h25
-rw-r--r--src/components/player_sprite.cpp60
-rw-r--r--src/components/player_sprite.h23
-rw-r--r--src/components/ponderable.cpp41
-rw-r--r--src/components/ponderable.h24
-rw-r--r--src/components/simple_collider.cpp14
-rw-r--r--src/components/simple_collider.h18
-rw-r--r--src/components/static_image.cpp11
-rw-r--r--src/components/static_image.h18
-rw-r--r--src/components/transformable.cpp47
-rw-r--r--src/components/transformable.h27
-rw-r--r--src/components/user_movement.cpp100
-rw-r--r--src/components/user_movement.h19
-rw-r--r--src/consts.h3
-rw-r--r--src/direction.h11
-rw-r--r--src/entity.cpp46
-rw-r--r--src/entity.h64
-rw-r--r--src/entity_manager.cpp38
-rw-r--r--src/entity_manager.h152
-rw-r--r--src/entityfactory.cpp182
-rw-r--r--src/entityfactory.h15
-rw-r--r--src/game.cpp171
-rw-r--r--src/game.h51
-rw-r--r--src/main.cpp10
-rw-r--r--src/map.cpp151
-rw-r--r--src/map.h70
-rw-r--r--src/system.h17
-rw-r--r--src/system_manager.h37
-rw-r--r--src/systems/controlling.cpp168
-rw-r--r--src/systems/controlling.h26
-rw-r--r--src/systems/pondering.cpp23
-rw-r--r--src/systems/pondering.h14
-rw-r--r--src/systems/rendering.cpp21
-rw-r--r--src/systems/rendering.h19
-rw-r--r--src/world.cpp150
-rw-r--r--src/world.h21
53 files changed, 933 insertions, 1930 deletions
diff --git a/src/algorithms.h b/src/algorithms.h new file mode 100644 index 0000000..80e3e27 --- /dev/null +++ b/src/algorithms.h
@@ -0,0 +1,12 @@
1#ifndef ALGORITHMS_H_1DDC517E
2#define ALGORITHMS_H_1DDC517E
3
4template< typename ContainerT, typename PredicateT >
5void erase_if( ContainerT& items, const PredicateT& predicate ) {
6 for( auto it = items.begin(); it != items.end(); ) {
7 if( predicate(*it) ) it = items.erase(it);
8 else ++it;
9 }
10};
11
12#endif /* end of include guard: ALGORITHMS_H_1DDC517E */
diff --git a/src/component.h b/src/component.h new file mode 100644 index 0000000..2cbdc9d --- /dev/null +++ b/src/component.h
@@ -0,0 +1,7 @@
1#ifndef COMPONENT_H_F0CE4573
2#define COMPONENT_H_F0CE4573
3
4class Component {
5};
6
7#endif /* end of include guard: COMPONENT_H_F0CE4573 */
diff --git a/src/components/ai.cpp b/src/components/ai.cpp deleted file mode 100644 index 9f8c764..0000000 --- a/src/components/ai.cpp +++ /dev/null
@@ -1,142 +0,0 @@
1#include "ai.h"
2#include <cstdlib>
3#include "entity.h"
4
5void AIActionContainer::addAction(std::shared_ptr<AIAction> action)
6{
7 actions.push_back(action);
8}
9
10void AIActionContainer::start(Game& game, Entity& entity)
11{
12 currentAction = begin(actions);
13
14 if (currentAction != end(actions))
15 {
16 (*currentAction)->start(game, entity);
17 }
18}
19
20void AIActionContainer::perform(Game& game, Entity& entity, double dt)
21{
22 if (!isDone())
23 {
24 (*currentAction)->perform(game, entity, dt);
25
26 if ((*currentAction)->isDone())
27 {
28 currentAction++;
29
30 if (!isDone())
31 {
32 (*currentAction)->start(game, entity);
33 }
34 }
35 }
36}
37
38bool AIActionContainer::isDone() const
39{
40 return currentAction == end(actions);
41}
42
43AI::AI(int chance)
44{
45 this->chance = chance;
46}
47
48int AI::getChance() const
49{
50 return chance;
51}
52
53AI& AIComponent::emplaceAI(int chance)
54{
55 maxChance += chance;
56 ais.emplace_back(chance);
57
58 return ais.back();
59}
60
61void AIComponent::tick(Game& game, Entity& entity, double dt)
62{
63 if (currentAI == nullptr)
64 {
65 int toChoose = rand() % maxChance;
66 for (auto& ai : ais)
67 {
68 if (toChoose < ai.getChance())
69 {
70 currentAI = &ai;
71 break;
72 } else {
73 toChoose -= ai.getChance();
74 }
75 }
76
77 if (currentAI != nullptr)
78 {
79 currentAI->start(game, entity);
80 }
81 }
82
83 if (currentAI != nullptr)
84 {
85 currentAI->perform(game, entity, dt);
86
87 if (currentAI->isDone())
88 {
89 currentAI = nullptr;
90 }
91 }
92}
93
94MoveAIAction::MoveAIAction(Direction dir, int len, int speed)
95{
96 this->dir = dir;
97 this->len = len;
98 this->speed = speed;
99}
100
101void MoveAIAction::start(Game& game, Entity& entity)
102{
103 remaining = len;
104}
105
106void MoveAIAction::perform(Game&, Entity& entity, double dt)
107{
108 double dist = dt * speed;
109 remaining -= dist;
110
111 switch (dir)
112 {
113 case Direction::Left:
114 {
115 entity.position.first -= dist;
116 break;
117 }
118
119 case Direction::Right:
120 {
121 entity.position.first += dist;
122 break;
123 }
124
125 case Direction::Up:
126 {
127 entity.position.second -= dist;
128 break;
129 }
130
131 case Direction::Down:
132 {
133 entity.position.second += dist;
134 break;
135 }
136 }
137}
138
139bool MoveAIAction::isDone() const
140{
141 return remaining <= 0.0;
142}
diff --git a/src/components/ai.h b/src/components/ai.h deleted file mode 100644 index 840283b..0000000 --- a/src/components/ai.h +++ /dev/null
@@ -1,73 +0,0 @@
1#ifndef AI_H
2#define AI_H
3
4#include <list>
5#include <map>
6#include <string>
7#include <memory>
8
9#include "entity.h"
10
11class AIAction {
12 public:
13 virtual void start(Game& game, Entity& entity) = 0;
14 virtual void perform(Game& game, Entity& entity, double dt) = 0;
15 virtual bool isDone() const = 0;
16};
17
18class AIActionContainer {
19 public:
20 void addAction(std::shared_ptr<AIAction> action);
21 virtual void start(Game& game, Entity& entity);
22 virtual void perform(Game& game, Entity& entity, double dt);
23 virtual bool isDone() const;
24
25 private:
26 std::list<std::shared_ptr<AIAction>> actions;
27 std::list<std::shared_ptr<AIAction>>::iterator currentAction {end(actions)};
28};
29
30class AI : public AIActionContainer {
31 public:
32 AI(int chance);
33
34 int getChance() const;
35
36 private:
37 int chance;
38};
39
40class AIComponent : public Component {
41 public:
42 AI& emplaceAI(int chance);
43 void tick(Game& game, Entity& entity, double dt);
44
45 private:
46 int maxChance = 0;
47 std::list<AI> ais;
48 AI* currentAI = nullptr;
49};
50
51class MoveAIAction : public AIAction {
52 public:
53 enum class Direction {
54 Left,
55 Right,
56 Up,
57 Down
58 };
59
60 MoveAIAction(Direction dir, int len, int speed);
61
62 void start(Game& game, Entity& entity);
63 void perform(Game& game, Entity& entity, double dt);
64 bool isDone() const;
65
66 private:
67 Direction dir;
68 int len;
69 int speed;
70 double remaining;
71};
72
73#endif /* end of include guard: AI_H */
diff --git a/src/components/animatable.cpp b/src/components/animatable.cpp new file mode 100644 index 0000000..fcd277c --- /dev/null +++ b/src/components/animatable.cpp
@@ -0,0 +1,27 @@
1#include "animatable.h"
2
3AnimatableComponent::AnimatableComponent(const char* filename, int frame_width, int frame_height, int frames_across)
4 : texture(filename), frame_width(frame_width), frame_height(frame_height), frames_across(frames_across)
5{
6
7}
8
9int AnimatableComponent::getFrame() const
10{
11 return frame;
12}
13
14void AnimatableComponent::setFrame(int frame)
15{
16 this->frame = frame;
17}
18
19const Texture& AnimatableComponent::getTexture() const
20{
21 return texture;
22}
23
24Rectangle AnimatableComponent::getFrameRect() const
25{
26 return {frame_width * (frame % frames_across), frame_height * (frame / frames_across), frame_width, frame_height};
27}
diff --git a/src/components/animatable.h b/src/components/animatable.h new file mode 100644 index 0000000..cf6ee54 --- /dev/null +++ b/src/components/animatable.h
@@ -0,0 +1,31 @@
1#ifndef SPRITE_RENDERABLE_H_D3AACBBF
2#define SPRITE_RENDERABLE_H_D3AACBBF
3
4#include "component.h"
5#include "renderer.h"
6#include "direction.h"
7
8class AnimatableComponent : public Component {
9 public:
10 AnimatableComponent(const char* filename, int frame_width, int frame_height, int frames_across);
11
12 int getFrame() const;
13 void setFrame(int frame);
14
15 const Texture& getTexture() const;
16 Rectangle getFrameRect() const;
17
18 void setDirection(Direction dir) {};
19 void setWalking(bool w) {};
20 void setJumping(bool w) {};
21 void setCrouching(bool w) {};
22
23 private:
24 Texture texture;
25 int frame_width;
26 int frame_height;
27 int frames_across;
28 int frame = 0;
29};
30
31#endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */
diff --git a/src/components/controllable.cpp b/src/components/controllable.cpp new file mode 100644 index 0000000..a4d45f2 --- /dev/null +++ b/src/components/controllable.cpp
@@ -0,0 +1,71 @@
1#include "controllable.h"
2
3int ControllableComponent::getLeftKey() const
4{
5 return leftKey;
6}
7
8void ControllableComponent::setLeftKey(int k)
9{
10 leftKey = k;
11}
12
13int ControllableComponent::getRightKey() const
14{
15 return rightKey;
16}
17
18void ControllableComponent::setRightKey(int k)
19{
20 rightKey = k;
21}
22
23int ControllableComponent::getJumpKey() const
24{
25 return jumpKey;
26}
27
28void ControllableComponent::setJumpKey(int k)
29{
30 jumpKey = k;
31}
32
33int ControllableComponent::getDropKey() const
34{
35 return dropKey;
36}
37
38void ControllableComponent::setDropKey(int k)
39{
40 dropKey = k;
41}
42
43bool ControllableComponent::isFrozen() const
44{
45 return frozen;
46}
47
48void ControllableComponent::setFrozen(bool f)
49{
50 frozen = f;
51}
52
53bool ControllableComponent::isHoldingLeft() const
54{
55 return holdingLeft;
56}
57
58void ControllableComponent::setHoldingLeft(bool f)
59{
60 holdingLeft = f;
61}
62
63bool ControllableComponent::isHoldingRight() const
64{
65 return holdingRight;
66}
67
68void ControllableComponent::setHoldingRight(bool f)
69{
70 holdingRight = f;
71}
diff --git a/src/components/controllable.h b/src/components/controllable.h new file mode 100644 index 0000000..317d68d --- /dev/null +++ b/src/components/controllable.h
@@ -0,0 +1,36 @@
1#ifndef CONTROLLABLE_H_4E0B85B4
2#define CONTROLLABLE_H_4E0B85B4
3
4#include "component.h"
5#include "renderer.h"
6
7class ControllableComponent : public Component {
8 public:
9 int getLeftKey() const;
10 void setLeftKey(int k);
11 int getRightKey() const;
12 void setRightKey(int k);
13 int getJumpKey() const;
14 void setJumpKey(int k);
15 int getDropKey() const;
16 void setDropKey(int k);
17
18 bool isFrozen() const;
19 void setFrozen(bool f);
20 bool isHoldingLeft() const;
21 void setHoldingLeft(bool f);
22 bool isHoldingRight() const;
23 void setHoldingRight(bool f);
24
25 private:
26 int leftKey = GLFW_KEY_LEFT;
27 int rightKey = GLFW_KEY_RIGHT;
28 int jumpKey = GLFW_KEY_UP;
29 int dropKey = GLFW_KEY_DOWN;
30
31 bool frozen = false;
32 bool holdingLeft = false;
33 bool holdingRight = false;
34};
35
36#endif /* end of include guard: CONTROLLABLE_H_4E0B85B4 */
diff --git a/src/components/droppable.cpp b/src/components/droppable.cpp new file mode 100644 index 0000000..534fd9a --- /dev/null +++ b/src/components/droppable.cpp
@@ -0,0 +1,11 @@
1#include "droppable.h"
2
3void DroppableComponent::setDroppable(bool can)
4{
5 droppable = can;
6}
7
8bool DroppableComponent::isDroppable() const
9{
10 return droppable;
11}
diff --git a/src/components/droppable.h b/src/components/droppable.h new file mode 100644 index 0000000..1f5608b --- /dev/null +++ b/src/components/droppable.h
@@ -0,0 +1,15 @@
1#ifndef DROPPABLE_H_5DB254EF
2#define DROPPABLE_H_5DB254EF
3
4#include "component.h"
5
6class DroppableComponent : public Component {
7 public:
8 void setDroppable(bool can);
9 bool isDroppable() const;
10
11 private:
12 bool droppable = false;
13};
14
15#endif /* end of include guard: DROPPABLE_H_5DB254EF */
diff --git a/src/components/map_collision.cpp b/src/components/map_collision.cpp deleted file mode 100644 index 3ad574b..0000000 --- a/src/components/map_collision.cpp +++ /dev/null
@@ -1,241 +0,0 @@
1#include "map_collision.h"
2#include "map.h"
3#include "game.h"
4#include "consts.h"
5
6MapCollisionComponent::MapCollisionComponent(const Map& map) : map(map)
7{
8 addCollision(-6, 0, MAP_HEIGHT*TILE_HEIGHT, Direction::left, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Left).type));
9 addCollision(GAME_WIDTH+6, 0, MAP_HEIGHT*TILE_HEIGHT, Direction::right, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Right).type));
10 addCollision(-6, 0, GAME_WIDTH, Direction::up, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Up).type));
11 addCollision(MAP_HEIGHT*TILE_HEIGHT+6, 0, GAME_WIDTH, Direction::down, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Down).type));
12
13 for (int i=0; i<MAP_WIDTH*MAP_HEIGHT; i++)
14 {
15 int x = i % MAP_WIDTH;
16 int y = i / MAP_WIDTH;
17 int tile = map.getMapdata()[i];
18
19 if ((tile > 0) && (tile < 28) && (!((tile >= 5) && (tile <= 7))))
20 {
21 addCollision(x*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::right, Collision::Type::wall);
22 addCollision((x+1)*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::left, Collision::Type::wall);
23 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::wall);
24 addCollision((y+1)*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::up, Collision::Type::wall);
25 } else if ((tile >= 5) && (tile <= 7))
26 {
27 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::platform);
28 } else if (tile == 42)
29 {
30 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::danger);
31 }
32 }
33}
34
35void MapCollisionComponent::addCollision(double axis, double lower, double
36 upper, Direction dir, Collision::Type type)
37{
38 std::list<Collision>::iterator it;
39
40 switch (dir)
41 {
42 case Direction::up:
43 it = up_collisions.begin();
44 for (; it!=up_collisions.end(); it++)
45 {
46 if (it->axis < axis) break;
47 }
48
49 up_collisions.insert(it, {axis, lower, upper, type});
50
51 break;
52 case Direction::down:
53 it = down_collisions.begin();
54 for (; it!=down_collisions.end(); it++)
55 {
56 if (it->axis > axis) break;
57 }
58
59 down_collisions.insert(it, {axis, lower, upper, type});
60
61 break;
62 case Direction::left:
63 it = left_collisions.begin();
64 for (; it!=left_collisions.end(); it++)
65 {
66 if (it->axis < axis) break;
67 }
68
69 left_collisions.insert(it, {axis, lower, upper, type});
70
71 break;
72 case Direction::right:
73 it = right_collisions.begin();
74 for (; it!=right_collisions.end(); it++)
75 {
76 if (it->axis > axis) break;
77 }
78
79 right_collisions.insert(it, {axis, lower, upper, type});
80
81 break;
82 }
83}
84
85void MapCollisionComponent::detectCollision(Game& game, Entity&, Entity& collider, std::pair<double, double> old_position)
86{
87 if (collider.position.first < old_position.first)
88 {
89 for (auto collision : left_collisions)
90 {
91 if (collision.axis > old_position.first) continue;
92 if (collision.axis < collider.position.first) break;
93
94 if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper))
95 {
96 // We have a collision!
97 processCollision(game, collider, collision, Direction::left, old_position);
98
99 break;
100 }
101 }
102 } else if (collider.position.first > old_position.first)
103 {
104 for (auto collision : right_collisions)
105 {
106 if (collision.axis < old_position.first+collider.size.first) continue;
107 if (collision.axis > collider.position.first+collider.size.first) break;
108
109 if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper))
110 {
111 // We have a collision!
112 processCollision(game, collider, collision, Direction::right, old_position);
113
114 break;
115 }
116 }
117 }
118
119 if (collider.position.second < old_position.second)
120 {
121 for (auto collision : up_collisions)
122 {
123 if (collision.axis > old_position.second) continue;
124 if (collision.axis < collider.position.second) break;
125
126 if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper))
127 {
128 // We have a collision!
129 processCollision(game, collider, collision, Direction::up, old_position);
130
131 break;
132 }
133 }
134 } else if (collider.position.second > old_position.second)
135 {
136 for (auto collision : down_collisions)
137 {
138 if (collision.axis < old_position.second+collider.size.second) continue;
139 if (collision.axis > collider.position.second+collider.size.second) break;
140
141 if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper))
142 {
143 // We have a collision!
144 processCollision(game, collider, collision, Direction::down, old_position);
145
146 break;
147 }
148 }
149 }
150}
151
152void MapCollisionComponent::processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair<double, double> old_position)
153{
154 if (collision.type == Collision::Type::wall)
155 {
156 if (dir == Direction::left)
157 {
158 collider.position.first = collision.axis;
159
160 Message msg(Message::Type::setHorizontalVelocity);
161 msg.velocity = 0.0;
162 collider.send(game, msg);
163 } else if (dir == Direction::right)
164 {
165 collider.position.first = collision.axis - collider.size.first;
166
167 Message msg(Message::Type::setHorizontalVelocity);
168 msg.velocity = 0.0;
169 collider.send(game, msg);
170 } else if (dir == Direction::up)
171 {
172 collider.position.second = collision.axis;
173
174 Message msg(Message::Type::setVerticalVelocity);
175 msg.velocity = 0.0;
176 collider.send(game, msg);
177 } else if (dir == Direction::down)
178 {
179 collider.position.second = collision.axis - collider.size.second;
180 collider.send(game, Message::Type::hitTheGround);
181 }
182 } else if (collision.type == Collision::Type::wrap)
183 {
184 if (dir == Direction::left)
185 {
186 collider.position.first = GAME_WIDTH-collider.size.first/2;
187 } else if (dir == Direction::right)
188 {
189 collider.position.first = -collider.size.first/2;
190 } else if (dir == Direction::up)
191 {
192 collider.position.second = GAME_HEIGHT-collider.size.second/2-1;
193 } else if (dir == Direction::down)
194 {
195 collider.position.second = -collider.size.second/2;
196 }
197 } else if (collision.type == Collision::Type::teleport)
198 {
199 if (dir == Direction::left)
200 {
201 game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Left).map), std::make_pair(GAME_WIDTH-collider.size.first/2, old_position.second));
202 } else if (dir == Direction::right)
203 {
204 game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Right).map), std::make_pair(-collider.size.first/2, old_position.second));
205 } else if (dir == Direction::up)
206 {
207 game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Up).map), std::make_pair(old_position.first, MAP_HEIGHT*TILE_HEIGHT-collider.size.second/2));
208 } else if (dir == Direction::down)
209 {
210 game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Down).map), std::make_pair(old_position.first, -collider.size.second/2));
211 }
212 } else if (collision.type == Collision::Type::reverse)
213 {
214 // TODO reverse
215 if (dir == Direction::right)
216 {
217 collider.position.first = collision.axis - collider.size.first;
218 collider.send(game, Message::Type::walkLeft);
219 }
220 } else if (collision.type == Collision::Type::platform)
221 {
222 Message msg(Message::Type::drop);
223 msg.dropAxis = collision.axis;
224
225 collider.send(game, msg);
226 } else if (collision.type == Collision::Type::danger)
227 {
228 game.playerDie();
229 }
230}
231
232MapCollisionComponent::Collision::Type MapCollisionComponent::collisionFromMoveType(Map::MoveType type)
233{
234 switch (type)
235 {
236 case Map::MoveType::Wall: return Collision::Type::wall;
237 case Map::MoveType::Wrap: return Collision::Type::wrap;
238 case Map::MoveType::Warp: return Collision::Type::teleport;
239 case Map::MoveType::ReverseWarp: return Collision::Type::reverse;
240 }
241}
diff --git a/src/components/map_collision.h b/src/components/map_collision.h deleted file mode 100644 index 18b9397..0000000 --- a/src/components/map_collision.h +++ /dev/null
@@ -1,47 +0,0 @@
1#ifndef MAP_COLLISION_H
2#define MAP_COLLISION_H
3
4#include "entity.h"
5#include "map.h"
6#include <list>
7
8class Game;
9
10class MapCollisionComponent : public Component {
11 public:
12 MapCollisionComponent(const Map& map);
13 void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position);
14
15 private:
16 enum class Direction {
17 up, left, down, right
18 };
19
20 struct Collision {
21 enum class Type {
22 wall,
23 wrap,
24 teleport,
25 reverse,
26 platform,
27 danger
28 };
29
30 double axis;
31 double lower;
32 double upper;
33 Type type;
34 };
35
36 void addCollision(double axis, double lower, double upper, Direction dir, Collision::Type type);
37 void processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair<double, double> old_position);
38 Collision::Type collisionFromMoveType(Map::MoveType type);
39
40 std::list<Collision> left_collisions;
41 std::list<Collision> right_collisions;
42 std::list<Collision> up_collisions;
43 std::list<Collision> down_collisions;
44 const Map& map;
45};
46
47#endif
diff --git a/src/components/map_render.cpp b/src/components/map_render.cpp deleted file mode 100644 index 45766e1..0000000 --- a/src/components/map_render.cpp +++ /dev/null
@@ -1,40 +0,0 @@
1#include "map_render.h"
2#include "map.h"
3#include "game.h"
4#include "consts.h"
5
6MapRenderComponent::MapRenderComponent(const Map& map) : screen(GAME_WIDTH, GAME_HEIGHT)
7{
8 screen.fill(screen.entirety(), 0, 0, 0);
9
10 Texture tiles("res/tiles.png");
11
12 for (int i=0; i<MAP_WIDTH*MAP_HEIGHT; i++)
13 {
14 int tile = map.getMapdata()[i];
15 int x = i % MAP_WIDTH;
16 int y = i / MAP_WIDTH;
17 Rectangle dst {x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
18 Rectangle src {tile%8*TILE_WIDTH, tile/8*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
19
20 if (tile > 0)
21 {
22 screen.blit(tiles, src, dst);
23 }
24 }
25
26 Texture font("res/font.bmp");
27 std::string map_name = map.getTitle();
28 int start_x = (40/2) - (map_name.length()/2);
29 for (size_t i=0; i<map_name.length(); i++)
30 {
31 Rectangle srcRect {map_name[i] % 16 * 8, map_name[i] / 16 * 8, 8, 8};
32 Rectangle dstRect {(start_x + (int)i)*8, 24*8, 8, 8};
33 screen.blit(font, srcRect, dstRect);
34 }
35}
36
37void MapRenderComponent::render(Game&, Entity&, Texture& buffer)
38{
39 buffer.blit(screen, screen.entirety(), buffer.entirety());
40}
diff --git a/src/components/map_render.h b/src/components/map_render.h deleted file mode 100644 index a232aa6..0000000 --- a/src/components/map_render.h +++ /dev/null
@@ -1,19 +0,0 @@
1#ifndef MAP_RENDER_H
2#define MAP_RENDER_H
3
4#include "entity.h"
5#include "renderer.h"
6
7class Map;
8class Game;
9
10class MapRenderComponent : public Component {
11 public:
12 MapRenderComponent(const Map& map);
13 void render(Game& game, Entity& entity, Texture& buffer);
14
15 private:
16 Texture screen;
17};
18
19#endif
diff --git a/src/components/physics_body.cpp b/src/components/physics_body.cpp deleted file mode 100644 index 97394d1..0000000 --- a/src/components/physics_body.cpp +++ /dev/null
@@ -1,66 +0,0 @@
1#include "physics_body.h"
2#include "game.h"
3#include "consts.h"
4
5void PhysicsBodyComponent::receive(Game&, Entity&, const Message& msg)
6{
7 if (msg.type == Message::Type::walkLeft)
8 {
9 velocity.first = -90;
10 } else if (msg.type == Message::Type::walkRight)
11 {
12 velocity.first = 90;
13 } else if (msg.type == Message::Type::stopWalking)
14 {
15 velocity.first = 0.0;
16 } else if (msg.type == Message::Type::setHorizontalVelocity)
17 {
18 velocity.first = msg.velocity;
19 } else if (msg.type == Message::Type::setVerticalVelocity)
20 {
21 velocity.second = msg.velocity;
22 }
23}
24
25void PhysicsBodyComponent::tick(Game&, Entity& entity, double dt)
26{
27 // Accelerate
28 velocity.first += accel.first * dt;
29 velocity.second += accel.second * dt;
30
31 // Terminal velocity
32#define TERMINAL_VELOCITY_X (2 * TILE_WIDTH * FRAMES_PER_SECOND)
33#define TERMINAL_VELOCITY_Y (2 * TILE_HEIGHT * FRAMES_PER_SECOND)
34 if (velocity.first < -TERMINAL_VELOCITY_X) velocity.first = -TERMINAL_VELOCITY_X;
35 if (velocity.first > TERMINAL_VELOCITY_X) velocity.first = TERMINAL_VELOCITY_X;
36 if (velocity.second < -TERMINAL_VELOCITY_Y) velocity.second = -TERMINAL_VELOCITY_Y;
37 if (velocity.second > TERMINAL_VELOCITY_Y) velocity.second = TERMINAL_VELOCITY_Y;
38
39 // Do the movement
40 entity.position.first += velocity.first * dt;
41 entity.position.second += velocity.second * dt;
42}
43
44void PhysicsBodyComponent::detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position)
45{
46 // If already colliding, do nothing!
47 if ((old_position.first + collider.size.first > entity.position.first)
48 && (old_position.first < entity.position.first + entity.size.first)
49 && (old_position.second + collider.size.second > entity.position.second)
50 && (old_position.second < entity.position.second + entity.size.second))
51 {
52 return;
53 }
54
55 // If newly colliding, SHOCK AND HORROR!
56 if ((collider.position.first + collider.size.first > entity.position.first)
57 && (collider.position.first < entity.position.first + entity.size.first)
58 && (collider.position.second + collider.size.second > entity.position.second)
59 && (collider.position.second < entity.position.second + entity.size.second))
60 {
61 Message msg(Message::Type::collision);
62 msg.collisionEntity = &collider;
63
64 entity.send(game, msg);
65 }
66}
diff --git a/src/components/physics_body.h b/src/components/physics_body.h deleted file mode 100644 index 079cc51..0000000 --- a/src/components/physics_body.h +++ /dev/null
@@ -1,20 +0,0 @@
1#ifndef PHYSICS_BODY_H
2#define PHYSICS_BODY_H
3
4#include "entity.h"
5#include <utility>
6
7class Game;
8
9class PhysicsBodyComponent : public Component {
10 public:
11 void receive(Game& game, Entity& entity, const Message& msg);
12 void tick(Game& game, Entity& entity, double dt);
13 void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position);
14
15 protected:
16 std::pair<double, double> velocity;
17 std::pair<double, double> accel;
18};
19
20#endif
diff --git a/src/components/player_physics.cpp b/src/components/player_physics.cpp deleted file mode 100644 index 40e9948..0000000 --- a/src/components/player_physics.cpp +++ /dev/null
@@ -1,118 +0,0 @@
1#include "player_physics.h"
2#include "muxer.h"
3#include "game.h"
4#include "consts.h"
5
6#define JUMP_VELOCITY(h, l) (-2 * (h) / (l))
7#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l))
8
9PlayerPhysicsComponent::PlayerPhysicsComponent()
10{
11 jump_velocity = JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3);
12 jump_gravity = JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3);
13 jump_gravity_short = JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233);
14
15 accel.second = jump_gravity_short;
16}
17
18void PlayerPhysicsComponent::receive(Game&, Entity& entity, const Message& msg)
19{
20 if (msg.type == Message::Type::walkLeft)
21 {
22 velocity.first = -90;
23 direction = -1;
24 } else if (msg.type == Message::Type::walkRight)
25 {
26 velocity.first = 90;
27 direction = 1;
28 } else if (msg.type == Message::Type::stopWalking)
29 {
30 velocity.first = 0.0;
31 direction = 0;
32 } else if (msg.type == Message::Type::setHorizontalVelocity)
33 {
34 velocity.first = msg.velocity;
35 } else if (msg.type == Message::Type::setVerticalVelocity)
36 {
37 velocity.second = msg.velocity;
38 } else if (msg.type == Message::Type::hitTheGround)
39 {
40 if (isFalling)
41 {
42 playSound("res/Randomize27.wav", 0.05);
43 isFalling = false;
44 }
45
46 velocity.second = 0.0;
47 } else if (msg.type == Message::Type::jump)
48 {
49 playSound("res/Randomize87.wav", 0.25);
50
51 velocity.second = jump_velocity;
52 accel.second = jump_gravity;
53 } else if (msg.type == Message::Type::stopJump)
54 {
55 accel.second = jump_gravity_short;
56 } else if (msg.type == Message::Type::canDrop)
57 {
58 canDrop = true;
59 } else if (msg.type == Message::Type::cantDrop)
60 {
61 canDrop = false;
62 } else if (msg.type == Message::Type::drop)
63 {
64 if (canDrop)
65 {
66 canDrop = false;
67 } else {
68 entity.position.second = msg.dropAxis - entity.size.second;
69 velocity.second = 0;
70 }
71 } else if (msg.type == Message::Type::die)
72 {
73 frozen = true;
74 } else if (msg.type == Message::Type::stopDying)
75 {
76 frozen = false;
77 }
78}
79
80void PlayerPhysicsComponent::tick(Game& game, Entity& entity, double dt)
81{
82 // If frozen, do nothing
83 if (frozen)
84 {
85 return;
86 }
87
88 // Continue walking even if blocked earlier
89 if (velocity.first == 0)
90 {
91 if (direction < 0)
92 {
93 velocity.first = -90;
94 } else if (direction > 0)
95 {
96 velocity.first = 90;
97 }
98 }
99
100 // Increase gravity at the height of jump
101 if ((accel.second == jump_gravity) && (velocity.second >= 0))
102 {
103 accel.second = jump_gravity_short;
104 }
105
106 // Do the movement
107 std::pair<double, double> old_position = entity.position;
108 PhysicsBodyComponent::tick(game, entity, dt);
109
110 // Check for collisions
111 game.detectCollision(entity, old_position);
112
113 // Are we moving due to gravity?
114 if (velocity.second != 0.0)
115 {
116 isFalling = true;
117 }
118}
diff --git a/src/components/player_physics.h b/src/components/player_physics.h deleted file mode 100644 index 26f1fae..0000000 --- a/src/components/player_physics.h +++ /dev/null
@@ -1,25 +0,0 @@
1#ifndef PLAYER_PHYSICS_H
2#define PLAYER_PHYSICS_H
3
4#include "entity.h"
5#include "physics_body.h"
6
7class Game;
8
9class PlayerPhysicsComponent : public PhysicsBodyComponent {
10 public:
11 PlayerPhysicsComponent();
12 void tick(Game& game, Entity& entity, double dt);
13 void receive(Game& game, Entity& entity, const Message& msg);
14
15 private:
16 double jump_velocity;
17 double jump_gravity;
18 double jump_gravity_short;
19 int direction = 0;
20 bool canDrop = false;
21 bool frozen = false;
22 bool isFalling = false;
23};
24
25#endif
diff --git a/src/components/player_sprite.cpp b/src/components/player_sprite.cpp deleted file mode 100644 index 452a940..0000000 --- a/src/components/player_sprite.cpp +++ /dev/null
@@ -1,60 +0,0 @@
1#include "player_sprite.h"
2
3PlayerSpriteComponent::PlayerSpriteComponent() : sprite("res/Starla.png")
4{
5
6}
7
8void PlayerSpriteComponent::render(Game&, Entity& entity, Texture& buffer)
9{
10 animFrame++;
11
12 int frame = 0;
13 if (isMoving)
14 {
15 frame += 2;
16
17 if (animFrame % 20 < 10)
18 {
19 frame += 2;
20 }
21 }
22
23 if (facingLeft)
24 {
25 frame++;
26 }
27
28 double alpha = 1.0;
29 if (dying && (animFrame % 4 < 2))
30 {
31 alpha = 0.0;
32 }
33
34 Rectangle src_rect {frame*10, 0, 10, 12};
35 Rectangle dst_rect {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second};
36 buffer.blit(sprite, src_rect, dst_rect, alpha);
37}
38
39void PlayerSpriteComponent::receive(Game&, Entity&, const Message& msg)
40{
41 if (msg.type == Message::Type::walkLeft)
42 {
43 facingLeft = true;
44 isMoving = true;
45 } else if (msg.type == Message::Type::walkRight)
46 {
47 facingLeft = false;
48 isMoving = true;
49 } else if (msg.type == Message::Type::stopWalking)
50 {
51 isMoving = false;
52 } else if (msg.type == Message::Type::die)
53 {
54 dying = true;
55 isMoving = false;
56 } else if (msg.type == Message::Type::stopDying)
57 {
58 dying = false;
59 }
60}
diff --git a/src/components/player_sprite.h b/src/components/player_sprite.h deleted file mode 100644 index b1ac0af..0000000 --- a/src/components/player_sprite.h +++ /dev/null
@@ -1,23 +0,0 @@
1#ifndef PLAYER_SPRITE_H
2#define PLAYER_SPRITE_H
3
4#include "entity.h"
5#include "renderer.h"
6
7class Game;
8
9class PlayerSpriteComponent : public Component {
10 public:
11 PlayerSpriteComponent();
12 void render(Game& game, Entity& entity, Texture& buffer);
13 void receive(Game& game, Entity& entity, const Message& msg);
14
15 private:
16 Texture sprite;
17 int animFrame = 0;
18 bool facingLeft = false;
19 bool isMoving = false;
20 bool dying = false;
21};
22
23#endif
diff --git a/src/components/ponderable.cpp b/src/components/ponderable.cpp new file mode 100644 index 0000000..2cfa6a6 --- /dev/null +++ b/src/components/ponderable.cpp
@@ -0,0 +1,41 @@
1#include "ponderable.h"
2
3double PonderableComponent::getVelocityX() const
4{
5 return velocityX;
6}
7
8void PonderableComponent::setVelocityX(double v)
9{
10 velocityX = v;
11}
12
13double PonderableComponent::getVelocityY() const
14{
15 return velocityY;
16}
17
18void PonderableComponent::setVelocityY(double v)
19{
20 velocityY = v;
21}
22
23double PonderableComponent::getAccelX() const
24{
25 return accelX;
26}
27
28void PonderableComponent::setAccelX(double v)
29{
30 accelX = v;
31}
32
33double PonderableComponent::getAccelY() const
34{
35 return accelY;
36}
37
38void PonderableComponent::setAccelY(double v)
39{
40 accelY = v;
41}
diff --git a/src/components/ponderable.h b/src/components/ponderable.h new file mode 100644 index 0000000..5aab4b3 --- /dev/null +++ b/src/components/ponderable.h
@@ -0,0 +1,24 @@
1#ifndef TANGIBLE_H_746DB3EE
2#define TANGIBLE_H_746DB3EE
3
4#include "component.h"
5
6class PonderableComponent : public Component {
7 public:
8 double getVelocityX() const;
9 void setVelocityX(double v);
10 double getVelocityY() const;
11 void setVelocityY(double v);
12 double getAccelX() const;
13 void setAccelX(double v);
14 double getAccelY() const;
15 void setAccelY(double v);
16
17 private:
18 double velocityX = 0.0;
19 double velocityY = 0.0;
20 double accelX = 0.0;
21 double accelY = 0.0;
22};
23
24#endif /* end of include guard: TANGIBLE_H_746DB3EE */
diff --git a/src/components/simple_collider.cpp b/src/components/simple_collider.cpp deleted file mode 100644 index f4b414e..0000000 --- a/src/components/simple_collider.cpp +++ /dev/null
@@ -1,14 +0,0 @@
1#include "simple_collider.h"
2
3SimpleColliderComponent::SimpleColliderComponent(std::function<void (Game& game, Entity& collider)> callback) : callback(callback)
4{
5
6}
7
8void SimpleColliderComponent::receive(Game& game, Entity&, const Message& msg)
9{
10 if (msg.type == Message::Type::collision)
11 {
12 callback(game, *msg.collisionEntity);
13 }
14}
diff --git a/src/components/simple_collider.h b/src/components/simple_collider.h deleted file mode 100644 index 15d78cf..0000000 --- a/src/components/simple_collider.h +++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef SIMPLE_COLLIDER_H
2#define SIMPLE_COLLIDER_H
3
4#include "entity.h"
5#include <functional>
6
7class Game;
8
9class SimpleColliderComponent : public Component {
10 public:
11 SimpleColliderComponent(std::function<void (Game& game, Entity& collider)> callback);
12 void receive(Game& game, Entity& entity, const Message& msg);
13
14 private:
15 std::function<void (Game& game, Entity& collider)> callback;
16};
17
18#endif
diff --git a/src/components/static_image.cpp b/src/components/static_image.cpp deleted file mode 100644 index 9fa8dca..0000000 --- a/src/components/static_image.cpp +++ /dev/null
@@ -1,11 +0,0 @@
1#include "static_image.h"
2
3StaticImageComponent::StaticImageComponent(const char* filename) : sprite(Texture(filename))
4{
5
6}
7
8void StaticImageComponent::render(Game&, Entity& entity, Texture& buffer)
9{
10 buffer.blit(sprite, sprite.entirety(), {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second});
11}
diff --git a/src/components/static_image.h b/src/components/static_image.h deleted file mode 100644 index 2dec78b..0000000 --- a/src/components/static_image.h +++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef STATIC_IMAGE_H
2#define STATIC_IMAGE_H
3
4#include "entity.h"
5#include "renderer.h"
6
7class Game;
8
9class StaticImageComponent : public Component {
10 public:
11 StaticImageComponent(const char* filename);
12 void render(Game& game, Entity& entity, Texture& buffer);
13
14 private:
15 Texture sprite;
16};
17
18#endif
diff --git a/src/components/transformable.cpp b/src/components/transformable.cpp new file mode 100644 index 0000000..0d6b67e --- /dev/null +++ b/src/components/transformable.cpp
@@ -0,0 +1,47 @@
1#include "transformable.h"
2
3TransformableComponent::TransformableComponent(double x, double y, int w, int h)
4 : x(x), y(y), w(w), h(h)
5{
6
7}
8
9double TransformableComponent::getX() const
10{
11 return x;
12}
13
14double TransformableComponent::getY() const
15{
16 return y;
17}
18
19int TransformableComponent::getW() const
20{
21 return w;
22}
23
24int TransformableComponent::getH() const
25{
26 return h;
27}
28
29void TransformableComponent::setX(double v)
30{
31 x = v;
32}
33
34void TransformableComponent::setY(double v)
35{
36 y = v;
37}
38
39void TransformableComponent::setW(int v)
40{
41 w = v;
42}
43
44void TransformableComponent::setH(int v)
45{
46 h = v;
47}
diff --git a/src/components/transformable.h b/src/components/transformable.h new file mode 100644 index 0000000..87ba84d --- /dev/null +++ b/src/components/transformable.h
@@ -0,0 +1,27 @@
1#ifndef LOCATABLE_H_39E526CA
2#define LOCATABLE_H_39E526CA
3
4#include "component.h"
5
6class TransformableComponent : public Component {
7 public:
8 TransformableComponent(double x, double y, int w, int h);
9
10 double getX() const;
11 double getY() const;
12 int getW() const;
13 int getH() const;
14
15 void setX(double v);
16 void setY(double v);
17 void setW(int v);
18 void setH(int v);
19
20 private:
21 double x;
22 double y;
23 int w;
24 int h;
25};
26
27#endif /* end of include guard: LOCATABLE_H_39E526CA */
diff --git a/src/components/user_movement.cpp b/src/components/user_movement.cpp deleted file mode 100644 index e499fee..0000000 --- a/src/components/user_movement.cpp +++ /dev/null
@@ -1,100 +0,0 @@
1#include "user_movement.h"
2#include "renderer.h"
3
4void UserMovementComponent::input(Game& game, Entity& entity, int key, int action)
5{
6 if (action == GLFW_PRESS)
7 {
8 if (key == GLFW_KEY_LEFT)
9 {
10 holdingLeft = true;
11
12 if (!frozen)
13 {
14 entity.send(game, Message::Type::walkLeft);
15 }
16 } else if (key == GLFW_KEY_RIGHT)
17 {
18 holdingRight = true;
19
20 if (!frozen)
21 {
22 entity.send(game, Message::Type::walkRight);
23 }
24 } else if (key == GLFW_KEY_UP)
25 {
26 if (!frozen)
27 {
28 entity.send(game, Message::Type::jump);
29 }
30 } else if (key == GLFW_KEY_DOWN)
31 {
32 if (!frozen)
33 {
34 entity.send(game, Message::Type::canDrop);
35 }
36 }
37 } else if (action == GLFW_RELEASE)
38 {
39 if (key == GLFW_KEY_LEFT)
40 {
41 holdingLeft = false;
42
43 if (!frozen)
44 {
45 if (holdingRight)
46 {
47 entity.send(game, Message::Type::walkRight);
48 } else {
49 entity.send(game, Message::Type::stopWalking);
50 }
51 }
52 } else if (key == GLFW_KEY_RIGHT)
53 {
54 holdingRight = false;
55
56 if (!frozen)
57 {
58 if (holdingLeft)
59 {
60 entity.send(game, Message::Type::walkLeft);
61 } else {
62 entity.send(game, Message::Type::stopWalking);
63 }
64 }
65 } else if (key == GLFW_KEY_DOWN)
66 {
67 if (!frozen)
68 {
69 entity.send(game, Message::Type::cantDrop);
70 }
71 } else if (key == GLFW_KEY_UP)
72 {
73 if (!frozen)
74 {
75 entity.send(game, Message::Type::stopJump);
76 }
77 }
78 }
79}
80
81void UserMovementComponent::receive(Game& game, Entity& entity, const Message& msg)
82{
83 if (msg.type == Message::Type::die)
84 {
85 frozen = true;
86
87 entity.send(game, Message::Type::stopWalking);
88 } else if (msg.type == Message::Type::stopDying)
89 {
90 frozen = false;
91
92 if (holdingLeft)
93 {
94 entity.send(game, Message::Type::walkLeft);
95 } else if (holdingRight)
96 {
97 entity.send(game, Message::Type::walkRight);
98 }
99 }
100}
diff --git a/src/components/user_movement.h b/src/components/user_movement.h deleted file mode 100644 index 1bcf05e..0000000 --- a/src/components/user_movement.h +++ /dev/null
@@ -1,19 +0,0 @@
1#ifndef USER_MOVEMENT_H
2#define USER_MOVEMENT_H
3
4#include "entity.h"
5
6class Game;
7
8class UserMovementComponent : public Component {
9 public:
10 void input(Game& game, Entity& entity, int key, int action);
11 void receive(Game&, Entity&, const Message& msg);
12
13 private:
14 bool holdingLeft = false;
15 bool holdingRight = false;
16 bool frozen = false;
17};
18
19#endif
diff --git a/src/consts.h b/src/consts.h index 804c761..4595719 100644 --- a/src/consts.h +++ b/src/consts.h
@@ -11,4 +11,7 @@ const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1;
11const int FRAMES_PER_SECOND = 60; 11const int FRAMES_PER_SECOND = 60;
12const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND; 12const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND;
13 13
14#define JUMP_VELOCITY(h, l) (-2 * (h) / (l))
15#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l))
16
14#endif 17#endif
diff --git a/src/direction.h b/src/direction.h new file mode 100644 index 0000000..32d6b41 --- /dev/null +++ b/src/direction.h
@@ -0,0 +1,11 @@
1#ifndef DIRECTION_H_9C49EAFD
2#define DIRECTION_H_9C49EAFD
3
4enum class Direction {
5 Left,
6 Right,
7 Up,
8 Down
9};
10
11#endif /* end of include guard: DIRECTION_H_9C49EAFD */
diff --git a/src/entity.cpp b/src/entity.cpp deleted file mode 100644 index 2b6cd7f..0000000 --- a/src/entity.cpp +++ /dev/null
@@ -1,46 +0,0 @@
1#include "entity.h"
2
3void Entity::addComponent(std::shared_ptr<Component> c)
4{
5 components.push_back(c);
6}
7
8void Entity::send(Game& game, const Message& msg)
9{
10 for (auto component : components)
11 {
12 component->receive(game, *this, msg);
13 }
14}
15
16void Entity::tick(Game& game, double dt)
17{
18 for (auto component : components)
19 {
20 component->tick(game, *this, dt);
21 }
22}
23
24void Entity::input(Game& game, int key, int action)
25{
26 for (auto component : components)
27 {
28 component->input(game, *this, key, action);
29 }
30}
31
32void Entity::render(Game& game, Texture& buffer)
33{
34 for (auto component : components)
35 {
36 component->render(game, *this, buffer);
37 }
38}
39
40void Entity::detectCollision(Game& game, Entity& collider, std::pair<double, double> old_position)
41{
42 for (auto component : components)
43 {
44 component->detectCollision(game, *this, collider, old_position);
45 }
46}
diff --git a/src/entity.h b/src/entity.h deleted file mode 100644 index 7f09f2d..0000000 --- a/src/entity.h +++ /dev/null
@@ -1,64 +0,0 @@
1#ifndef ENTITY_H
2#define ENTITY_H
3
4#include <list>
5#include "renderer.h"
6
7class Game;
8class Map;
9class Entity;
10class Component;
11
12class Message {
13 public:
14 enum class Type {
15 walkLeft,
16 walkRight,
17 stopWalking,
18 setHorizontalVelocity,
19 setVerticalVelocity,
20 collision,
21 jump,
22 stopJump,
23 drop,
24 canDrop,
25 cantDrop,
26 die,
27 stopDying,
28 hitTheGround
29 };
30
31 Message(Type type) : type(type) {}
32
33 Type type;
34 Entity* collisionEntity;
35 int dropAxis;
36 double velocity;
37};
38
39class Entity {
40 public:
41 void addComponent(std::shared_ptr<Component> c);
42 void send(Game& game, const Message& msg);
43 void tick(Game& game, double dt);
44 void input(Game& game, int key, int action);
45 void render(Game& game, Texture& buffer);
46 void detectCollision(Game& game, Entity& collider, std::pair<double, double> old_position);
47
48 std::pair<double, double> position;
49 std::pair<int, int> size;
50
51 private:
52 std::list<std::shared_ptr<Component>> components;
53};
54
55class Component {
56 public:
57 virtual void receive(Game&, Entity&, const Message&) {}
58 virtual void render(Game&, Entity&, Texture&) {}
59 virtual void tick(Game&, Entity&, double) {}
60 virtual void input(Game&, Entity&, int, int) {}
61 virtual void detectCollision(Game&, Entity&, Entity&, std::pair<double, double>) {}
62};
63
64#endif
diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp new file mode 100644 index 0000000..4bdfe8a --- /dev/null +++ b/src/entity_manager.cpp
@@ -0,0 +1,38 @@
1#ifndef ENTITY_MANAGER_CPP_42D78C22
2#define ENTITY_MANAGER_CPP_42D78C22
3
4#include "entity_manager.h"
5
6template <>
7std::set<int> EntityManager::getEntitiesWithComponents<>(std::set<std::type_index>& componentTypes)
8{
9 if (cachedComponents.count(componentTypes) == 1)
10 {
11 return cachedComponents[componentTypes];
12 }
13
14 std::set<int>& cache = cachedComponents[componentTypes];
15 for (auto& entity : entities)
16 {
17 EntityData& data = entity.second;
18 bool cacheEntity = true;
19
20 for (auto& componentType : componentTypes)
21 {
22 if (data.components.count(componentType) == 0)
23 {
24 cacheEntity = false;
25 break;
26 }
27 }
28
29 if (cacheEntity)
30 {
31 cache.insert(entity.first);
32 }
33 }
34
35 return cache;
36}
37
38#endif /* end of include guard: ENTITY_MANAGER_CPP_42D78C22 */
diff --git a/src/entity_manager.h b/src/entity_manager.h new file mode 100644 index 0000000..5f0f2d4 --- /dev/null +++ b/src/entity_manager.h
@@ -0,0 +1,152 @@
1#ifndef ENTITY_MANAGER_H_C5832F11
2#define ENTITY_MANAGER_H_C5832F11
3
4#include <map>
5#include <typeindex>
6#include <set>
7#include <cassert>
8#include "component.h"
9#include "algorithms.h"
10
11class EntityManager {
12 private:
13 struct EntityData {
14 std::map<std::type_index, std::unique_ptr<Component>> components;
15 };
16
17 std::map<int, EntityData> entities;
18 std::map<std::set<std::type_index>, std::set<int>> cachedComponents;
19
20 int nextEntityID = 0;
21
22 template <class T, class... R>
23 std::set<int> getEntitiesWithComponentsHelper(std::set<std::type_index>& componentTypes)
24 {
25 componentTypes.insert(typeid(T));
26
27 return getEntitiesWithComponents<R...>(componentTypes);
28 }
29
30 template <class... R>
31 std::set<int> getEntitiesWithComponents(std::set<std::type_index>& componentTypes)
32 {
33 return getEntitiesWithComponentsHelper<R...>(componentTypes);
34 }
35
36 public:
37 EntityManager() = default;
38 EntityManager(const EntityManager& copy) = delete;
39
40 int emplaceEntity()
41 {
42 // Find a suitable entity ID
43 while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0))
44 {
45 nextEntityID++;
46 }
47
48 if (nextEntityID < 0)
49 {
50 nextEntityID = 0;
51
52 while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0))
53 {
54 nextEntityID++;
55 }
56
57 assert(nextEntityID >= 0);
58 }
59
60 // Initialize the data
61 int id = nextEntityID++;
62 entities[id];
63
64 return id;
65 }
66
67 void deleteEntity(int entity)
68 {
69 assert(entities.count(entity) == 1);
70
71 // Uncache components
72 for (auto& cache : cachedComponents)
73 {
74 cache.second.erase(entity);
75 }
76
77 // Destroy the data
78 entities.erase(entity);
79 }
80
81 template <class T, class... Args>
82 T& emplaceComponent(int entity, Args&&... args)
83 {
84 assert(entities.count(entity) == 1);
85
86 EntityData& data = entities[entity];
87 std::type_index componentType = typeid(T);
88
89 assert(data.components.count(componentType) == 0);
90
91 // Initialize the component
92 std::unique_ptr<T> ptr = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
93 T& component = *ptr;
94 data.components[componentType] = std::move(ptr);
95
96 // Invalidate related caches
97 erase_if(cachedComponents, [&componentType] (std::pair<const std::set<std::type_index>, std::set<int>>& cache) {
98 return cache.first.count(componentType) == 1;
99 });
100
101 return component;
102 }
103
104 template <class T>
105 void removeComponent(int entity)
106 {
107 assert(entities.count(entity) == 1);
108
109 EntityData& data = entities[entity];
110 std::type_index componentType = typeid(T);
111
112 assert(data.components.count(componentType) == 1);
113
114 // Destroy the component
115 data.components.erase(componentType);
116
117 // Uncache the component
118 for (auto& cache : cachedComponents)
119 {
120 if (cache.first.count(componentType) == 1)
121 {
122 cache.second.erase(entity);
123 }
124 }
125 }
126
127 template <class T>
128 T& getComponent(int entity)
129 {
130 assert(entities.count(entity) == 1);
131
132 EntityData& data = entities[entity];
133 std::type_index componentType = typeid(T);
134
135 assert(data.components.count(componentType) == 1);
136
137 return *((T*)data.components[componentType].get());
138 }
139
140 template <class... R>
141 std::set<int> getEntitiesWithComponents()
142 {
143 std::set<std::type_index> componentTypes;
144
145 return getEntitiesWithComponentsHelper<R...>(componentTypes);
146 }
147};
148
149template <>
150std::set<int> EntityManager::getEntitiesWithComponents<>(std::set<std::type_index>& componentTypes);
151
152#endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */
diff --git a/src/entityfactory.cpp b/src/entityfactory.cpp deleted file mode 100644 index b80fe99..0000000 --- a/src/entityfactory.cpp +++ /dev/null
@@ -1,182 +0,0 @@
1#include "entityfactory.h"
2#include <libxml/parser.h>
3#include "muxer.h"
4#include <cstdio>
5#include <map>
6#include <list>
7#include "components/static_image.h"
8#include "components/simple_collider.h"
9#include "components/physics_body.h"
10#include "components/ai.h"
11#include "game.h"
12
13void parseEntityAIData(AI& ai, xmlNodePtr node, const std::map<std::string, int>& items)
14{
15 xmlChar* key;
16
17 for (xmlNodePtr aiNode = node->xmlChildrenNode; aiNode != NULL; aiNode = aiNode->next)
18 {
19 if (!xmlStrcmp(aiNode->name, (xmlChar*) "move"))
20 {
21 MoveAIAction::Direction dir;
22 int len;
23 int speed;
24
25 key = xmlGetProp(aiNode, (xmlChar*) "direction");
26 if (key == 0) exit(2);
27 if (!xmlStrcmp(key, (xmlChar*) "left"))
28 {
29 dir = MoveAIAction::Direction::Left;
30 } else if (!xmlStrcmp(key, (xmlChar*) "right"))
31 {
32 dir = MoveAIAction::Direction::Right;
33 } else if (!xmlStrcmp(key, (xmlChar*) "up"))
34 {
35 dir = MoveAIAction::Direction::Up;
36 } else if (!xmlStrcmp(key, (xmlChar*) "down"))
37 {
38 dir = MoveAIAction::Direction::Down;
39 } else {
40 exit(2);
41 }
42 xmlFree(key);
43
44 key = xmlGetProp(aiNode, (xmlChar*) "length");
45 if (key != 0)
46 {
47 len = atoi((char*) key);
48 } else {
49 key = xmlGetProp(aiNode, (xmlChar*) "length-var");
50 if (key == 0) exit(2);
51 std::string varName = (char*) key;
52 len = items.at(varName);
53 }
54 xmlFree(key);
55
56 key = xmlGetProp(aiNode, (xmlChar*) "speed");
57 if (key != 0)
58 {
59 speed = atoi((char*) key);
60 } else {
61 key = xmlGetProp(aiNode, (xmlChar*) "speed-var");
62 if (key == 0) exit(2);
63 std::string varName = (char*) key;
64 speed = items.at(varName);
65 }
66 xmlFree(key);
67
68 ai.addAction(std::make_shared<MoveAIAction>(dir, len, speed));
69 } else if (!xmlStrcmp(aiNode->name, (xmlChar*) "switch"))
70 {
71 key = xmlGetProp(aiNode, (xmlChar*) "item");
72 if (key == 0) exit(2);
73 std::string switchItem = (char*) key;
74 xmlFree(key);
75
76 for (xmlNodePtr switchNode = aiNode->xmlChildrenNode; switchNode != NULL; switchNode = switchNode->next)
77 {
78 if (!xmlStrcmp(switchNode->name, (xmlChar*) "case"))
79 {
80 key = xmlGetProp(switchNode, (xmlChar*) "value");
81 if (key == 0) exit(2);
82 int caseValue = atoi((char*) key);
83 xmlFree(key);
84
85 if (items.at(switchItem) == caseValue)
86 {
87 parseEntityAIData(ai, switchNode, items);
88 }
89 }
90 }
91 }
92 }
93}
94
95std::shared_ptr<Entity> EntityFactory::createNamedEntity(const std::string name, const std::map<std::string, int>& items)
96{
97 xmlDocPtr doc = xmlParseFile("res/entities.xml");
98 if (doc == nullptr)
99 {
100 fprintf(stderr, "Error reading entities\n");
101 exit(-1);
102 }
103
104 xmlNodePtr top = xmlDocGetRootElement(doc);
105 if (top == nullptr)
106 {
107 fprintf(stderr, "Empty entities file\n");
108 exit(-1);
109 }
110
111 if (xmlStrcmp(top->name, (const xmlChar*) "entities"))
112 {
113 fprintf(stderr, "Invalid entities definition\n");
114 exit(-1);
115 }
116
117 auto entity = std::make_shared<Entity>();
118
119 xmlChar* key;
120 for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next)
121 {
122 if (!xmlStrcmp(node->name, (xmlChar*) "entity"))
123 {
124 key = xmlGetProp(node, (xmlChar*) "id");
125 if (key == 0) exit(-1);
126 std::string entityID = (char*) key;
127 xmlFree(key);
128
129 if (entityID == name)
130 {
131 key = xmlGetProp(node, (xmlChar*) "sprite");
132 if (key == 0) exit(-1);
133 auto spriteComponent = std::make_shared<StaticImageComponent>((char*) key);
134 entity->addComponent(spriteComponent);
135 xmlFree(key);
136
137 auto physicsComponent = std::make_shared<PhysicsBodyComponent>();
138 entity->addComponent(physicsComponent);
139
140 key = xmlGetProp(node, (xmlChar*) "width");
141 if (key == 0) exit(-1);
142 entity->size.first = atoi((char*) key);
143 xmlFree(key);
144
145 key = xmlGetProp(node, (xmlChar*) "height");
146 if (key == 0) exit(-1);
147 entity->size.second = atoi((char*) key);
148 xmlFree(key);
149
150 bool addAI = false;
151 auto aiComponent = std::make_shared<AIComponent>();
152
153 for (xmlNodePtr entityNode = node->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next)
154 {
155 if (!xmlStrcmp(entityNode->name, (xmlChar*) "ai"))
156 {
157 addAI = true;
158
159 xmlChar* chanceKey = xmlGetProp(entityNode, (xmlChar*) "chance");
160 if (chanceKey == 0) exit(2);
161 int chance = atoi((char*) chanceKey);
162 xmlFree(chanceKey);
163
164 AI& ai = aiComponent->emplaceAI(chance);
165 parseEntityAIData(ai, entityNode, items);
166 }
167 }
168
169 if (addAI)
170 {
171 entity->addComponent(aiComponent);
172 }
173
174 break;
175 }
176 }
177 }
178
179 xmlFreeDoc(doc);
180
181 return entity;
182}
diff --git a/src/entityfactory.h b/src/entityfactory.h deleted file mode 100644 index 56f7216..0000000 --- a/src/entityfactory.h +++ /dev/null
@@ -1,15 +0,0 @@
1#ifndef ENTITYFACTORY_H
2#define ENTITYFACTORY_H
3
4#include <string>
5#include <map>
6
7class Entity;
8class Map;
9
10class EntityFactory {
11 public:
12 static std::shared_ptr<Entity> createNamedEntity(const std::string name, const std::map<std::string, int>& items);
13};
14
15#endif
diff --git a/src/game.cpp b/src/game.cpp index 673c804..b3fa9a8 100644 --- a/src/game.cpp +++ b/src/game.cpp
@@ -1,60 +1,47 @@
1#include "game.h" 1#include "game.h"
2#include <cstdlib> 2#include "components/animatable.h"
3#include "renderer.h" 3#include "components/transformable.h"
4#include "muxer.h" 4#include "components/controllable.h"
5#include "map.h" 5#include "components/droppable.h"
6#include "components/user_movement.h" 6#include "components/ponderable.h"
7#include "components/player_physics.h" 7#include "systems/rendering.h"
8#include "components/player_sprite.h" 8#include "systems/controlling.h"
9#include "components/map_render.h" 9#include "systems/pondering.h"
10#include "components/map_collision.h"
11#include "consts.h"
12
13Game::Game(const char* mapfile) : world(mapfile)
14{
15 // Set up entities
16 player = std::make_shared<Entity>();
17 player->position = world.getStartingPosition();
18 player->size = std::make_pair(10.0,12.0);
19
20 auto player_input = std::make_shared<UserMovementComponent>();
21 player->addComponent(player_input);
22
23 auto player_physics = std::make_shared<PlayerPhysicsComponent>();
24 player->addComponent(player_physics);
25
26 auto player_anim = std::make_shared<PlayerSpriteComponent>();
27 player->addComponent(player_anim);
28
29 const Map& startingMap = world.getStartingMap();
30 save = {&startingMap, player->position};
31
32 loadMap(startingMap, player->position);
33}
34 10
35void key_callback(GLFWwindow* window, int key, int, int action, int) 11void key_callback(GLFWwindow* window, int key, int, int action, int)
36{ 12{
37 Game* game = (Game*) glfwGetWindowUserPointer(window); 13 Game& game = *((Game*) glfwGetWindowUserPointer(window));
38 14
39 if ((key == GLFW_KEY_ESCAPE) && (action == GLFW_PRESS)) 15 if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE))
40 { 16 {
41 game->shouldQuit = true; 17 game.shouldQuit = true;
18
19 return;
42 } 20 }
43 21
44 for (auto entity : game->entities) 22 game.systemManager.getSystem<ControllingSystem>().input(key, action);
45 {
46 entity->input(*game, key, action);
47 }
48} 23}
49 24
50void Game::execute(GLFWwindow* window) 25Game::Game(GLFWwindow* window) : window(window)
51{ 26{
27 systemManager.emplaceSystem<ControllingSystem>(*this);
28 systemManager.emplaceSystem<RenderingSystem>(*this);
29 systemManager.emplaceSystem<PonderingSystem>(*this);
30
31 int player = entityManager.emplaceEntity();
32 entityManager.emplaceComponent<AnimatableComponent>(player, "res/Starla.png", 10, 12, 6);
33 entityManager.emplaceComponent<TransformableComponent>(player, 203, 44, 10, 12);
34 entityManager.emplaceComponent<DroppableComponent>(player);
35 entityManager.emplaceComponent<PonderableComponent>(player);
36 entityManager.emplaceComponent<ControllableComponent>(player);
37
52 glfwSwapInterval(1); 38 glfwSwapInterval(1);
53 glfwSetWindowUserPointer(window, this); 39 glfwSetWindowUserPointer(window, this);
54 glfwSetKeyCallback(window, key_callback); 40 glfwSetKeyCallback(window, key_callback);
55 41}
56 Texture buffer(GAME_WIDTH, GAME_HEIGHT);
57 42
43void Game::execute()
44{
58 double lastTime = glfwGetTime(); 45 double lastTime = glfwGetTime();
59 const double dt = 0.01; 46 const double dt = 0.01;
60 double accumulator = 0.0; 47 double accumulator = 0.0;
@@ -65,114 +52,24 @@ void Game::execute(GLFWwindow* window)
65 double frameTime = currentTime - lastTime; 52 double frameTime = currentTime - lastTime;
66 lastTime = currentTime; 53 lastTime = currentTime;
67 54
68 // Should we load a new world?
69 if (newWorld)
70 {
71 newWorld = false;
72 entities.clear();
73 entities = std::move(nextEntities);
74
75 player->position = nextPosition;
76 }
77
78 // Handle input
79 glfwPollEvents(); 55 glfwPollEvents();
80 56
81 // Tick!
82 accumulator += frameTime; 57 accumulator += frameTime;
83 while (accumulator >= dt) 58 while (accumulator >= dt)
84 { 59 {
85 for (auto entity : entities) 60 systemManager.getSystem<ControllingSystem>().tick(dt);
86 { 61 systemManager.getSystem<PonderingSystem>().tick(dt);
87 entity->tick(*this, dt);
88 }
89 62
90 accumulator -= dt; 63 accumulator -= dt;
91 } 64 }
92 65
93 // Do any scheduled tasks 66 systemManager.getSystem<RenderingSystem>().tick(frameTime);
94 for (auto& task : scheduled)
95 {
96 task.first -= frameTime;
97
98 if (task.first <= 0)
99 {
100 task.second();
101 }
102 }
103
104 scheduled.remove_if([] (std::pair<double, std::function<void ()>> value) { return value.first <= 0; });
105
106 // Do rendering
107 buffer.fill(buffer.entirety(), 0, 0, 0);
108 for (auto entity : entities)
109 {
110 entity->render(*this, buffer);
111 }
112
113 buffer.renderScreen();
114 }
115}
116
117void Game::loadMap(const Map& map, std::pair<double, double> position)
118{
119 auto mapEn = std::make_shared<Entity>();
120
121 auto map_render = std::make_shared<MapRenderComponent>(map);
122 mapEn->addComponent(map_render);
123
124 auto map_collision = std::make_shared<MapCollisionComponent>(map);
125 mapEn->addComponent(map_collision);
126
127 // Map in the back, player on top, rest of entities in between
128 nextEntities.clear();
129 nextEntities.push_back(mapEn);
130 map.createEntities(nextEntities);
131 nextEntities.push_back(player);
132
133 newWorld = true;
134
135 currentMap = &map;
136 nextPosition = position;
137}
138
139void Game::detectCollision(Entity& collider, std::pair<double, double> old_position)
140{
141 for (auto entity : entities)
142 {
143 entity->detectCollision(*this, collider, old_position);
144 } 67 }
145} 68}
146 69
147void Game::saveGame() 70EntityManager& Game::getEntityManager()
148{ 71{
149 save = {currentMap, player->position}; 72 return entityManager;
150} 73}
151 74
152void Game::schedule(double time, std::function<void ()> callback)
153{
154 scheduled.emplace_front(time, std::move(callback));
155}
156 75
157void Game::playerDie()
158{
159 player->send(*this, Message::Type::die);
160
161 playSound("res/Hit_Hurt5.wav", 0.25);
162
163 schedule(0.75, [&] () {
164 if (*currentMap != *save.map)
165 {
166 loadMap(*save.map, save.position);
167 } else {
168 player->position = save.position;
169 }
170
171 player->send(*this, Message::Type::stopDying);
172 });
173}
174
175const World& Game::getWorld() const
176{
177 return world;
178}
diff --git a/src/game.h b/src/game.h index dd4b2f7..3822700 100644 --- a/src/game.h +++ b/src/game.h
@@ -1,45 +1,24 @@
1#ifndef GAME_H 1#ifndef GAME_H_1014DDC9
2#define GAME_H 2#define GAME_H_1014DDC9
3 3
4#include <memory> 4#include "renderer.h"
5#include <functional> 5#include "entity_manager.h"
6#include <list> 6#include "system_manager.h"
7#include <map>
8#include "map.h"
9#include "world.h"
10
11class Entity;
12struct GLFWwindow;
13
14struct Savefile {
15 const Map* map;
16 std::pair<double, double> position;
17};
18 7
19class Game { 8class Game {
20 public: 9 public:
21 Game(const char* maps); 10 Game(GLFWwindow* window);
22 void execute(GLFWwindow* window); 11
23 void loadMap(const Map& map, std::pair<double, double> position); 12 void execute();
24 void detectCollision(Entity& collider, std::pair<double, double> old_position); 13 EntityManager& getEntityManager();
25 void saveGame();
26 void schedule(double time, std::function<void ()> callback);
27 void playerDie();
28 const World& getWorld() const;
29 14
30 private:
31 friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); 15 friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
32 16
33 std::list<std::shared_ptr<Entity>> entities; 17 private:
34 std::list<std::shared_ptr<Entity>> nextEntities; 18 EntityManager entityManager;
35 std::pair<double, double> nextPosition; 19 SystemManager systemManager;
36 bool newWorld; 20 GLFWwindow* const window;
37 std::shared_ptr<Entity> player;
38 const Map* currentMap;
39 Savefile save;
40 std::list<std::pair<double, std::function<void ()>>> scheduled;
41 bool shouldQuit = false; 21 bool shouldQuit = false;
42 World world;
43}; 22};
44 23
45#endif 24#endif /* end of include guard: GAME_H_1014DDC9 */
diff --git a/src/main.cpp b/src/main.cpp index 4157350..35749f5 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -1,21 +1,23 @@
1#include <ctime> 1#include <ctime>
2#include <list> 2#include <list>
3#include "renderer.h"
4#include <cstdlib> 3#include <cstdlib>
5#include "game.h" 4#include "renderer.h"
6#include "muxer.h" 5#include "muxer.h"
6#include "game.h"
7 7
8int main() 8int main()
9{ 9{
10 srand(time(NULL)); 10 srand(time(NULL));
11 11
12 GLFWwindow* window = initRenderer(); 12 GLFWwindow* window = initRenderer();
13 glfwSwapInterval(1);
14
13 initMuxer(); 15 initMuxer();
14 16
15 // Put this in a block so game goes out of scope before we destroy the renderer 17 // Put this in a block so game goes out of scope before we destroy the renderer
16 { 18 {
17 Game game {"res/maps.xml"}; 19 Game game {window};
18 game.execute(window); 20 game.execute();
19 } 21 }
20 22
21 destroyMuxer(); 23 destroyMuxer();
diff --git a/src/map.cpp b/src/map.cpp deleted file mode 100644 index e3725b2..0000000 --- a/src/map.cpp +++ /dev/null
@@ -1,151 +0,0 @@
1#include "map.h"
2#include <cstdlib>
3#include <cstring>
4#include <map>
5#include "entityfactory.h"
6#include "entity.h"
7#include "game.h"
8#include "consts.h"
9
10Map::Map(int id)
11{
12 this->id = id;
13 mapdata = (int*) calloc(1, sizeof(int));
14}
15
16Map::Map(const Map& map)
17{
18 mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int));
19 memcpy(mapdata, map.mapdata, MAP_WIDTH*MAP_HEIGHT*sizeof(int));
20
21 id = map.id;
22 title = map.title;
23 adjacents = map.adjacents;
24 entities = map.entities;
25}
26
27Map::Map(Map&& map) : Map()
28{
29 swap(*this, map);
30}
31
32Map::~Map()
33{
34 free(mapdata);
35}
36
37Map& Map::operator= (Map map)
38{
39 swap(*this, map);
40
41 return *this;
42}
43
44void swap(Map& first, Map& second)
45{
46 std::swap(first.mapdata, second.mapdata);
47 std::swap(first.title, second.title);
48 std::swap(first.adjacents, second.adjacents);
49 std::swap(first.id, second.id);
50 std::swap(first.entities, second.entities);
51}
52
53int Map::getID() const
54{
55 return id;
56}
57
58const int* Map::getMapdata() const
59{
60 return mapdata;
61}
62
63std::string Map::getTitle() const
64{
65 return title;
66}
67
68void Map::createEntities(std::list<std::shared_ptr<Entity>>& entities) const
69{
70 for (auto data : this->entities)
71 {
72 auto entity = EntityFactory::createNamedEntity(data.name, data.items);
73 entity->position = data.position;
74
75 entities.push_back(entity);
76 }
77}
78
79bool Map::operator==(const Map& other) const
80{
81 return id == other.id;
82}
83
84bool Map::operator!=(const Map& other) const
85{
86 return id != other.id;
87}
88
89Map::MoveType Map::moveTypeForShort(std::string str)
90{
91 if (str == "wrap") return MoveType::Wrap;
92 if (str == "warp") return MoveType::Warp;
93 if (str == "reverseWarp") return MoveType::ReverseWarp;
94
95 return MoveType::Wall;
96}
97
98Map::MoveDir Map::moveDirForShort(std::string str)
99{
100 if (str == "right") return MoveDir::Right;
101 if (str == "up") return MoveDir::Up;
102 if (str == "down") return MoveDir::Down;
103
104 return MoveDir::Left;
105}
106
107static const Map::Adjacent defaultAdjacent {};
108const Map::Adjacent& Map::getAdjacent(MoveDir dir) const
109{
110 if (adjacents.count(dir) > 0)
111 {
112 return adjacents.at(dir);
113 } else {
114 return defaultAdjacent;
115 }
116}
117
118bool Map::moveTypeTakesMap(MoveType type)
119{
120 switch (type)
121 {
122 case MoveType::Wall: return false;
123 case MoveType::Wrap: return false;
124 case MoveType::Warp: return true;
125 case MoveType::ReverseWarp: return true;
126 }
127}
128
129void Map::setMapdata(int* mapdata)
130{
131 free(this->mapdata);
132 this->mapdata = mapdata;
133}
134
135void Map::setTitle(std::string title)
136{
137 this->title = title;
138}
139
140void Map::setAdjacent(MoveDir dir, MoveType type, int map)
141{
142 Adjacent& cur = adjacents[dir];
143 cur.type = type;
144 if (map != -1) cur.map = map;
145}
146
147void Map::addEntity(EntityData& data)
148{
149 entities.push_back(data);
150}
151
diff --git a/src/map.h b/src/map.h deleted file mode 100644 index 22333aa..0000000 --- a/src/map.h +++ /dev/null
@@ -1,70 +0,0 @@
1#ifndef MAP_H
2#define MAP_H
3
4#include <string>
5#include <list>
6#include <map>
7
8class Entity;
9
10class Map {
11 public:
12 Map(int id);
13 Map() : Map(-1) {}
14 Map(const Map& map);
15 Map(Map&& map);
16 ~Map();
17 Map& operator= (Map other);
18 friend void swap(Map& first, Map& second);
19
20 enum class MoveType {
21 Wall,
22 Wrap,
23 Warp,
24 ReverseWarp
25 };
26
27 enum class MoveDir {
28 Left,
29 Right,
30 Up,
31 Down
32 };
33
34 struct EntityData {
35 std::string name;
36 std::pair<int, int> position;
37 std::map<std::string, int> items;
38 };
39
40 struct Adjacent {
41 MoveType type = MoveType::Wall;
42 int map = -1;
43 };
44
45 static MoveType moveTypeForShort(std::string str);
46 static MoveDir moveDirForShort(std::string str);
47 static bool moveTypeTakesMap(MoveType type);
48
49 int getID() const;
50 const int* getMapdata() const;
51 std::string getTitle() const;
52 const Adjacent& getAdjacent(MoveDir dir) const;
53
54 void createEntities(std::list<std::shared_ptr<Entity>>& entities) const;
55 bool operator==(const Map& other) const;
56 bool operator!=(const Map& other) const;
57
58 void setMapdata(int* mapdata);
59 void setTitle(std::string title);
60 void setAdjacent(MoveDir dir, MoveType type, int map);
61 void addEntity(EntityData& data);
62 private:
63 int* mapdata;
64 std::string title;
65 int id;
66 std::list<EntityData> entities;
67 std::map<MoveDir, Adjacent> adjacents;
68};
69
70#endif
diff --git a/src/system.h b/src/system.h new file mode 100644 index 0000000..e08db0a --- /dev/null +++ b/src/system.h
@@ -0,0 +1,17 @@
1#ifndef SYSTEM_H_B61A8CEA
2#define SYSTEM_H_B61A8CEA
3
4class Game;
5
6class System {
7 public:
8 System(Game& game)
9 : game(game) {}
10
11 virtual void tick(double dt) = 0;
12
13 protected:
14 Game& game;
15};
16
17#endif /* end of include guard: SYSTEM_H_B61A8CEA */
diff --git a/src/system_manager.h b/src/system_manager.h new file mode 100644 index 0000000..8f76db2 --- /dev/null +++ b/src/system_manager.h
@@ -0,0 +1,37 @@
1#ifndef SYSTEM_MANAGER_H_544E6056
2#define SYSTEM_MANAGER_H_544E6056
3
4#include <list>
5#include <memory>
6#include <map>
7#include <typeindex>
8#include "system.h"
9
10class SystemManager {
11 private:
12 std::list<std::unique_ptr<System>> loop;
13 std::map<std::type_index, System*> systems;
14
15 public:
16 template <class T, class... Args>
17 void emplaceSystem(Game& game, Args&&... args)
18 {
19 std::unique_ptr<T> ptr = std::unique_ptr<T>(new T(game, std::forward<Args>(args)...));
20 std::type_index systemType = typeid(T);
21
22 systems[systemType] = ptr.get();
23 loop.push_back(std::move(ptr));
24 }
25
26 template <class T>
27 T& getSystem()
28 {
29 std::type_index systemType = typeid(T);
30
31 assert(systems.count(systemType) == 1);
32
33 return *((T*)systems[systemType]);
34 }
35};
36
37#endif /* end of include guard: SYSTEM_MANAGER_H_544E6056 */
diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp new file mode 100644 index 0000000..b1e73ad --- /dev/null +++ b/src/systems/controlling.cpp
@@ -0,0 +1,168 @@
1#include "controlling.h"
2#include "game.h"
3#include "components/controllable.h"
4#include "components/ponderable.h"
5#include "components/animatable.h"
6#include "components/droppable.h"
7#include "direction.h"
8#include "muxer.h"
9#include "consts.h"
10
11void ControllingSystem::tick(double dt)
12{
13 while (!actions.empty())
14 {
15 int key = actions.front().first;
16 int action = actions.front().second;
17
18 auto entities = game.getEntityManager().getEntitiesWithComponents<ControllableComponent, PonderableComponent, AnimatableComponent, DroppableComponent>();
19 for (auto entity : entities)
20 {
21 auto& controllable = game.getEntityManager().getComponent<ControllableComponent>(entity);
22
23 if (action == GLFW_PRESS)
24 {
25 if (key == controllable.getLeftKey())
26 {
27 controllable.setHoldingLeft(true);
28
29 if (!controllable.isFrozen())
30 {
31 walkLeft(entity);
32 }
33 } else if (key == controllable.getRightKey())
34 {
35 controllable.setHoldingRight(true);
36
37 if (!controllable.isFrozen())
38 {
39 walkRight(entity);
40 }
41 } else if (key == controllable.getJumpKey())
42 {
43 if (!controllable.isFrozen())
44 {
45 jump(entity);
46 }
47 } else if (key == controllable.getDropKey())
48 {
49 if (!controllable.isFrozen())
50 {
51 drop(entity, true);
52 }
53 }
54 } else if (action == GLFW_RELEASE)
55 {
56 if (key == controllable.getLeftKey())
57 {
58 controllable.setHoldingLeft(false);
59
60 if (!controllable.isFrozen())
61 {
62 if (controllable.isHoldingRight())
63 {
64 walkRight(entity);
65 } else {
66 stopWalking(entity);
67 }
68 }
69 } else if (key == controllable.getRightKey())
70 {
71 controllable.setHoldingRight(false);
72
73 if (!controllable.isFrozen())
74 {
75 if (controllable.isHoldingRight())
76 {
77 walkLeft(entity);
78 } else {
79 stopWalking(entity);
80 }
81 }
82 } else if (key == controllable.getDropKey())
83 {
84 if (!controllable.isFrozen())
85 {
86 drop(entity, false);
87 }
88 } else if (key == controllable.getJumpKey())
89 {
90 if (!controllable.isFrozen())
91 {
92 stopJumping(entity);
93 }
94 }
95 }
96 }
97
98 actions.pop();
99 }
100}
101
102void ControllingSystem::input(int key, int action)
103{
104 actions.push(std::make_pair(key, action));
105}
106
107void ControllingSystem::walkLeft(int entity)
108{
109 auto& ponderable = game.getEntityManager().getComponent<PonderableComponent>(entity);
110 auto& animatable = game.getEntityManager().getComponent<AnimatableComponent>(entity);
111
112 ponderable.setVelocityX(-90);
113
114 animatable.setDirection(Direction::Left);
115 animatable.setWalking(true);
116}
117
118void ControllingSystem::walkRight(int entity)
119{
120 auto& ponderable = game.getEntityManager().getComponent<PonderableComponent>(entity);
121 auto& animatable = game.getEntityManager().getComponent<AnimatableComponent>(entity);
122
123 ponderable.setVelocityX(90);
124
125 animatable.setDirection(Direction::Right);
126 animatable.setWalking(true);
127}
128
129void ControllingSystem::stopWalking(int entity)
130{
131 auto& ponderable = game.getEntityManager().getComponent<PonderableComponent>(entity);
132 auto& animatable = game.getEntityManager().getComponent<AnimatableComponent>(entity);
133
134 ponderable.setVelocityX(0);
135
136 animatable.setWalking(false);
137}
138
139void ControllingSystem::jump(int entity)
140{
141 auto& ponderable = game.getEntityManager().getComponent<PonderableComponent>(entity);
142 auto& animatable = game.getEntityManager().getComponent<AnimatableComponent>(entity);
143
144 playSound("res/Randomize87.wav", 0.25);
145
146 ponderable.setVelocityY(JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3));
147 ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3));
148
149 animatable.setJumping(true);
150}
151
152void ControllingSystem::stopJumping(int entity)
153{
154 auto& ponderable = game.getEntityManager().getComponent<PonderableComponent>(entity);
155 auto& animatable = game.getEntityManager().getComponent<AnimatableComponent>(entity);
156
157 ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233));
158 animatable.setJumping(false);
159}
160
161void ControllingSystem::drop(int entity, bool start)
162{
163 auto& animatable = game.getEntityManager().getComponent<AnimatableComponent>(entity);
164 auto& droppable = game.getEntityManager().getComponent<DroppableComponent>(entity);
165
166 droppable.setDroppable(start);
167 animatable.setCrouching(start);
168}
diff --git a/src/systems/controlling.h b/src/systems/controlling.h new file mode 100644 index 0000000..61f86eb --- /dev/null +++ b/src/systems/controlling.h
@@ -0,0 +1,26 @@
1#ifndef CONTROLLING_H_80B1BB8D
2#define CONTROLLING_H_80B1BB8D
3
4#include "system.h"
5#include <queue>
6
7class ControllingSystem : public System {
8 public:
9 ControllingSystem(Game& game)
10 : System(game) {}
11
12 void tick(double dt);
13 void input(int key, int action);
14
15 private:
16 void walkLeft(int entity);
17 void walkRight(int entity);
18 void stopWalking(int entity);
19 void jump(int entity);
20 void stopJumping(int entity);
21 void drop(int entity, bool start);
22
23 std::queue<std::pair<int,int>> actions;
24};
25
26#endif /* end of include guard: CONTROLLING_H_80B1BB8D */
diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp new file mode 100644 index 0000000..96775d0 --- /dev/null +++ b/src/systems/pondering.cpp
@@ -0,0 +1,23 @@
1#include "pondering.h"
2#include "game.h"
3#include "components/ponderable.h"
4#include "components/transformable.h"
5
6void PonderingSystem::tick(double dt)
7{
8 auto entities = game.getEntityManager().getEntitiesWithComponents<PonderableComponent, TransformableComponent>();
9
10 for (auto entity : entities)
11 {
12 auto& transformable = game.getEntityManager().getComponent<TransformableComponent>(entity);
13 auto& ponderable = game.getEntityManager().getComponent<PonderableComponent>(entity);
14
15 // Accelerate
16 ponderable.setVelocityX(ponderable.getVelocityX() + ponderable.getAccelX() * dt);
17 ponderable.setVelocityY(ponderable.getVelocityY() + ponderable.getAccelY() * dt);
18
19 // Move
20 transformable.setX(transformable.getX() + ponderable.getVelocityX() * dt);
21 transformable.setY(transformable.getY() + ponderable.getVelocityY() * dt);
22 }
23}
diff --git a/src/systems/pondering.h b/src/systems/pondering.h new file mode 100644 index 0000000..ad01a22 --- /dev/null +++ b/src/systems/pondering.h
@@ -0,0 +1,14 @@
1#ifndef PONDERING_H_F2530E0E
2#define PONDERING_H_F2530E0E
3
4#include "system.h"
5
6class PonderingSystem : public System {
7 public:
8 PonderingSystem(Game& game)
9 : System(game) {}
10
11 void tick(double dt);
12};
13
14#endif /* end of include guard: PONDERING_H_F2530E0E */
diff --git a/src/systems/rendering.cpp b/src/systems/rendering.cpp new file mode 100644 index 0000000..251c2bc --- /dev/null +++ b/src/systems/rendering.cpp
@@ -0,0 +1,21 @@
1#include "rendering.h"
2#include "game.h"
3#include "components/animatable.h"
4#include "components/transformable.h"
5
6void RenderingSystem::tick(double dt)
7{
8 texture.fill(texture.entirety(), 0, 0, 0);
9
10 std::set<int> spriteEntities = game.getEntityManager().getEntitiesWithComponents<AnimatableComponent, TransformableComponent>();
11 for (int entity : spriteEntities)
12 {
13 auto& sprite = game.getEntityManager().getComponent<AnimatableComponent>(entity);
14 auto& transform = game.getEntityManager().getComponent<TransformableComponent>(entity);
15 Rectangle dstrect {(int) transform.getX(), (int) transform.getY(), transform.getW(), transform.getH()};
16
17 texture.blit(sprite.getTexture(), sprite.getFrameRect(), dstrect);
18 }
19
20 texture.renderScreen();
21}
diff --git a/src/systems/rendering.h b/src/systems/rendering.h new file mode 100644 index 0000000..9b6e27e --- /dev/null +++ b/src/systems/rendering.h
@@ -0,0 +1,19 @@
1#ifndef RENDERING_H_76ABC02A
2#define RENDERING_H_76ABC02A
3
4#include "system.h"
5#include "renderer.h"
6#include "consts.h"
7
8class RenderingSystem : public System {
9 public:
10 RenderingSystem(Game& game)
11 : System(game) {}
12
13 void tick(double dt);
14
15 private:
16 Texture texture {GAME_WIDTH, GAME_HEIGHT};
17};
18
19#endif /* end of include guard: RENDERING_H_76ABC02A */
diff --git a/src/world.cpp b/src/world.cpp deleted file mode 100644 index 0c61c47..0000000 --- a/src/world.cpp +++ /dev/null
@@ -1,150 +0,0 @@
1#include "world.h"
2#include <libxml/parser.h>
3#include "consts.h"
4
5World::World(const char* filename)
6{
7 xmlDocPtr doc = xmlParseFile(filename);
8 if (doc == nullptr)
9 {
10 exit(2);
11 }
12
13 xmlNodePtr top = xmlDocGetRootElement(doc);
14 if (top == nullptr)
15 {
16 exit(2);
17 }
18
19 if (xmlStrcmp(top->name, (const xmlChar*) "world"))
20 {
21 exit(2);
22 }
23
24 xmlChar* startxKey = xmlGetProp(top, (xmlChar*) "startx");
25 if (startxKey == 0) exit(2);
26 startX = atoi((char*) startxKey);
27 xmlFree(startxKey);
28
29 xmlChar* startyKey = xmlGetProp(top, (xmlChar*) "starty");
30 if (startyKey == 0) exit(2);
31 startY = atoi((char*) startyKey);
32 xmlFree(startyKey);
33
34 xmlChar* startmapKey = xmlGetProp(top, (xmlChar*) "startmap");
35 if (startxKey == 0) exit(2);
36 startMap = atoi((char*) startmapKey);
37 xmlFree(startmapKey);
38
39 for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next)
40 {
41 if (!xmlStrcmp(node->name, (const xmlChar*) "map"))
42 {
43 xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id");
44 if (idKey == 0) exit(2);
45 int theId = atoi((char*) idKey);
46 xmlFree(idKey);
47
48 maps.emplace(theId, theId);
49 Map& map = maps[theId];
50
51 xmlChar* titleKey = xmlGetProp(node, (xmlChar*) "title");
52 if (titleKey == 0) exit(2);
53 map.setTitle((char*) titleKey);
54 xmlFree(titleKey);
55
56 for (xmlNodePtr mapNode = node->xmlChildrenNode; mapNode != NULL; mapNode = mapNode->next)
57 {
58 if (!xmlStrcmp(mapNode->name, (const xmlChar*) "environment"))
59 {
60 xmlChar* key = xmlNodeGetContent(mapNode);
61 int* mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int));
62 mapdata[0] = atoi(strtok((char*) key, ",\n"));
63 for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++)
64 {
65 mapdata[i] = atoi(strtok(NULL, ",\n"));
66 }
67 map.setMapdata(mapdata);
68 xmlFree(key);
69 } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "entity"))
70 {
71 Map::EntityData data;
72
73 xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type");
74 if (typeKey == 0) exit(2);
75 data.name = (char*) typeKey;
76 xmlFree(typeKey);
77
78 xmlChar* xKey = xmlGetProp(mapNode, (const xmlChar*) "x");
79 if (xKey == 0) exit(2);
80 data.position.first = atoi((char*) xKey);
81 xmlFree(xKey);
82
83 xmlChar* yKey = xmlGetProp(mapNode, (const xmlChar*) "y");
84 if (yKey == 0) exit(2);
85 data.position.second = atoi((char*) yKey);
86 xmlFree(yKey);
87
88 for (xmlNodePtr entityNode = mapNode->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next)
89 {
90 if (!xmlStrcmp(entityNode->name, (xmlChar*) "item"))
91 {
92 xmlChar* itemIdKey = xmlGetProp(entityNode, (const xmlChar*) "id");
93 if (itemIdKey == 0) exit(2);
94 std::string itemId = (char*) itemIdKey;
95 xmlFree(itemIdKey);
96
97 xmlChar* itemIdVal = xmlNodeGetContent(entityNode);
98 if (itemIdVal == 0) exit(2);
99 data.items[itemId] = atoi((char*) itemIdVal);
100 xmlFree(itemIdVal);
101 }
102 }
103
104 map.addEntity(data);
105 } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "adjacent"))
106 {
107 Map::MoveDir direction;
108 Map::MoveType moveType;
109 int mapId = 0;
110
111 xmlChar* dirKey = xmlGetProp(mapNode, (const xmlChar*) "dir");
112 if (dirKey == 0) exit(2);
113 direction = Map::moveDirForShort((char*) dirKey);
114 xmlFree(dirKey);
115
116 xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type");
117 if (typeKey == 0) exit(2);
118 moveType = Map::moveTypeForShort((char*) typeKey);
119 xmlFree(typeKey);
120
121 xmlChar* mapIdKey = xmlGetProp(mapNode, (const xmlChar*) "map");
122 if (mapIdKey != 0)
123 {
124 mapId = atoi((char*) mapIdKey);
125 }
126 xmlFree(mapIdKey);
127
128 map.setAdjacent(direction, moveType, mapId);
129 }
130 }
131 }
132 }
133
134 xmlFreeDoc(doc);
135}
136
137const Map& World::getMap(int id) const
138{
139 return maps.at(id);
140}
141
142const Map& World::getStartingMap() const
143{
144 return maps.at(startMap);
145}
146
147std::pair<int, int> World::getStartingPosition() const
148{
149 return std::make_pair(startX, startY);
150}
diff --git a/src/world.h b/src/world.h deleted file mode 100644 index f566487..0000000 --- a/src/world.h +++ /dev/null
@@ -1,21 +0,0 @@
1#ifndef WORLD_H
2#define WORLD_H
3
4#include <map>
5#include "map.h"
6
7class World {
8 public:
9 World(const char* filename);
10 const Map& getMap(int id) const;
11 const Map& getStartingMap() const;
12 std::pair<int, int> getStartingPosition() const;
13
14 private:
15 std::map<int, Map> maps;
16 int startMap;
17 int startX;
18 int startY;
19};
20
21#endif /* end of include guard: WORLD_H */