From: Daniel Karbach Date: Sat, 18 Jan 2014 13:11:23 +0000 (+0100) Subject: some lousy world collision, friction, and drag X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=e4732374394610bdd3deafd2138cbea267a670e0;p=gworm.git some lousy world collision, friction, and drag --- diff --git a/src/app/Application.cpp b/src/app/Application.cpp index d798b37..b7983aa 100644 --- a/src/app/Application.cpp +++ b/src/app/Application.cpp @@ -220,6 +220,7 @@ void Application::RenderUI() { canvas.Arrow(screenPos, screenPos + Vector(e.vel * 10.0f)); cout << "entity: pos " << e.pos << ", vel " << e.vel << ", acc " << e.acc << endl; + cout << " vel mag: " << Length(e.vel) << ", acc mag: " << Length(e.acc) << endl; } } diff --git a/src/graphics/Vector.h b/src/graphics/Vector.h index d35cf33..6565cc1 100644 --- a/src/graphics/Vector.h +++ b/src/graphics/Vector.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -36,6 +37,16 @@ public: y -= other.y; return *this; } + Vector &operator *=(Scalar factor) { + x *= factor; + y *= factor; + return *this; + } + Vector &operator /=(Scalar factor) { + x /= factor; + y /= factor; + return *this; + } SDL_Point ToPoint() const { SDL_Point p; @@ -142,6 +153,13 @@ constexpr bool operator !=(Vector lhs, Vector rhs) { } +template +constexpr bool IsZero(Vector v) { + return std::abs(v.x) < std::numeric_limits::epsilon() + && std::abs(v.y) < std::numeric_limits::epsilon(); +} + + template constexpr Scalar Cross2D(Vector lhs, Vector rhs) { return (lhs.x * rhs.y) - (lhs.y * rhs.x); @@ -171,6 +189,19 @@ template constexpr Vector Rotate270(Vector v) { return Vector(v.y, -v.x); } +template +inline Vector Rotate(Vector v, Float by) { + Float sine(std::sin(by)); + Float cosine(std::cos(by)); + return Vector(v.x * cosine - v.y * sine, v.x * sine + v.y * cosine); +} + +/// reflect v along normalized n +template +inline Vector Reflect(Vector v, Vector n) { + const Scalar dd = Scalar(2) * Dot(v, n); + return Vector(v.x - (dd * n.x), v.y - (dd * n.y)); +} template diff --git a/src/gworm.cpp b/src/gworm.cpp index efd5757..3f22ade 100644 --- a/src/gworm.cpp +++ b/src/gworm.cpp @@ -1,11 +1,15 @@ #include "app/Application.h" #include "app/SDL.h" +#include "graphics/const.h" #include "graphics/Canvas.h" #include "graphics/Window.h" #include "world/Entity.h" #include "world/World.h" +#include + using namespace gworm; +using namespace std; namespace { @@ -48,10 +52,19 @@ int main(int argc, const char *argv[]) { World world(Vector(500, 500)); make_planet(world, Vector(250, 250), 220); - Entity e; - e.vel = Vector(-19, 19); - e.mass = 1; - world.AddEntity(e); + Entity orb; + orb.vel = Vector(-19, 19); + orb.mass = 1; + world.AddEntity(orb); + + Entity coll; + coll.pos = Vector(250, -25); + coll.vel = Vector(-10, 0); + coll.mass = 2; + world.AddEntity(coll); + + cout << "normal at top: " << world.NormalAt(Vector(250, 30)) << endl; + cout << "normal at left: " << world.NormalAt(Vector(30, 250)) << endl; Application app(canv, world); app.Run(); diff --git a/src/world/World.cpp b/src/world/World.cpp index 53115dc..dcac95e 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -15,12 +15,107 @@ 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); +} + Entity &World::AddEntity(const Entity &e) { entities.emplace_back(e); diff --git a/src/world/World.h b/src/world/World.h index f15d43b..8a00f60 100644 --- a/src/world/World.h +++ b/src/world/World.h @@ -22,6 +22,8 @@ public: public: void Update(float dt); + bool InBounds(Vector pos) const + { return pos.x > 0 && pos.y > 0 && pos.x < size.x && pos.y < size.y; } int Index(Vector pos) const { return pos.x * size.y + pos.y; } float MassAt(Vector pos) const { return masses[Index(pos)]; } @@ -33,6 +35,9 @@ public: Entity &AddEntity(const Entity &); Vector ForceAt(Vector, float m) const; + bool WorldCollision(const Entity &, Vector &) const; + Vector NormalAt(Vector) const; + bool IsSurface(Vector) const; private: Vector size;