]> git.localhorst.tv Git - orbi.git/commitdiff
hbox/vbox implementation
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 23 Apr 2014 18:37:50 +0000 (20:37 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 24 Apr 2014 08:36:47 +0000 (10:36 +0200)
src/app/Application.cpp
src/orbi.cpp
src/world/AABB.cpp
src/world/Entity.cpp
src/world/Entity.h
src/world/World.cpp
src/world/World.h

index b6a08f115cc48b66d57367297380afad1b1a43a4..94901bfd44df41c8f431931f8049132c5ea40a2a 100644 (file)
@@ -154,7 +154,7 @@ void Application::Update(int dt) {
        }
        target.Update(delta);
        focus = ctrl.Controlling()
-               ? ctrl.Controlled().bounds.Center()
+               ? ctrl.Controlled().vbox.Center()
                : target.Pos();
        cam.Update(delta);
 }
@@ -190,13 +190,28 @@ void Application::RenderWorld() {
 }
 
 void Application::RenderEntities() {
-       constexpr Color entityColor(0x00, 0xFA, 0x00);
-       canvas.SetColor(entityColor);
+       constexpr Color vboxColor(0xFA, 0x00, 0x00);
+       constexpr Color hboxColor(0x00, 0xFA, 0x00);
 
        for (const Entity &e : world.Entities()) {
-               const Vector<float> pos(e.bounds.Left(), e.bounds.Top());
-               const Vector<float> size(e.bounds.Size());
-               canvas.OutlineRect(cam.ToScreen(pos), cam.ToScale(size));
+               canvas.SetColor(vboxColor);
+               canvas.Line(
+                       cam.ToScreen(Vector<float>(e.vbox.Left(), e.vbox.Top())),
+                       cam.ToScreen(Vector<float>(e.vbox.Right(), e.vbox.Top()))
+               );
+               canvas.Line(
+                       cam.ToScreen(Vector<float>(e.vbox.Left(), e.vbox.Bottom())),
+                       cam.ToScreen(Vector<float>(e.vbox.Right(), e.vbox.Bottom()))
+               );
+               canvas.SetColor(hboxColor);
+               canvas.Line(
+                       cam.ToScreen(Vector<float>(e.hbox.Left(), e.hbox.Top())),
+                       cam.ToScreen(Vector<float>(e.hbox.Left(), e.hbox.Bottom()))
+               );
+               canvas.Line(
+                       cam.ToScreen(Vector<float>(e.hbox.Right(), e.hbox.Top())),
+                       cam.ToScreen(Vector<float>(e.hbox.Right(), e.hbox.Bottom()))
+               );
        }
 }
 
index 59c0e0c1cbdbf8ecd9254da156ce212a43d1bcb6..5775459dd5a6f5f6c9a95c578b01d46d4c80c13b 100644 (file)
@@ -53,7 +53,9 @@ int main(int argc, const char *argv[]) {
        world.SetTile(Vector<int>(3, 9), Tile(0));
 
        Entity e;
-       e.bounds = AABB(Vector<float>(5, 0), Vector<float>(1.9, 2.9));
+       e.vbox = AABB(Vector<float>(.1, 0), Vector<float>(1.8, 3));
+       e.hbox = AABB(Vector<float>(0, .1), Vector<float>(2, 1.8));
+       e.Move(Vector<float>(5, 0));
        Entity &player = world.AddEntity(e);
 
        Application app(canv, world, tiles);
index 0ed5a63934b8e1e11a9243a3e76b0a3255279253..edce97e313dfe3f832dab4204f6ca0d100dc7643 100644 (file)
@@ -1,6 +1,7 @@
 #include "AABB.h"
 
 #include "Collision.h"
+#include "../graphics/const.h"
 
 
 namespace orbi {
@@ -19,7 +20,7 @@ bool AABB::Intersects(const AABB &other, Collision &coll) const {
        if (sdiff.x < sdiff.y) {
                coll.pos.y = diff.Center().y;
                coll.norm.y = 0;
-               coll.depth.y = 0;
+               coll.depth.y = sdiff.y * sigma(Center().y - other.Center().y);
                if (Center().x < other.Center().x) {
                        coll.pos.x = Right();
                        coll.norm.x = -1;
@@ -33,6 +34,7 @@ bool AABB::Intersects(const AABB &other, Collision &coll) const {
                coll.pos.x = diff.Center().x;
                coll.norm.x = 0;
                coll.depth.x = 0;
+               coll.depth.x = sdiff.x * sigma(Center().x - other.Center().x);
                if (Center().y < other.Center().y) {
                        coll.pos.y = Bottom();
                        coll.norm.y = -1;
index 86d3a45193261926b321509202e83238861bf699..8a26d7d2bbed2a0998ce92f376aa8c2d85833a1c 100644 (file)
@@ -10,4 +10,9 @@ void Entity::Update(float dt, Vector<float> extAcc, Vector<float> tv) {
        if (vel.y > tv.y) vel.y = tv.y;
 }
 
+void Entity::Move(Vector<float> delta) {
+       vbox.Move(delta);
+       hbox.Move(delta);
+}
+
 }
index f8576c15374c33708fd010e20890197320266f43..b0dcc69b50803753842bd145715761678f110b65 100644 (file)
@@ -14,10 +14,11 @@ public:
 
 public:
        void Update(float dt, Vector<float> extAcc, Vector<float> tv);
-       void Move(Vector<float> delta) { bounds.Move(delta); }
+       void Move(Vector<float> delta);
 
 public:
-       AABB bounds;
+       AABB vbox;
+       AABB hbox;
        Vector<float> vel;
        Vector<float> acc;
 
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);
 }
 
 
index 7c982059514cfaee0924066727cde375fb89867e..038f9dcce39db83362bea625a72f13384f041ef8 100644 (file)
@@ -35,12 +35,17 @@ public:
        const std::list<Entity> &Entities() const { return entities; }
        Entity &AddEntity(const Entity &);
 
+private:
+       void BoundsCollision(Entity &, float dt);
+       void TileCollision(Entity &, float dt);
+
 private:
        Vector<int> size;
        int count;
 
        Vector<float> gravity;
        Vector<float> terminal;
+       float fixSpeed;
 
        std::vector<Tile> tiles;