summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-02-18 12:35:45 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-02-18 12:35:45 -0500
commite16fb5be90c889c371cbb0ca2444735c2e12073c (patch)
treecbaa20e14a34c460b6c9886f266c4b4b6f62ae87
parented08b673c50b076042d8f0c49501372168142764 (diff)
downloadtherapy-e16fb5be90c889c371cbb0ca2444735c2e12073c.tar.gz
therapy-e16fb5be90c889c371cbb0ca2444735c2e12073c.tar.bz2
therapy-e16fb5be90c889c371cbb0ca2444735c2e12073c.zip
Implemented map adjacency
This brings along with it the ability to move to different maps, for which the PlayingSystem and PlayableComponent were introduced. The PlayingSystem is a general overseer system that handles big picture stuff like initializing the player and changing maps. The PlayableComponent represents the player. While the ControllableComponent is also likely to always only be on the player entity, the two are distinct by separation of concerns.

This also required a refactoring of how collisions are processed, because of a bug where the player can move to a new map when horizontal collisions are checked, and vertical collisions are skipped, causing the player to clip through the ground because the normal force was never handled.
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/collision.cpp97
-rw-r--r--src/collision.h81
-rw-r--r--src/components/mappable.h10
-rw-r--r--src/components/playable.h15
-rw-r--r--src/consts.h2
-rw-r--r--src/entity_manager.h10
-rw-r--r--src/game.cpp27
-rw-r--r--src/map.h70
-rw-r--r--src/systems/mapping.cpp28
-rw-r--r--src/systems/playing.cpp98
-rw-r--r--src/systems/playing.h21
-rw-r--r--src/systems/pondering.cpp347
-rw-r--r--src/systems/pondering.h11
-rw-r--r--src/world.cpp58
15 files changed, 717 insertions, 160 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e7bcb8..155063e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -55,6 +55,7 @@ add_executable(Aromatherapy
55 src/animation.cpp 55 src/animation.cpp
56 src/world.cpp 56 src/world.cpp
57 src/util.cpp 57 src/util.cpp
58 src/collision.cpp
58 src/renderer/renderer.cpp 59 src/renderer/renderer.cpp
59 src/renderer/mesh.cpp 60 src/renderer/mesh.cpp
60 src/renderer/shader.cpp 61 src/renderer/shader.cpp
@@ -64,6 +65,7 @@ add_executable(Aromatherapy
64 src/systems/animating.cpp 65 src/systems/animating.cpp
65 src/systems/mapping.cpp 66 src/systems/mapping.cpp
66 src/systems/orienting.cpp 67 src/systems/orienting.cpp
68 src/systems/playing.cpp
67) 69)
68 70
69set_property(TARGET Aromatherapy PROPERTY CXX_STANDARD 11) 71set_property(TARGET Aromatherapy PROPERTY CXX_STANDARD 11)
diff --git a/src/collision.cpp b/src/collision.cpp new file mode 100644 index 0000000..b747a90 --- /dev/null +++ b/src/collision.cpp
@@ -0,0 +1,97 @@
1#include "collision.h"
2
3bool Collision::operator<(const Collision& other) const
4{
5 // Most important is the type of collision
6 if (type_ != other.type_)
7 {
8 return (static_cast<int>(type_) > static_cast<int>(other.type_));
9 }
10
11 // Next, categorize the collisions arbitrarily based on direction
12 if (dir_ != other.dir_)
13 {
14 return (static_cast<int>(dir_) < static_cast<int>(other.dir_));
15 }
16
17 // We want to process closer collisions first
18 if (axis_ != other.axis_)
19 {
20 switch (dir_)
21 {
22 case Direction::left:
23 case Direction::up:
24 {
25 return (axis_ < other.axis_);
26 }
27
28 case Direction::right:
29 case Direction::down:
30 {
31 return (axis_ > other.axis_);
32 }
33 }
34 }
35
36 // Order the remaining attributes arbitrarily
37 return std::tie(collider_, lower_, upper_) <
38 std::tie(other.collider_, other.lower_, other.upper_);
39}
40
41bool Collision::isColliding(
42 double x,
43 double y,
44 int w,
45 int h) const
46{
47 int right = x + w;
48 int bottom = y + h;
49
50 switch (dir_)
51 {
52 case Direction::left:
53 case Direction::right:
54 {
55 if (!((bottom > lower_) && (y < upper_)))
56 {
57 return false;
58 }
59
60 break;
61 }
62
63 case Direction::up:
64 case Direction::down:
65 {
66 if (!((right > lower_) && (x < upper_)))
67 {
68 return false;
69 }
70
71 break;
72 }
73 }
74
75 switch (dir_)
76 {
77 case Direction::left:
78 {
79 return (axis_ >= x);
80 }
81
82 case Direction::right:
83 {
84 return (axis_ <= right);
85 }
86
87 case Direction::up:
88 {
89 return (axis_ >= y);
90 }
91
92 case Direction::down:
93 {
94 return (axis_ <= bottom);
95 }
96 }
97}
diff --git a/src/collision.h b/src/collision.h new file mode 100644 index 0000000..e5371f8 --- /dev/null +++ b/src/collision.h
@@ -0,0 +1,81 @@
1#ifndef COLLISION_H_53D84877
2#define COLLISION_H_53D84877
3
4#include "entity_manager.h"
5#include "direction.h"
6
7class Collision {
8public:
9
10 using id_type = EntityManager::id_type;
11
12 // Types are defined in descending priority order
13 enum class Type {
14 wall,
15 platform,
16 adjacency,
17 warp,
18 danger
19 };
20
21 Collision(
22 id_type collider,
23 Direction dir,
24 Type type,
25 int axis,
26 double lower,
27 double upper) :
28 collider_(collider),
29 dir_(dir),
30 type_(type),
31 axis_(axis),
32 lower_(lower),
33 upper_(upper)
34 {
35 }
36
37 inline id_type getCollider() const
38 {
39 return collider_;
40 }
41
42 inline Direction getDirection() const
43 {
44 return dir_;
45 }
46
47 inline Type getType() const
48 {
49 return type_;
50 }
51
52 inline int getAxis() const
53 {
54 return axis_;
55 }
56
57 inline double getLower() const
58 {
59 return lower_;
60 }
61
62 inline double getUpper() const
63 {
64 return upper_;
65 }
66
67 bool operator<(const Collision& other) const;
68
69 bool isColliding(double x, double y, int w, int h) const;
70
71private:
72
73 id_type collider_;
74 Direction dir_;
75 Type type_;
76 int axis_;
77 double lower_;
78 double upper_;
79};
80
81#endif /* end of include guard: COLLISION_H_53D84877 */
diff --git a/src/components/mappable.h b/src/components/mappable.h index 2dbab77..633cdf4 100644 --- a/src/components/mappable.h +++ b/src/components/mappable.h
@@ -4,6 +4,7 @@
4#include <map> 4#include <map>
5#include "component.h" 5#include "component.h"
6#include "renderer/texture.h" 6#include "renderer/texture.h"
7#include "collision.h"
7#include "map.h" 8#include "map.h"
8 9
9class MappableComponent : public Component { 10class MappableComponent : public Component {
@@ -12,14 +13,7 @@ public:
12 class Boundary { 13 class Boundary {
13 public: 14 public:
14 15
15 enum class Type { 16 using Type = Collision::Type;
16 wall,
17 wrap,
18 teleport,
19 reverse,
20 platform,
21 danger
22 };
23 17
24 Boundary( 18 Boundary(
25 double axis, 19 double axis,
diff --git a/src/components/playable.h b/src/components/playable.h new file mode 100644 index 0000000..a6e71b0 --- /dev/null +++ b/src/components/playable.h
@@ -0,0 +1,15 @@
1#ifndef PLAYABLE_H_DDC566C3
2#define PLAYABLE_H_DDC566C3
3
4#include "component.h"
5
6class PlayableComponent : public Component {
7public:
8
9 bool changingMap = false;
10 int newMapId = -1;
11 double newMapX = 0;
12 double newMapY = 0;
13};
14
15#endif /* end of include guard: PLAYABLE_H_DDC566C3 */
diff --git a/src/consts.h b/src/consts.h index 581018d..a065159 100644 --- a/src/consts.h +++ b/src/consts.h
@@ -7,7 +7,7 @@ const int GAME_WIDTH = 320;
7const int GAME_HEIGHT = 200; 7const int GAME_HEIGHT = 200;
8const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH; 8const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH;
9const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1; 9const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1;
10const int WALL_GAP = 6; 10const int WALL_GAP = 5;
11const int TILESET_COLS = 8; 11const int TILESET_COLS = 8;
12const int FONT_COLS = 16; 12const int FONT_COLS = 16;
13 13
diff --git a/src/entity_manager.h b/src/entity_manager.h index 65fa6ca..1e8d31c 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h
@@ -26,6 +26,7 @@ private:
26 26
27 database_type entities; 27 database_type entities;
28 std::vector<bool> slotAvailable; 28 std::vector<bool> slotAvailable;
29 std::set<id_type> allEntities;
29 std::map<std::set<std::type_index>, std::set<id_type>> cachedComponents; 30 std::map<std::set<std::type_index>, std::set<id_type>> cachedComponents;
30 31
31 id_type nextEntityID = 0; 32 id_type nextEntityID = 0;
@@ -59,12 +60,14 @@ public:
59 // If the database is saturated, add a new element for the new entity. 60 // If the database is saturated, add a new element for the new entity.
60 entities.emplace_back(); 61 entities.emplace_back();
61 slotAvailable.push_back(false); 62 slotAvailable.push_back(false);
63 allEntities.insert(nextEntityID);
62 64
63 return nextEntityID++; 65 return nextEntityID++;
64 } else { 66 } else {
65 // If there is an available slot in the database, use it. 67 // If there is an available slot in the database, use it.
66 id_type id = nextEntityID++; 68 id_type id = nextEntityID++;
67 slotAvailable[id] = false; 69 slotAvailable[id] = false;
70 allEntities.insert(id);
68 71
69 // Fast forward the next available slot pointer to an available slot. 72 // Fast forward the next available slot pointer to an available slot.
70 while ((nextEntityID < entities.size()) && !slotAvailable[nextEntityID]) 73 while ((nextEntityID < entities.size()) && !slotAvailable[nextEntityID])
@@ -89,6 +92,8 @@ public:
89 cache.second.erase(entity); 92 cache.second.erase(entity);
90 } 93 }
91 94
95 allEntities.erase(entity);
96
92 // Destroy the data 97 // Destroy the data
93 entities[entity].components.clear(); 98 entities[entity].components.clear();
94 99
@@ -202,6 +207,11 @@ public:
202 207
203 return getEntitiesWithComponentsHelper<R...>(componentTypes); 208 return getEntitiesWithComponentsHelper<R...>(componentTypes);
204 } 209 }
210
211 const std::set<id_type>& getEntities() const
212 {
213 return allEntities;
214 }
205}; 215};
206 216
207template <> 217template <>
diff --git a/src/game.cpp b/src/game.cpp index 228ff23..f245e7c 100644 --- a/src/game.cpp +++ b/src/game.cpp
@@ -9,6 +9,7 @@
9#include "systems/animating.h" 9#include "systems/animating.h"
10#include "systems/mapping.h" 10#include "systems/mapping.h"
11#include "systems/orienting.h" 11#include "systems/orienting.h"
12#include "systems/playing.h"
12#include "animation.h" 13#include "animation.h"
13#include "consts.h" 14#include "consts.h"
14 15
@@ -28,36 +29,14 @@ void key_callback(GLFWwindow* window, int key, int, int action, int)
28 29
29Game::Game() : world_("res/maps.xml") 30Game::Game() : world_("res/maps.xml")
30{ 31{
32 systemManager_.emplaceSystem<PlayingSystem>(*this);
31 systemManager_.emplaceSystem<ControllingSystem>(*this); 33 systemManager_.emplaceSystem<ControllingSystem>(*this);
32 systemManager_.emplaceSystem<OrientingSystem>(*this); 34 systemManager_.emplaceSystem<OrientingSystem>(*this);
33 systemManager_.emplaceSystem<PonderingSystem>(*this); 35 systemManager_.emplaceSystem<PonderingSystem>(*this);
34 systemManager_.emplaceSystem<MappingSystem>(*this); 36 systemManager_.emplaceSystem<MappingSystem>(*this);
35 systemManager_.emplaceSystem<AnimatingSystem>(*this); 37 systemManager_.emplaceSystem<AnimatingSystem>(*this);
36 38
37 int player = entityManager_.emplaceEntity(); 39 systemManager_.getSystem<PlayingSystem>().initPlayer();
38
39 AnimationSet playerGraphics {"res/Starla.png", 10, 12, 6};
40 playerGraphics.emplaceAnimation("stillLeft", 3, 1, 1);
41 playerGraphics.emplaceAnimation("stillRight", 0, 1, 1);
42 playerGraphics.emplaceAnimation("walkingLeft", 4, 2, 10);
43 playerGraphics.emplaceAnimation("walkingRight", 1, 2, 10);
44
45 entityManager_.emplaceComponent<AnimatableComponent>(
46 player,
47 std::move(playerGraphics),
48 "stillLeft");
49
50 entityManager_.emplaceComponent<TransformableComponent>(
51 player,
52 203, 44, 10, 12);
53
54 systemManager_.getSystem<PonderingSystem>().initializeBody(
55 player,
56 PonderableComponent::Type::freefalling);
57
58 entityManager_.emplaceComponent<ControllableComponent>(player);
59 entityManager_.emplaceComponent<OrientableComponent>(player);
60
61 systemManager_.getSystem<MappingSystem>().loadMap(world_.getStartingMapId()); 40 systemManager_.getSystem<MappingSystem>().loadMap(world_.getStartingMapId());
62 41
63 glfwSwapInterval(1); 42 glfwSwapInterval(1);
diff --git a/src/map.h b/src/map.h index 9177870..6fe1e62 100644 --- a/src/map.h +++ b/src/map.h
@@ -10,13 +10,55 @@
10class Map { 10class Map {
11public: 11public:
12 12
13 class Adjacent {
14 public:
15
16 enum class Type {
17 wall,
18 wrap,
19 warp,
20 reverse
21 };
22
23 Adjacent(
24 Type type = Type::wall,
25 int mapId = -1) :
26 type_(type),
27 mapId_(mapId)
28 {
29 }
30
31 inline Type getType() const
32 {
33 return type_;
34 }
35
36 inline int getMapId() const
37 {
38 return mapId_;
39 }
40
41 private:
42
43 Type type_;
44 int mapId_;
45 };
46
13 Map( 47 Map(
14 int id, 48 int id,
15 std::vector<int> tiles, 49 std::vector<int> tiles,
16 std::string title) : 50 std::string title,
51 Adjacent leftAdjacent,
52 Adjacent rightAdjacent,
53 Adjacent upAdjacent,
54 Adjacent downAdjacent) :
17 id_(id), 55 id_(id),
18 tiles_(std::move(tiles)), 56 tiles_(std::move(tiles)),
19 title_(std::move(title)) 57 title_(std::move(title)),
58 leftAdjacent_(std::move(leftAdjacent)),
59 rightAdjacent_(std::move(rightAdjacent)),
60 upAdjacent_(std::move(upAdjacent)),
61 downAdjacent_(std::move(downAdjacent))
20 { 62 {
21 } 63 }
22 64
@@ -35,11 +77,35 @@ public:
35 return title_; 77 return title_;
36 } 78 }
37 79
80 inline const Adjacent& getLeftAdjacent() const
81 {
82 return leftAdjacent_;
83 }
84
85 inline const Adjacent& getRightAdjacent() const
86 {
87 return rightAdjacent_;
88 }
89
90 inline const Adjacent& getUpAdjacent() const
91 {
92 return upAdjacent_;
93 }
94
95 inline const Adjacent& getDownAdjacent() const
96 {
97 return downAdjacent_;
98 }
99
38private: 100private:
39 101
40 int id_; 102 int id_;
41 std::vector<int> tiles_; 103 std::vector<int> tiles_;
42 std::string title_; 104 std::string title_;
105 Adjacent leftAdjacent_;
106 Adjacent rightAdjacent_;
107 Adjacent upAdjacent_;
108 Adjacent downAdjacent_;
43}; 109};
44 110
45#endif /* end of include guard: MAP_H_74055FC0 */ 111#endif /* end of include guard: MAP_H_74055FC0 */
diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index 120a27a..05167c1 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp
@@ -93,6 +93,34 @@ void MappingSystem::loadMap(size_t mapId)
93 93
94 const Map& map = game_.getWorld().getMap(mappable.getMapId()); 94 const Map& map = game_.getWorld().getMap(mappable.getMapId());
95 95
96 addBoundary(
97 mappable.getLeftBoundaries(),
98 -WALL_GAP,
99 0,
100 MAP_HEIGHT * TILE_HEIGHT,
101 MappableComponent::Boundary::Type::adjacency);
102
103 addBoundary(
104 mappable.getRightBoundaries(),
105 GAME_WIDTH + WALL_GAP,
106 0,
107 MAP_HEIGHT * TILE_HEIGHT,
108 MappableComponent::Boundary::Type::adjacency);
109
110 addBoundary(
111 mappable.getUpBoundaries(),
112 -WALL_GAP,
113 0,
114 GAME_WIDTH,
115 MappableComponent::Boundary::Type::adjacency);
116
117 addBoundary(
118 mappable.getDownBoundaries(),
119 MAP_HEIGHT * TILE_HEIGHT + WALL_GAP,
120 0,
121 GAME_WIDTH,
122 MappableComponent::Boundary::Type::adjacency);
123
96 for (size_t i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++) 124 for (size_t i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++)
97 { 125 {
98 size_t x = i % MAP_WIDTH; 126 size_t x = i % MAP_WIDTH;
diff --git a/src/systems/playing.cpp b/src/systems/playing.cpp new file mode 100644 index 0000000..2c6a419 --- /dev/null +++ b/src/systems/playing.cpp
@@ -0,0 +1,98 @@
1#include "playing.h"
2#include "game.h"
3#include "components/transformable.h"
4#include "components/animatable.h"
5#include "components/playable.h"
6#include "components/controllable.h"
7#include "components/orientable.h"
8#include "systems/mapping.h"
9#include "systems/pondering.h"
10#include "animation.h"
11
12void PlayingSystem::tick(double)
13{
14 // Check if we need to change the map
15 auto players = game_.getEntityManager().getEntitiesWithComponents<
16 PlayableComponent>();
17
18 for (id_type player : players)
19 {
20 auto& playable = game_.getEntityManager().
21 getComponent<PlayableComponent>(player);
22
23 if (playable.changingMap)
24 {
25 // Change the map!
26 auto entities = game_.getEntityManager().getEntities();
27
28 for (id_type entity : entities)
29 {
30 if (entity != player)
31 {
32 game_.getEntityManager().deleteEntity(entity);
33 }
34 }
35
36 game_.getSystemManager().getSystem<MappingSystem>().
37 loadMap(playable.newMapId);
38
39 auto& transformable = game_.getEntityManager().
40 getComponent<TransformableComponent>(player);
41
42 transformable.setX(playable.newMapX);
43 transformable.setY(playable.newMapY);
44
45 playable.changingMap = false;
46
47 break;
48 }
49 }
50}
51
52void PlayingSystem::initPlayer()
53{
54 id_type player = game_.getEntityManager().emplaceEntity();
55
56 AnimationSet playerGraphics {"res/Starla.png", 10, 12, 6};
57 playerGraphics.emplaceAnimation("stillLeft", 3, 1, 1);
58 playerGraphics.emplaceAnimation("stillRight", 0, 1, 1);
59 playerGraphics.emplaceAnimation("walkingLeft", 4, 2, 10);
60 playerGraphics.emplaceAnimation("walkingRight", 1, 2, 10);
61
62 game_.getEntityManager().emplaceComponent<AnimatableComponent>(
63 player,
64 std::move(playerGraphics),
65 "stillLeft");
66
67 game_.getEntityManager().emplaceComponent<TransformableComponent>(
68 player,
69 203, 44, 10, 12);
70
71 game_.getSystemManager().getSystem<PonderingSystem>().initializeBody(
72 player,
73 PonderableComponent::Type::freefalling);
74
75 game_.getEntityManager().emplaceComponent<ControllableComponent>(player);
76 game_.getEntityManager().emplaceComponent<OrientableComponent>(player);
77 game_.getEntityManager().emplaceComponent<PlayableComponent>(player);
78}
79
80void PlayingSystem::changeMap(
81 size_t mapId,
82 double x,
83 double y)
84{
85 auto players = game_.getEntityManager().getEntitiesWithComponents<
86 PlayableComponent>();
87
88 for (id_type player : players)
89 {
90 auto& playable = game_.getEntityManager().
91 getComponent<PlayableComponent>(player);
92
93 playable.changingMap = true;
94 playable.newMapId = mapId;
95 playable.newMapX = x;
96 playable.newMapY = y;
97 }
98}
diff --git a/src/systems/playing.h b/src/systems/playing.h new file mode 100644 index 0000000..c98a464 --- /dev/null +++ b/src/systems/playing.h
@@ -0,0 +1,21 @@
1#ifndef PLAYING_H_70A54F7D
2#define PLAYING_H_70A54F7D
3
4#include "system.h"
5
6class PlayingSystem : public System {
7public:
8
9 PlayingSystem(Game& game) : System(game)
10 {
11 }
12
13 void tick(double dt);
14
15 void initPlayer();
16
17 void changeMap(size_t mapId, double x, double y);
18
19};
20
21#endif /* end of include guard: PLAYING_H_70A54F7D */
diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 4a165b1..2490dc9 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp
@@ -1,11 +1,14 @@
1#include "pondering.h" 1#include "pondering.h"
2#include <queue>
2#include "game.h" 3#include "game.h"
3#include "components/ponderable.h" 4#include "components/ponderable.h"
4#include "components/transformable.h" 5#include "components/transformable.h"
5#include "components/orientable.h" 6#include "components/orientable.h"
6#include "components/mappable.h" 7#include "components/mappable.h"
7#include "systems/orienting.h" 8#include "systems/orienting.h"
9#include "systems/playing.h"
8#include "consts.h" 10#include "consts.h"
11#include "collision.h"
9 12
10void PonderingSystem::tick(double dt) 13void PonderingSystem::tick(double dt)
11{ 14{
@@ -42,6 +45,9 @@ void PonderingSystem::tick(double dt)
42 bool oldGrounded = ponderable.isGrounded(); 45 bool oldGrounded = ponderable.isGrounded();
43 ponderable.setGrounded(false); 46 ponderable.setGrounded(false);
44 47
48 std::priority_queue<Collision> collisions;
49
50 // Find collisions
45 for (id_type mapEntity : maps) 51 for (id_type mapEntity : maps)
46 { 52 {
47 auto& mappable = game_.getEntityManager(). 53 auto& mappable = game_.getEntityManager().
@@ -57,13 +63,13 @@ void PonderingSystem::tick(double dt)
57 && (oldY < it->second.getUpper())) 63 && (oldY < it->second.getUpper()))
58 { 64 {
59 // We have a collision! 65 // We have a collision!
60 processCollision( 66 collisions.emplace(
61 entity, 67 mapEntity,
62 Direction::left, 68 Direction::left,
63 newX, 69 it->second.getType(),
64 newY,
65 it->first, 70 it->first,
66 it->second.getType()); 71 it->second.getLower(),
72 it->second.getUpper());
67 } 73 }
68 } 74 }
69 } else if (newX > oldX) 75 } else if (newX > oldX)
@@ -77,13 +83,13 @@ void PonderingSystem::tick(double dt)
77 && (oldY < it->second.getUpper())) 83 && (oldY < it->second.getUpper()))
78 { 84 {
79 // We have a collision! 85 // We have a collision!
80 processCollision( 86 collisions.emplace(
81 entity, 87 mapEntity,
82 Direction::right, 88 Direction::right,
83 newX, 89 it->second.getType(),
84 newY,
85 it->first, 90 it->first,
86 it->second.getType()); 91 it->second.getLower(),
92 it->second.getUpper());
87 } 93 }
88 } 94 }
89 } 95 }
@@ -98,13 +104,13 @@ void PonderingSystem::tick(double dt)
98 && (oldX < it->second.getUpper())) 104 && (oldX < it->second.getUpper()))
99 { 105 {
100 // We have a collision! 106 // We have a collision!
101 processCollision( 107 collisions.emplace(
102 entity, 108 mapEntity,
103 Direction::up, 109 Direction::up,
104 newX, 110 it->second.getType(),
105 newY,
106 it->first, 111 it->first,
107 it->second.getType()); 112 it->second.getLower(),
113 it->second.getUpper());
108 } 114 }
109 } 115 }
110 } else if (newY > oldY) 116 } else if (newY > oldY)
@@ -118,13 +124,221 @@ void PonderingSystem::tick(double dt)
118 && (oldX < it->second.getUpper())) 124 && (oldX < it->second.getUpper()))
119 { 125 {
120 // We have a collision! 126 // We have a collision!
121 processCollision( 127 collisions.emplace(
122 entity, 128 mapEntity,
123 Direction::down, 129 Direction::down,
124 newX, 130 it->second.getType(),
125 newY,
126 it->first, 131 it->first,
127 it->second.getType()); 132 it->second.getLower(),
133 it->second.getUpper());
134 }
135 }
136 }
137 }
138
139 // Process collisions in order of priority
140 while (!collisions.empty())
141 {
142 Collision collision = collisions.top();
143 collisions.pop();
144
145 // Make sure that they are still colliding
146 if (!collision.isColliding(
147 newX,
148 newY,
149 transformable.getW(),
150 transformable.getH()))
151 {
152 continue;
153 }
154
155 bool touchedWall = false;
156 bool stopProcessing = false;
157
158 switch (collision.getType())
159 {
160 case Collision::Type::wall:
161 {
162 touchedWall = true;
163
164 break;
165 }
166
167 case Collision::Type::platform:
168 {
169 if (game_.getEntityManager().
170 hasComponent<OrientableComponent>(entity))
171 {
172 auto& orientable = game_.getEntityManager().
173 getComponent<OrientableComponent>(entity);
174
175 if (orientable.getDropState() !=
176 OrientableComponent::DropState::none)
177 {
178 orientable.setDropState(OrientableComponent::DropState::active);
179 } else {
180 touchedWall = true;
181 }
182 } else {
183 touchedWall = true;
184 }
185
186 break;
187 }
188
189 case Collision::Type::adjacency:
190 {
191 auto& mappable = game_.getEntityManager().
192 getComponent<MappableComponent>(collision.getCollider());
193 const Map& map = game_.getWorld().getMap(mappable.getMapId());
194 auto& adj = [&] () -> const Map::Adjacent& {
195 switch (collision.getDirection())
196 {
197 case Direction::left: return map.getLeftAdjacent();
198 case Direction::right: return map.getRightAdjacent();
199 case Direction::up: return map.getUpAdjacent();
200 case Direction::down: return map.getDownAdjacent();
201 }
202 }();
203
204 switch (adj.getType())
205 {
206 case Map::Adjacent::Type::wall:
207 {
208 touchedWall = true;
209
210 break;
211 }
212
213 case Map::Adjacent::Type::wrap:
214 {
215 switch (collision.getDirection())
216 {
217 case Direction::left:
218 {
219 newX = GAME_WIDTH + WALL_GAP - transformable.getW();
220
221 break;
222 }
223
224 case Direction::right:
225 {
226 newX = -WALL_GAP;
227
228 break;
229 }
230
231 case Direction::up:
232 {
233 newY = MAP_HEIGHT * TILE_HEIGHT + WALL_GAP -
234 transformable.getH();
235
236 break;
237 }
238
239 case Direction::down:
240 {
241 newY = -WALL_GAP;
242
243 break;
244 }
245 }
246 }
247
248 case Map::Adjacent::Type::warp:
249 {
250 double warpX = newX;
251 double warpY = newY;
252
253 switch (collision.getDirection())
254 {
255 case Direction::left:
256 {
257 warpX = GAME_WIDTH + WALL_GAP - transformable.getW();
258
259 break;
260 }
261
262 case Direction::right:
263 {
264 warpX = -WALL_GAP;
265
266 break;
267 }
268
269 case Direction::up:
270 {
271 warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.getH();
272
273 break;
274 }
275
276 case Direction::down:
277 {
278 warpY = -WALL_GAP;
279
280 break;
281 }
282 }
283
284 game_.getSystemManager().getSystem<PlayingSystem>().
285 changeMap(adj.getMapId(), warpX, warpY);
286
287 stopProcessing = true;
288
289 break;
290 }
291 }
292 }
293
294 default:
295 {
296 // Not yet implemented.
297
298 break;
299 }
300 }
301
302 if (stopProcessing)
303 {
304 break;
305 }
306
307 if (touchedWall)
308 {
309 switch (collision.getDirection())
310 {
311 case Direction::left:
312 {
313 newX = collision.getAxis();
314 ponderable.setVelocityX(0.0);
315
316 break;
317 }
318
319 case Direction::right:
320 {
321 newX = collision.getAxis() - transformable.getW();
322 ponderable.setVelocityX(0.0);
323
324 break;
325 }
326
327 case Direction::up:
328 {
329 newY = collision.getAxis();
330 ponderable.setVelocityY(0.0);
331
332 break;
333 }
334
335 case Direction::down:
336 {
337 newY = collision.getAxis() - transformable.getH();
338 ponderable.setVelocityY(0.0);
339 ponderable.setGrounded(true);
340
341 break;
128 } 342 }
129 } 343 }
130 } 344 }
@@ -173,96 +387,3 @@ void PonderingSystem::initializeBody(
173 ponderable.setAccelY(NORMAL_GRAVITY); 387 ponderable.setAccelY(NORMAL_GRAVITY);
174 } 388 }
175} 389}
176
177void PonderingSystem::processCollision(
178 id_type entity,
179 Direction dir,
180 double& newX,
181 double& newY,
182 int axis,
183 MappableComponent::Boundary::Type type)
184{
185 auto& ponderable = game_.getEntityManager().
186 getComponent<PonderableComponent>(entity);
187
188 auto& transformable = game_.getEntityManager().
189 getComponent<TransformableComponent>(entity);
190
191 bool touchedGround = false;
192
193 switch (type)
194 {
195 case MappableComponent::Boundary::Type::wall:
196 {
197 switch (dir)
198 {
199 case Direction::left:
200 {
201 newX = axis;
202 ponderable.setVelocityX(0.0);
203
204 break;
205 }
206
207 case Direction::right:
208 {
209 newX = axis - transformable.getW();
210 ponderable.setVelocityX(0.0);
211
212 break;
213 }
214
215 case Direction::up:
216 {
217 newY = axis;
218 ponderable.setVelocityY(0.0);
219
220 break;
221 }
222
223 case Direction::down:
224 {
225 touchedGround = true;
226
227 break;
228 }
229 }
230
231 break;
232 }
233
234 case MappableComponent::Boundary::Type::platform:
235 {
236 if (game_.getEntityManager().hasComponent<OrientableComponent>(entity))
237 {
238 auto& orientable = game_.getEntityManager().
239 getComponent<OrientableComponent>(entity);
240
241 if (orientable.getDropState() != OrientableComponent::DropState::none)
242 {
243 orientable.setDropState(OrientableComponent::DropState::active);
244 } else {
245 touchedGround = true;
246 }
247 } else {
248 touchedGround = true;
249 }
250
251 break;
252 }
253
254 default:
255 {
256 // Not yet implemented.
257
258 break;
259 }
260 }
261
262 if (touchedGround)
263 {
264 newY = axis - transformable.getH();
265 ponderable.setVelocityY(0.0);
266 ponderable.setGrounded(true);
267 }
268}
diff --git a/src/systems/pondering.h b/src/systems/pondering.h index a16622b..d70525b 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h
@@ -2,7 +2,6 @@
2#define PONDERING_H_F2530E0E 2#define PONDERING_H_F2530E0E
3 3
4#include "system.h" 4#include "system.h"
5#include "components/mappable.h"
6#include "components/ponderable.h" 5#include "components/ponderable.h"
7#include "direction.h" 6#include "direction.h"
8 7
@@ -17,16 +16,6 @@ public:
17 16
18 void initializeBody(id_type entity, PonderableComponent::Type type); 17 void initializeBody(id_type entity, PonderableComponent::Type type);
19 18
20private:
21
22 void processCollision(
23 id_type entity,
24 Direction dir,
25 double& newX,
26 double& newY,
27 int axis,
28 MappableComponent::Boundary::Type type);
29
30}; 19};
31 20
32#endif /* end of include guard: PONDERING_H_F2530E0E */ 21#endif /* end of include guard: PONDERING_H_F2530E0E */
diff --git a/src/world.cpp b/src/world.cpp index 9b1e4f6..3b6bd41 100644 --- a/src/world.cpp +++ b/src/world.cpp
@@ -63,6 +63,10 @@ World::World(std::string filename)
63 xmlFree(key); 63 xmlFree(key);
64 64
65 std::vector<int> mapTiles; 65 std::vector<int> mapTiles;
66 Map::Adjacent leftAdj;
67 Map::Adjacent rightAdj;
68 Map::Adjacent upAdj;
69 Map::Adjacent downAdj;
66 70
67 for (xmlNodePtr mapNode = node->xmlChildrenNode; 71 for (xmlNodePtr mapNode = node->xmlChildrenNode;
68 mapNode != nullptr; 72 mapNode != nullptr;
@@ -82,6 +86,54 @@ World::World(std::string filename)
82 } 86 }
83 87
84 xmlFree(key); 88 xmlFree(key);
89 } else if (!xmlStrcmp(
90 mapNode->name,
91 reinterpret_cast<const xmlChar*>("adjacent")))
92 {
93 key = getProp(mapNode, "type");
94 std::string adjTypeStr(reinterpret_cast<char*>(key));
95 xmlFree(key);
96
97 Map::Adjacent::Type adjType;
98 if (adjTypeStr == "wall")
99 {
100 adjType = Map::Adjacent::Type::wall;
101 } else if (adjTypeStr == "wrap")
102 {
103 adjType = Map::Adjacent::Type::wrap;
104 } else if (adjTypeStr == "warp")
105 {
106 adjType = Map::Adjacent::Type::warp;
107 } else if (adjTypeStr == "reverseWarp")
108 {
109 adjType = Map::Adjacent::Type::reverse;
110 } else {
111 throw std::logic_error("Invalid adjacency type");
112 }
113
114 key = getProp(mapNode, "map");
115 int adjMapId = atoi(reinterpret_cast<char*>(key));
116 xmlFree(key);
117
118 key = getProp(mapNode, "dir");
119 std::string adjDir(reinterpret_cast<char*>(key));
120 xmlFree(key);
121
122 if (adjDir == "left")
123 {
124 leftAdj = {adjType, adjMapId};
125 } else if (adjDir == "right")
126 {
127 rightAdj = {adjType, adjMapId};
128 } else if (adjDir == "up")
129 {
130 upAdj = {adjType, adjMapId};
131 } else if (adjDir == "down")
132 {
133 downAdj = {adjType, adjMapId};
134 } else {
135 throw std::logic_error("Invalid adjacency direction");
136 }
85 } 137 }
86 } 138 }
87 139
@@ -91,7 +143,11 @@ World::World(std::string filename)
91 std::forward_as_tuple( 143 std::forward_as_tuple(
92 mapId, 144 mapId,
93 std::move(mapTiles), 145 std::move(mapTiles),
94 std::move(mapTitle))); 146 std::move(mapTitle),
147 leftAdj,
148 rightAdj,
149 upAdj,
150 downAdj));
95 } 151 }
96 } 152 }
97 153