]> git.localhorst.tv Git - gworm.git/blobdiff - src/world/World.cpp
some lousy world collision, friction, and drag
[gworm.git] / src / world / World.cpp
index 53115dc386360b73558a07ae5ee00bafe381c9e2..dcac95eb72708791b37b15f4a29a76035aa0e503 100644 (file)
@@ -15,12 +15,107 @@ World::World(Vector<int> size)
 
 
 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);