]> git.localhorst.tv Git - orbi.git/blobdiff - src/world/World.cpp
hbox/vbox implementation
[orbi.git] / src / world / World.cpp
index 7276ece6fdaa5b16519e3e24c0724e16a6b2d7f8..c76f8608bb82b30c4aaadda76413658df2fe0999 100644 (file)
@@ -3,6 +3,9 @@
 #include "Collision.h"
 #include "../graphics/const.h"
 
+#include <algorithm>
+#include <cmath>
+
 
 namespace orbi {
 
@@ -11,6 +14,7 @@ World::World(Vector<int> size)
 , count(size.x * size.y)
 , gravity(0, 5)
 , terminal(50, 50)
+, fixSpeed(5)
 , tiles(count) {
 
 }
@@ -21,74 +25,105 @@ void World::Update(float dt) {
                e.Update(dt, gravity, terminal);
                e.onGround = false;
 
-               const AABB &b = e.bounds;
+               BoundsCollision(e, dt);
+               TileCollision(e, dt);
+
+       }
+}
+
+void World::BoundsCollision(Entity &e, float dt) {
+       if (e.vbox.Top() < 0) {
+               e.Move(Vector<float>(0, -e.vbox.Top()));
+               e.vel.y = 0;
+       }
+       if (e.vbox.Bottom() > size.y) {
+               e.Move(Vector<float>(0, size.y - e.vbox.Bottom()));
+               e.vel.y = 0;
+               e.onGround = true;
+       }
+       if (e.hbox.Right() > size.x) {
+               e.Move(Vector<float>(size.x - e.hbox.Right(), 0));
+               e.vel.x = 0;
+       }
+       if (e.hbox.Left() < 0) {
+               e.Move(Vector<float>(-e.hbox.Left(), 0));
+               e.vel.x = 0;
+       }
+}
+
+void World::TileCollision(Entity &e, float dt) {
+       Vector<float> response;
 
-               // world bounds collision
-               if (b.Top() < 0) {
-                       e.Move(Vector<float>(0, -b.Top()));
+       // top
+       for (int x = e.vbox.Left(), y = e.vbox.Top(),
+                       end = std::ceil(e.vbox.Right()); x < end; ++x) {
+               const Tile &tile = TileAt(Vector<int>(x, y));
+               if (tile.IsSolid()) {
+                       response.y = y + 1 - e.vbox.Top();
                        e.vel.y = 0;
+                       break;
                }
-               if (b.Right() > size.x) {
-                       e.Move(Vector<float>(size.x - b.Right(), 0));
-                       e.vel.x = 0;
-               }
-               if (b.Bottom() > size.y) {
-                       e.Move(Vector<float>(0, size.y - b.Bottom()));
-                       e.vel.y = 0;
+       }
+
+       // bottom
+       for (int x = e.vbox.Left(), y = e.vbox.Bottom(),
+                       end = std::ceil(e.vbox.Right()); x < end; ++x) {
+               const Tile &tile = TileAt(Vector<int>(x, y));
+               if (tile.IsSolid()) {
+                       response.y = y - e.vbox.Bottom();
                        e.onGround = true;
+                       e.vel.y = 0;
+                       break;
                }
-               if (b.Left() < 0) {
-                       e.Move(Vector<float>(-b.Left(), 0));
-                       e.vel.x = 0;
-               }
-
-               const Vector<int> cBegin(b.Left(), b.Top());
-               const Vector<int> cEnd(b.Right() + 1, b.Bottom() + 1);
-
-               Vector<float> min;
-               Vector<float> max;
-
-               for (Vector<int> pos(cBegin); pos.y < cEnd.y; ++pos.y) {
-                       for (pos.x = cBegin.x; pos.x < cEnd.x; ++pos.x) {
-                               if (!TileAt(pos).IsSolid()) continue;
-                               const AABB &tBounds = TileShapeAt(pos);
-                               Collision coll;
-                               if (!e.bounds.Intersects(tBounds, coll)) {
-                                       continue;
-                               }
-                               if (coll.depth.x < min.x) min.x = coll.depth.x;
-                               if (coll.depth.x > max.x) max.x = coll.depth.x;
-                               if (coll.depth.y < min.y) min.y = coll.depth.y;
-                               if (coll.depth.y > max.y) max.y = coll.depth.y;
+       }
+       if (response.y <= 0) {
+               // bottom, second row
+               // due to the hbox's huge bottom gap
+               for (int x = e.vbox.Left(), y = e.vbox.Bottom() - 1,
+                               end = std::ceil(e.vbox.Right()); x < end; ++x) {
+                       const Tile &tile = TileAt(Vector<int>(x, y));
+                       if (tile.IsSolid()) {
+                               response.y = -1;
+                               e.onGround = true;
+                               e.vel.y = 0;
+                               break;
                        }
                }
+       }
 
-               Vector<float> resp;
-               if (min.x != 0) {
-                       if (max.x == 0) {
-                               resp.x = min.x;
-                       }
-               } else {
-                       resp.x = max.x;
-               }
-               if (min.y != 0) {
-                       if (max.y == 0) {
-                               resp.y = min.y;
-                       }
-               } else {
-                       resp.y = max.y;
-               }
-               e.Move(resp);
-               if (resp.x != 0) {
+       // left
+       for (int y = e.hbox.Top(), x = e.hbox.Left(),
+                       end = std::ceil(e.hbox.Bottom()); y < end; ++y) {
+               const Tile &tile = TileAt(Vector<int>(x, y));
+               if (tile.IsSolid()) {
+                       response.x = x + 1 - e.hbox.Left();
                        e.vel.x = 0;
+                       break;
                }
-               if (resp.y != 0) {
-                       e.vel.y = 0;
-                       if (resp.y < 0) {
-                               e.onGround = true;
-                       }
+       }
+
+       // right
+       for (int y = e.hbox.Top(), x = e.hbox.Right(),
+                       end = std::ceil(e.hbox.Bottom()); y < end; ++y) {
+               const Tile &tile = TileAt(Vector<int>(x, y));
+               if (tile.IsSolid()) {
+                       response.x = x - e.hbox.Right();
+                       e.vel.x = 0;
+                       break;
                }
        }
+
+       if (response.x > fixSpeed * dt) {
+               response.x = fixSpeed * dt;
+       } else if (response.x < -fixSpeed * dt) {
+               response.x = -fixSpeed * dt;
+       }
+       if (response.y > fixSpeed * dt) {
+               response.y = fixSpeed * dt;
+       } else if (response.y < -fixSpeed * dt) {
+               response.y = -fixSpeed * dt;
+       }
+       e.Move(response);
 }