From: Daniel Karbach Date: Wed, 23 Apr 2014 18:37:50 +0000 (+0200) Subject: hbox/vbox implementation X-Git-Url: http://git.localhorst.tv/?p=orbi.git;a=commitdiff_plain;h=a8523bee4fc349a800f5f6d67b470c3a801beaa9 hbox/vbox implementation --- diff --git a/src/app/Application.cpp b/src/app/Application.cpp index b6a08f1..94901bf 100644 --- a/src/app/Application.cpp +++ b/src/app/Application.cpp @@ -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 pos(e.bounds.Left(), e.bounds.Top()); - const Vector size(e.bounds.Size()); - canvas.OutlineRect(cam.ToScreen(pos), cam.ToScale(size)); + canvas.SetColor(vboxColor); + canvas.Line( + cam.ToScreen(Vector(e.vbox.Left(), e.vbox.Top())), + cam.ToScreen(Vector(e.vbox.Right(), e.vbox.Top())) + ); + canvas.Line( + cam.ToScreen(Vector(e.vbox.Left(), e.vbox.Bottom())), + cam.ToScreen(Vector(e.vbox.Right(), e.vbox.Bottom())) + ); + canvas.SetColor(hboxColor); + canvas.Line( + cam.ToScreen(Vector(e.hbox.Left(), e.hbox.Top())), + cam.ToScreen(Vector(e.hbox.Left(), e.hbox.Bottom())) + ); + canvas.Line( + cam.ToScreen(Vector(e.hbox.Right(), e.hbox.Top())), + cam.ToScreen(Vector(e.hbox.Right(), e.hbox.Bottom())) + ); } } diff --git a/src/orbi.cpp b/src/orbi.cpp index 59c0e0c..5775459 100644 --- a/src/orbi.cpp +++ b/src/orbi.cpp @@ -53,7 +53,9 @@ int main(int argc, const char *argv[]) { world.SetTile(Vector(3, 9), Tile(0)); Entity e; - e.bounds = AABB(Vector(5, 0), Vector(1.9, 2.9)); + e.vbox = AABB(Vector(.1, 0), Vector(1.8, 3)); + e.hbox = AABB(Vector(0, .1), Vector(2, 1.8)); + e.Move(Vector(5, 0)); Entity &player = world.AddEntity(e); Application app(canv, world, tiles); diff --git a/src/world/AABB.cpp b/src/world/AABB.cpp index 0ed5a63..edce97e 100644 --- a/src/world/AABB.cpp +++ b/src/world/AABB.cpp @@ -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; diff --git a/src/world/Entity.cpp b/src/world/Entity.cpp index 86d3a45..8a26d7d 100644 --- a/src/world/Entity.cpp +++ b/src/world/Entity.cpp @@ -10,4 +10,9 @@ void Entity::Update(float dt, Vector extAcc, Vector tv) { if (vel.y > tv.y) vel.y = tv.y; } +void Entity::Move(Vector delta) { + vbox.Move(delta); + hbox.Move(delta); +} + } diff --git a/src/world/Entity.h b/src/world/Entity.h index f8576c1..b0dcc69 100644 --- a/src/world/Entity.h +++ b/src/world/Entity.h @@ -14,10 +14,11 @@ public: public: void Update(float dt, Vector extAcc, Vector tv); - void Move(Vector delta) { bounds.Move(delta); } + void Move(Vector delta); public: - AABB bounds; + AABB vbox; + AABB hbox; Vector vel; Vector acc; diff --git a/src/world/World.cpp b/src/world/World.cpp index 7276ece..c76f860 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -3,6 +3,9 @@ #include "Collision.h" #include "../graphics/const.h" +#include +#include + namespace orbi { @@ -11,6 +14,7 @@ World::World(Vector 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(0, -e.vbox.Top())); + e.vel.y = 0; + } + if (e.vbox.Bottom() > size.y) { + e.Move(Vector(0, size.y - e.vbox.Bottom())); + e.vel.y = 0; + e.onGround = true; + } + if (e.hbox.Right() > size.x) { + e.Move(Vector(size.x - e.hbox.Right(), 0)); + e.vel.x = 0; + } + if (e.hbox.Left() < 0) { + e.Move(Vector(-e.hbox.Left(), 0)); + e.vel.x = 0; + } +} + +void World::TileCollision(Entity &e, float dt) { + Vector response; - // world bounds collision - if (b.Top() < 0) { - e.Move(Vector(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(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(size.x - b.Right(), 0)); - e.vel.x = 0; - } - if (b.Bottom() > size.y) { - e.Move(Vector(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(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(-b.Left(), 0)); - e.vel.x = 0; - } - - const Vector cBegin(b.Left(), b.Top()); - const Vector cEnd(b.Right() + 1, b.Bottom() + 1); - - Vector min; - Vector max; - - for (Vector 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(x, y)); + if (tile.IsSolid()) { + response.y = -1; + e.onGround = true; + e.vel.y = 0; + break; } } + } - Vector 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(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(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); } diff --git a/src/world/World.h b/src/world/World.h index 7c98205..038f9dc 100644 --- a/src/world/World.h +++ b/src/world/World.h @@ -35,12 +35,17 @@ public: const std::list &Entities() const { return entities; } Entity &AddEntity(const Entity &); +private: + void BoundsCollision(Entity &, float dt); + void TileCollision(Entity &, float dt); + private: Vector size; int count; Vector gravity; Vector terminal; + float fixSpeed; std::vector tiles;