X-Git-Url: https://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fworld%2FWorld.cpp;h=dcac95eb72708791b37b15f4a29a76035aa0e503;hb=ba1cd7abc93eaacc3c25c0ad1b923b2ce7b280e2;hp=206105ba3d9c3cdf1ffdc5bd943fb3058e9cee99;hpb=3694504331ca888f2cacbcb841a83c402d26934a;p=gworm.git diff --git a/src/world/World.cpp b/src/world/World.cpp index 206105b..dcac95e 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -15,10 +15,105 @@ World::World(Vector 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 gravity = ForceAt(e.pos, e.mass); + const Vector drag = Rotate180(e.vel) * dragFact; + // TODO: drag should be inverse square. and not onmipresent + + e.acc = (gravity + drag) / e.mass; e.Update(dt); + + Vector at; + if (WorldCollision(e, at)) { + float speed = Length(e.vel); + Vector normVel = e.vel / speed; + float steps = 0; + while (MassAt(e.pos) > 0) { + e.pos -= normVel; + steps += 1.0f; + } + const Vector 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(0, 0); + } + } + } +} + + +bool World::WorldCollision(const Entity &e, Vector &at) const { + if (InBounds(e.pos) && MassAt(e.pos) > 0) { + at = e.pos; + return true; + } else { + return false; + } +} + +Vector World::NormalAt(Vector pos) const { + constexpr Vector 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 normal; + for (auto v : check) { + if (MassAt(pos + v) == 0) { + normal += v; + } } + return Norm(normal); +} + +//Vector World::NormalAt(Vector pos) const { +// Vector begin(pos - Vector(3, 3)); +// Vector end(pos + Vector(3, 3)); +// +// Vector normal; +// for (Vector 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 dir = pos - Vector(cur); +// normal += Rotate90(dir); +// } +// } +// } +// +// return Norm(normal); +//} + +bool World::IsSurface(Vector pos) const { + return MassAt(pos) > 0 && ( + MassAt(pos - Vector(1, 0)) == 0 || + MassAt(pos + Vector(1, 0)) == 0 || + MassAt(pos - Vector(0, 1)) == 0 || + MassAt(pos + Vector(0, 1)) == 0); } @@ -28,6 +123,8 @@ Entity &World::AddEntity(const Entity &e) { } +// returns <1.37136364,1.37136734> for 1 mass at <0,0> +/* Vector World::ForceAt(Vector p1, float m1) const { Vector force(0, 0); @@ -48,5 +145,33 @@ Vector World::ForceAt(Vector p1, float m1) const { return force; } +*/ + +// returns <1.37136674,1.37136662> for 1 mass at <0,0> +// (should be less prone to rounding loss, i.e. more accurate) +Vector World::ForceAt(Vector p1, float m1) const { + Vector force(0, 0); + + for (Vector p2(0, 0); p2.y < size.y; ++p2.y) { + Vector rowForce(0, 0); + for (p2.x = 0; p2.x < size.x; ++p2.x) { + const int i = Index(p2); + if (p1 == Vector(p2)) continue; + + const Vector diff(Vector(p2) - p1); + const Vector dir(Norm(diff)); + + const float m2 = masses[i]; + const float r2 = Dot(diff, diff); + + const float mag = G * ((m1 * m2) / r2) * 2; // double because m2 is our reference frame + + rowForce += dir * mag; + } + force += rowForce; + } + + return force; +} }