]> git.localhorst.tv Git - orbi.git/blob - src/world/World.cpp
don't reset speed if heading away from a surface
[orbi.git] / src / world / World.cpp
1 #include "World.h"
2
3 #include "Collision.h"
4 #include "../graphics/const.h"
5
6 #include <algorithm>
7 #include <cmath>
8
9 using namespace std;
10
11
12 namespace orbi {
13
14 World::World(Vector<int> size)
15 : size(size)
16 , count(size.x * size.y)
17 , gravity(0, 5)
18 , terminal(50, 50)
19 , fixSpeed(5)
20 , tiles(count) {
21
22 }
23
24
25 void World::Update(float dt) {
26         for (Entity &e : entities) {
27                 if (e.onGround) {
28                         e.Update(dt, Vector<float>(), terminal);
29                         e.onGround = false;
30                 } else {
31                         e.Update(dt, gravity, terminal);
32                 }
33
34                 BoundsCollision(e, dt);
35                 TileCollision(e, dt);
36
37         }
38 }
39
40 void World::BoundsCollision(Entity &e, float dt) {
41         if (e.vbox.Top() < 0) {
42                 e.Move(Vector<float>(0, -e.vbox.Top()));
43                 if (e.vel.y < 0) {
44                         e.vel.y = 0;
45                 }
46         }
47         if (e.vbox.Bottom() > size.y) {
48                 e.Move(Vector<float>(0, size.y - e.vbox.Bottom()));
49                 if (e.vel.y > 0) {
50                         e.vel.y = 0;
51                 }
52                 e.onGround = true;
53         }
54         if (e.hbox.Right() > size.x) {
55                 e.Move(Vector<float>(size.x - e.hbox.Right(), 0));
56                 if (e.vel.x > 0) {
57                         e.vel.x = 0;
58                 }
59         }
60         if (e.hbox.Left() < 0) {
61                 e.Move(Vector<float>(-e.hbox.Left(), 0));
62                 if (e.vel.x < 0) {
63                         e.vel.x = 0;
64                 }
65         }
66 }
67
68 void World::TileCollision(Entity &e, float dt) {
69         Vector<float> response;
70
71         // top
72         for (int x = e.vbox.Left(), y = e.vbox.Top(),
73                         end = std::ceil(e.vbox.Right()); x < end; ++x) {
74                 const Tile &tile = TileAt(Vector<int>(x, y));
75                 if (tile.IsSolid()) {
76                         response.y = y + 1 - e.vbox.Top();
77                         if (e.vel.y < 0) {
78                                 e.vel.y = 0;
79                         }
80                         break;
81                 }
82         }
83
84         // bottom
85         for (int x = e.vbox.Left(), y = e.vbox.Bottom(),
86                         end = std::ceil(e.vbox.Right()); x < end; ++x) {
87                 const Tile &tile = TileAt(Vector<int>(x, y));
88                 if (tile.IsSolid()) {
89                         response.y = y - e.vbox.Bottom();
90                         e.onGround = true;
91                         if (e.vel.y > 0) {
92                                 e.vel.y = 0;
93                         }
94                         break;
95                 }
96         }
97         if (response.y <= 0) {
98                 // bottom, second row
99                 // due to the hbox's huge bottom gap
100                 for (int x = e.vbox.Left(), y = e.vbox.Bottom() - 1,
101                                 end = std::ceil(e.vbox.Right()); x < end; ++x) {
102                         const Tile &tile = TileAt(Vector<int>(x, y));
103                         if (tile.IsSolid()) {
104                                 response.y = -1;
105                                 e.onGround = true;
106                         if (e.vel.y > 0) {
107                                         e.vel.y = 0;
108                                 }
109                                 break;
110                         }
111                 }
112         }
113
114         // left
115         for (int y = e.hbox.Top(), x = e.hbox.Left(),
116                         end = std::ceil(e.hbox.Bottom()); y < end; ++y) {
117                 const Tile &tile = TileAt(Vector<int>(x, y));
118                 if (tile.IsSolid()) {
119                         response.x = x + 1 - e.hbox.Left();
120                         if (e.vel.x < 0) {
121                                 e.vel.x = 0;
122                         }
123                         break;
124                 }
125         }
126
127         // right
128         for (int y = e.hbox.Top(), x = e.hbox.Right(),
129                         end = std::ceil(e.hbox.Bottom()); y < end; ++y) {
130                 const Tile &tile = TileAt(Vector<int>(x, y));
131                 if (tile.IsSolid()) {
132                         response.x = x - e.hbox.Right();
133                         if (e.vel.x > 0) {
134                                 e.vel.x = 0;
135                         }
136                         break;
137                 }
138         }
139
140         if (response.x > fixSpeed * dt) {
141                 response.x = fixSpeed * dt;
142         } else if (response.x < -fixSpeed * dt) {
143                 response.x = -fixSpeed * dt;
144         }
145         if (response.y > fixSpeed * dt) {
146                 response.y = fixSpeed * dt;
147         } else if (response.y < -fixSpeed * dt) {
148                 response.y = -fixSpeed * dt;
149         }
150         e.Move(response);
151 }
152
153 void World::EntityCollision() {
154         if (entities.size() <= 1) return;
155
156         auto firstEnd(entities.end());
157         --firstEnd;
158         for (auto first(entities.begin()); first != firstEnd; ++first) {
159                 auto second(first);
160                 ++second;
161                 for (auto secondEnd(entities.end()); second != secondEnd; ++second) {
162                         if (first->bounds.Intersects(second->bounds)) {
163                                 // damage + knockback
164                         }
165                 }
166         }
167 }
168
169
170 Entity &World::AddEntity(const Entity &e) {
171         entities.emplace_back(e);
172         return entities.back();
173 }
174
175 }