}
target.Update(delta);
focus = ctrl.Controlling()
- ? ctrl.Controlled().bounds.Center()
+ ? ctrl.Controlled().vbox.Center()
: target.Pos();
cam.Update(delta);
}
}
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()))
+ );
}
}
#include "Collision.h"
#include "../graphics/const.h"
+#include <algorithm>
+#include <cmath>
+
namespace orbi {
, count(size.x * size.y)
, gravity(0, 5)
, terminal(50, 50)
+, fixSpeed(5)
, tiles(count) {
}
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);
}