#include "World.h"
#include "Collision.h"
+#include "Entity.h"
#include "../graphics/const.h"
+#include <algorithm>
+#include <cmath>
+
+using namespace std;
+
namespace orbi {
, count(size.x * size.y)
, gravity(0, 5)
, terminal(50, 50)
+, fixSpeed(5)
, tiles(count) {
}
void World::Update(float dt) {
- for (Entity &e : entities) {
- e.Update(dt, gravity, terminal);
- e.onGround = false;
+ for (Entity *e : entities) {
+ if (e->onGround) {
+ e->Update(dt, Vector<float>(), terminal);
+ e->onGround = false;
+ } else {
+ e->Update(dt, gravity, terminal);
+ }
- const AABB &b = e.bounds;
+ BoundsCollision(*e, dt);
+ TileCollision(*e, dt);
- // world bounds collision
- if (b.Top() < 0) {
- e.Move(Vector<float>(0, -b.Top()));
+ }
+}
+
+void World::BoundsCollision(Entity &e, float dt) {
+ if (e.vbox.Top() < 0) {
+ e.Move(Vector<float>(0, -e.vbox.Top()));
+ if (e.vel.y < 0) {
e.vel.y = 0;
}
- 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()));
+ }
+ if (e.vbox.Bottom() > size.y) {
+ e.Move(Vector<float>(0, size.y - e.vbox.Bottom()));
+ if (e.vel.y > 0) {
e.vel.y = 0;
- e.onGround = true;
}
- if (b.Left() < 0) {
- e.Move(Vector<float>(-b.Left(), 0));
+ e.onGround = true;
+ }
+ if (e.hbox.Right() > size.x) {
+ e.Move(Vector<float>(size.x - e.hbox.Right(), 0));
+ if (e.vel.x > 0) {
e.vel.x = 0;
}
+ }
+ if (e.hbox.Left() < 0) {
+ e.Move(Vector<float>(-e.hbox.Left(), 0));
+ if (e.vel.x < 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;
+void World::TileCollision(Entity &e, float dt) {
+ Vector<float> response;
+
+ // 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();
+ if (e.vel.y < 0) {
+ e.vel.y = 0;
}
+ break;
}
+ }
- Vector<float> resp;
- if (min.x != 0) {
- if (max.x == 0) {
- resp.x = min.x;
+ // 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;
+ if (e.vel.y > 0) {
+ e.vel.y = 0;
}
- } else {
- resp.x = max.x;
+ break;
}
- if (min.y != 0) {
- if (max.y == 0) {
- resp.y = min.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;
+ if (e.vel.y > 0) {
+ e.vel.y = 0;
+ }
+ break;
}
- } else {
- resp.y = max.y;
}
- e.Move(resp);
- if (resp.x != 0) {
- e.vel.x = 0;
- }
- if (resp.y != 0) {
- e.vel.y = 0;
- if (resp.y < 0) {
- e.onGround = true;
+ }
+
+ // 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();
+ if (e.vel.x < 0) {
+ e.vel.x = 0;
}
+ break;
}
}
-}
+ // 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();
+ if (e.vel.x > 0) {
+ e.vel.x = 0;
+ }
+ break;
+ }
+ }
-const AABB &World::TileShapeAt(Vector<int> pos) const {
- tileShape = AABB(pos, Vector<float>(1, 1));
- return tileShape;
+ 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);
}
-
-Entity &World::AddEntity(const Entity &e) {
- entities.emplace_back(e);
- return entities.back();
+void World::EntityCollision() {
+ if (entities.size() <= 1) return;
+
+ auto firstEnd(entities.end());
+ --firstEnd;
+ for (auto first(entities.begin()); first != firstEnd; ++first) {
+ auto second(first);
+ ++second;
+ for (auto secondEnd(entities.end()); second != secondEnd; ++second) {
+ if ((*first)->bounds.Intersects((*second)->bounds)) {
+ // damage + knockback
+ }
+ }
+ }
}
+
}