: size(size)
, count(size.x * size.y)
, masses(count, 1000000000.0f)
-, colors(count, Color(0x7F, 0x7F, 0x7F)) {
+, colors(count, Color(0x7F, 0x7F, 0x7F))
+, colorDirty(true) {
}
void World::Update(float dt) {
+ constexpr float fricDyn = 0.75f;
+ constexpr float fricStat = 2.5f;
+ constexpr float dragFact = 0.05f;
+
for (Entity &e : entities) {
- e.acc = ForceAt(e.pos, e.mass) / e.mass;
+ const Vector<float> gravity = ForceAt(e.pos, e.mass);
+ const Vector<float> drag = Rotate180(e.vel) * dragFact;
+ // TODO: drag should be inverse square. and not onmipresent
+
+ e.acc = (gravity + drag) / e.mass;
e.Update(dt);
+
+ Vector<float> at;
+ if (WorldCollision(e, at)) {
+ float speed = Length(e.vel);
+ Vector<float> normVel = e.vel / speed;
+ float steps = 0;
+ while (MassAt(e.pos) > 0) {
+ e.pos -= normVel;
+ steps += 1.0f;
+ }
+ const Vector<float> normal = NormalAt(e.pos + normVel);
+ e.vel = Reflect(e.vel, normal);
+ speed = Length(e.vel);
+ normVel = e.vel / speed;
+ // some kind of friction, depends on angle to normal
+ speed *= (fricDyn * (std::abs(Dot(normVel, normal))));
+ if (speed > fricStat) {
+ speed -= fricStat;
+ e.vel = normVel * speed;
+ e.pos += normVel * steps;
+ } else {
+ e.vel = Vector<float>(0, 0);
+ }
+ }
+ }
+}
+
+
+bool World::WorldCollision(const Entity &e, Vector<float> &at) const {
+ if (InBounds(e.pos) && MassAt(e.pos) > 0) {
+ at = e.pos;
+ return true;
+ } else {
+ return false;
}
}
+Vector<float> World::NormalAt(Vector<float> pos) const {
+ constexpr Vector<float> check[] = {
+ { 0, -2 },
+ { 0.765367, -1.84776 },
+ { 1.41421, -1.41421 },
+ { 1.84776, -0.765367 },
+ { 2, 0 },
+ { 1.84776, 0.765367 },
+ { 1.41421, 1.41421 },
+ { 0.765367, 1.84776 },
+ { 0, 2 },
+ { -0.765367, 1.84776 },
+ { -1.41421, 1.41421 },
+ { -1.84776, 0.765367 },
+ { -2, 0 },
+ { -1.84776, -0.765367 },
+ { -1.41421, -1.41421 },
+ { -0.765367, -1.84776 },
+ };
+ Vector<float> normal;
+ for (auto v : check) {
+ if (MassAt(pos + v) == 0) {
+ normal += v;
+ }
+ }
+ return Norm(normal);
+}
+
+//Vector<float> World::NormalAt(Vector<float> pos) const {
+// Vector<int> begin(pos - Vector<float>(3, 3));
+// Vector<int> end(pos + Vector<float>(3, 3));
+//
+// Vector<float> normal;
+// for (Vector<int> cur(begin); cur.y < end.y; ++cur.y) {
+// for (cur.x = begin.x; cur.x < end.x; ++cur.x) {
+// if (IsSurface(cur) > 0) {
+// const Vector<float> dir = pos - Vector<float>(cur);
+// normal += Rotate90(dir);
+// }
+// }
+// }
+//
+// return Norm(normal);
+//}
+
+bool World::IsSurface(Vector<int> pos) const {
+ return MassAt(pos) > 0 && (
+ MassAt(pos - Vector<int>(1, 0)) == 0 ||
+ MassAt(pos + Vector<int>(1, 0)) == 0 ||
+ MassAt(pos - Vector<int>(0, 1)) == 0 ||
+ MassAt(pos + Vector<int>(0, 1)) == 0);
+}
+
Entity &World::AddEntity(const Entity &e) {
entities.emplace_back(e);