Commit a357ce2f authored by Leon's avatar Leon

Restructure and simplify engine

parent 652a2f71
......@@ -8,20 +8,20 @@ using namespace std;
namespace duodim
{
class World
class Scene
{
public:
static World& getInstance();
static Scene& getInstance();
static float gravityConst;
World();
World(World const&) = delete;
Scene();
Scene(Scene const&) = delete;
optional<Body> getBody(unsigned int id);
bool addBody(Body body);
bool removeBody(Body body);
void update(float deltaTime);
void operator =(World const&) = delete;
void operator =(Scene const&) = delete;
private:
static optional<World> instance;
static optional<Scene> instance;
vector<unsigned int> bodyKeys;
unordered_map<unsigned int, Body> bodies;
......
#ifndef INCLUDE_COLLISIONS_H
#define INCLUDE_COLLISIONS_H
#include "ACircle.hpp"
#include "Body.hpp"
#include "Vector2D.hpp"
namespace duodim
{
class Collisions
{
public:
static bool checkCirclesColliding(ACircle a, ACircle b);
static void resolveCollision();
};
}
#endif
\ No newline at end of file
......@@ -6,10 +6,7 @@
using namespace std;
namespace duodim
{
struct CollisionPair {
Body* a;
Body* b;
}
struct CollisionPair { Body* a; Body* b; };
class BroadPhase
{
......
#ifndef INCLUDE_CONTACT_H
#define INCLUDE_CONTACT_H
#ifndef INCLUDE_COLLISION_H
#define INCLUDE_COLLISION_H
#include "Body.hpp"
#include "Vector2D.hpp"
namespace duodim
{
/**
* Describes a physical contact between two Bodies in 2D space.
*/
class Contact
class Collision
{
public:
Contact(Vector2D<float> position, Vector2D<float> normal, float penetration);
Collision(Vector2D<float> position, Vector2D<float> normal, float penetration);
/**
* Get the 2D space position of the contact.
*/
......@@ -26,7 +27,16 @@ namespace duodim
*
*/
float getPenetration();
void solve();
void init();
void applyImpulse();
void positionalCorrection();
void infiniteMassCorrection();
private:
Body* a;
Body* b;
Vector2D<float> position;
Vector2D<float> normal;
Vector2D<float> tangent;
......
#ifndef INCLUDE_CONSTRAINT_SOLVER_MAP_H
#define INCLUDE_CONSTRAINT_SOLVER_MAP_H
#include <unordered_map>
#include <vector>
#include "Body.hpp"
#include "ContactConstraint.hpp"
#include "World.hpp"
namespace duodim
{
class ConstraintSolverMap
{
public:
ConstraintSolverMap(World instance);
void initializeVelocity();
void warmStartVelocity();
void solveVelocity();
void solvePosition();
private:
World instance;
unordered_map<BodyPair, vector<ContactConstraint>> _map;
};
}
#endif
\ No newline at end of file
......@@ -2,7 +2,7 @@
#define INCLUDE_CONTACT_CONSTRAINT_H
#include <vector>
#include "Body.hpp"
#include "Contact.hpp"
#include "Collision.hpp"
using namespace std;
namespace duodim
{
......@@ -21,7 +21,7 @@ namespace duodim
* @param newContacts given vector of Contacts
* @return a vector of ContactConstraints
*/
static vector<ContactConstraint> withContacts(vector<Contact> newContacts);
static vector<ContactConstraint> withContacts(vector<Collision> newContacts);
/**
* For a given vector or existing ContactConstraint and a vector of Contacts, generate a vector of new ContactConstraints
* and try to apply existing ContactConstraint values before returning them.
......@@ -29,16 +29,16 @@ namespace duodim
* @param newContacts given vector of Contacts
* @return a vector of ContactConstraints
*/
static vector<ContactConstraint> withPersistentContacts(vector<ContactConstraint> oldConstraints, vector<Contact> newContacts);
static vector<ContactConstraint> withPersistentContacts(vector<ContactConstraint> oldConstraints, vector<Collision> newContacts);
/**
* ContactConstraint constructor.
* @param contact the associated Contact.
* @param contact the associated Collision.
*/
ContactConstraint(Contact contact);
ContactConstraint(Collision contact);
/**
* Return this constraint's contact.
*/
Contact getContact();
Collision getContact();
/**
* Perform initial velocity calculations for two given bodies.
* @param a first Body
......@@ -55,7 +55,7 @@ namespace duodim
void solveVelocity(Body a, Body b);
void solvePosition(Body a, Body b);
private:
Contact contact;
Collision contact;
float normalImpulse = 0.f;
float tangentImpulse = 0.f;
float normalMass = 0.f;
......
#ifndef INCLUDE_NARROW_PHASE_H
#define INCLUDE_NARROW_PHASE_H
#include "Body.hpp"
#include "Collision.hpp"
#include "Shape.hpp"
namespace duodim
{
typedef void (*CollisionCallback)(Collision* c, Body* a, Body* b);
extern CollisionCallback Dispatch[ShapeType::ECOUNT][ShapeType::ECOUNT];
class NarrowPhase
{
public:
static void twoCircles(Collision* c, Body* a, Body* b);
static void circlePolygon(Collision* c, Body* a, Body* b);
static void polygonCircle(Collision* c, Body* a, Body* b);
static void twoPolygons(Collision* c, Body* a, Body* b);
};
}
#endif
\ No newline at end of file
#ifndef INCLUDE_BOUNDS_TREE_H
#define INCLUDE_BOUNDS_TREE_H
#include <unordered_map>
#include "AxisAlignedBoundingBox.hpp"
#include "Body.hpp"
namespace duodim
{
class Node
{
public:
Node();
Node(Body body, AxisAlignedBoundingBox bounds);
Body getData();
AxisAlignedBoundingBox getBounds();
unsigned int getParentId();
unsigned int getLeftChildId();
unsigned int getRightChildId();
unsigned int getHeight();
bool isLeaf();
void setBounds(AxisAlignedBoundingBox b);
void setHeight(unsigned int h);
private:
Body body;
AxisAlignedBoundingBox bounds;
unsigned int parent = UINT_MAX;
unsigned int left = UINT_MAX;
unsigned int right = UINT_MAX;
unsigned int height = 0u;
};
class BoundsTree
{
public:
BoundsTree();
Node getRoot();
Node getNode(unsigned int id);
void updateBranchNode(unsigned int id);
void rotate(unsigned int id, unsigned int childId);
void balanceSubtree(unsigned int id);
void updateAncestors(unsigned int id);
void insertLeaf();
private:
unordered_map<unsigned int, Node> nodes;
unsigned int rootId = UINT_MAX;
};
}
#endif
\ No newline at end of file
......@@ -30,6 +30,7 @@ namespace duodim
Material getMaterial();
Shape* getShape();
AxisAlignedBoundingBox getBounds();
Transform getTransform();
Vector2D<float> getVelocity();
......@@ -42,13 +43,14 @@ namespace duodim
unsigned int getId();
bool isStatic();
bool operator ==(Body o);
void addForce(Vector2D<float> f);
void addForce(Vector2D<float> f, Vector2D<float> pos);
void addImpulse(Vector2D<float> i, Vector2D<float> pos);
void addTorque(float t);
void setPosition(Vector2D<float> p);
void setShape(Shape s);
void setShape(Shape* s);
void setDensity(const float d);
void setId(const unsigned int i);
void update();
......
......@@ -5,9 +5,9 @@ namespace duodim
class Material
{
public:
static Material wood() = Material(0.f, .2f, .3f);
static Material bouncyBall() = Material(0.f, .8f, .3f);
static Material superBall() = Material(0.f, .95f, .3f);
static Material wood();
static Material bouncyBall();
static Material superBall();
Material();
Material(float friction, float restitution, float density);
float getFriction();
......
......@@ -13,6 +13,7 @@ namespace duodim
AxisAlignedBoundingBox getBounds(const Vector2D<float> position);
MassAndInertia getMassAndInertia(const float density);
ShapeType getType();
float getRadius();
void setRadius(float r);
protected:
......
......@@ -19,6 +19,7 @@ namespace duodim
AxisAlignedBoundingBox getBounds(const optional<Transform> transformOpt);
MassAndInertia getMassAndInertia(const float density);
ShapeType getType();
list<Vector2D<float>> getVertices();
list<Vector2D<float>> getNormals();
......
#ifndef INCLUDE_RECTANGLE_HPP
#define INCLUDE_RECTANGLE_HPP
#include <optional>
#include "AxisAlignedBoundingBox.hpp"
#include "Shape.hpp"
#include "Transform.hpp"
namespace duodim
{
class Rectangle : public Shape
{
public:
Rectangle();
Rectangle(float height, float width);
Rectangle(float dim);
~Rectangle();
AxisAlignedBoundingBox getBounds(const optional<Transform> transformOpt);
MassAndInertia getMassAndInertia(const float density);
float getHeight();
float getWidth();
float getMass();
float getInertia();
bool isQuadratic();
void setHeight(float h);
void setWidth(float w);
protected:
void updateName();
private:
float height;
float width;
};
}
#endif
\ No newline at end of file
......@@ -12,11 +12,13 @@ namespace duodim
float inertia;
};
enum ShapeType { CIRCLE, CONVEXPOLYGON, ECOUNT };
class Shape
{
public:
virtual AxisAlignedBoundingBox getBounds(optional<Transform> transformOpt);
virtual MassAndInertia getMassAndInertia(const float density);
virtual ShapeType getType();
string getName();
void setName(string n);
......
#include <optional>
#include "Engine.hpp"
#include "World.hpp"
#include "Scene.hpp"
using namespace duodim;
using namespace std;
......@@ -14,7 +14,7 @@ Engine::Engine() {}
int Engine::run()
{
running = true;
World& world = World::getInstance();
Scene& world = Scene::getInstance();
float frameStart = 0.f; // GetCurrentTime();
while (running)
......
#include <optional>
#include <unordered_map>
#include "World.hpp"
#include "Scene.hpp"
#include "Body.hpp"
using namespace duodim;
using namespace std;
World& World::getInstance()
Scene& Scene::getInstance()
{
static World instance;
static Scene instance;
return instance;
}
World::World() : bodies({}) {}
Scene::Scene() : bodies({}) {}
optional<Body> World::getBody(unsigned int id)
optional<Body> Scene::getBody(unsigned int id)
{
return bodies.find(id) == bodies.end() ? nullopt : optional<Body>{bodies[id]};
}
float World::gravityConst = -9.81f;
float Scene::gravityConst = -9.81f;
bool World::addBody(Body body)
bool Scene::addBody(Body body)
{
unsigned int startId = body.getId();
for (unsigned int i = 0; i < bodyKeys.size(); i++)
......@@ -41,14 +41,14 @@ bool World::addBody(Body body)
return true;
}
bool World::removeBody(Body body)
bool Scene::removeBody(Body body)
{
bodies.erase(body.getId());
updateKeys();
return true;
}
void World::update(float deltaTime)
void Scene::update(float deltaTime)
{
for(auto b : bodies)
{
......@@ -56,7 +56,7 @@ void World::update(float deltaTime)
}
}
void World::updateKeys()
void Scene::updateKeys()
{
bodyKeys.clear();
for (auto kv : bodies)
......
#include <math.h>
#include "ACircle.hpp"
#include "Collisions.hpp"
#include "Vector2D.hpp"
using namespace duodim;
bool Collisions::checkCirclesColliding(ACircle a, ACircle b)
{
return pow((a.getRadius() + b.getRadius()), 2) < (pow((a.getPosition().getX() - b.getPosition().getX()), 2) + pow((a.getPosition().getY() - b.getPosition().getY()), 2));
}
\ No newline at end of file
......@@ -13,19 +13,19 @@ BroadPhase& BroadPhase::getInstance()
BroadPhase::BroadPhase() {}
void BroadPhase::generatePairs(vector<Body*> bodies)
void BroadPhase::generatePairs(vector<Body> bodies)
{
pairs.clear();
AxisAlignedBoundingBox a_aabb;
AxisAlignedBoundingBox b_aabb;
for (auto i = bodies.begin(); i != bodies.end(); i = bodies.next())
for (auto i = 0; i < bodies.size(); i++)
{
for (auto j = bodies.begin(); j != bodies.end(); j = bodies.next())
for (auto j = 0; j != bodies.size(); j++)
{
Body* a = &i->getData();
Body* b = &j->getData();
Body a = bodies[i];
Body b = bodies[j];
if (a == b)
{
......@@ -33,9 +33,9 @@ void BroadPhase::generatePairs(vector<Body*> bodies)
}
a.update();
b.update();
if (a.getShape().getBounds().intersects(b.getShape().getBounds()))
if (a.getBounds().intersects(b.getBounds()))
{
pairs.push_back({&a, &b});
}
}
}
......
#include "Contact.hpp"
#include "Collision.hpp"
#include "Vector2D.hpp"
using namespace duodim;
Contact::Contact(Vector2D<float> position, Vector2D<float> normal, float penetration) : position(position), normal(normal), penetration(penetration)
Collision::Collision(Vector2D<float> position, Vector2D<float> normal, float penetration) : position(position), normal(normal), penetration(penetration)
{
tangent = normal.crossMult(1.f);
}
Vector2D<float> Contact::getPosition()
Vector2D<float> Collision::getPosition()
{
return position;
}
Vector2D<float> Contact::getNormal()
Vector2D<float> Collision::getNormal()
{
return normal;
}
Vector2D<float> Contact::getTangent()
Vector2D<float> Collision::getTangent()
{
return tangent;
}
float Contact::getPenetration()
float Collision::getPenetration()
{
return penetration;
}
\ No newline at end of file
#include <unordered_map>
#include "Body.hpp"
#include "ConstraintSolverMap.hpp"
#include "ContactConstraint.hpp"
using namespace duodim;
ConstraintSolverMap::ConstraintSolverMap(World instance) : instance(instance), _map({}) {}
void ConstraintSolverMap::initializeVelocity()
{
for (auto kv : _map)
{
auto a = instance.getBody(kv.first.aId);
auto b = instance.getBody(kv.first.bId);
if (a.has_value() && b.has_value())
{
for (auto cc : kv.second)
{
cc.initializeVelocity(a.value(), b.value());
}
}
}
}
void ConstraintSolverMap::warmStartVelocity()
{
for (auto kv : _map)
{
auto a = instance.getBody(kv.first.aId);
auto b = instance.getBody(kv.first.bId);
if (a.has_value() && b.has_value())
{
for (auto cc : kv.second)
{
cc.warmStartVelocity(a.value(), b.value());
}
}
}
}
void ConstraintSolverMap::solveVelocity()
{
for (auto kv : _map)
{
auto a = instance.getBody(kv.first.aId);
auto b = instance.getBody(kv.first.bId);
if (a.has_value() && b.has_value())
{
for (auto cc : kv.second)
{
cc.solveVelocity(a.value(), b.value());
}
}
}
}
void ConstraintSolverMap::solvePosition()
{
for (auto kv : _map)
{
auto a = instance.getBody(kv.first.aId);
auto b = instance.getBody(kv.first.bId);
if (a.has_value() && b.has_value())
{
for (auto cc : kv.second)
{
cc.solvePosition(a.value(), b.value());
}
}
}
}
\ No newline at end of file
......@@ -8,7 +8,7 @@
using namespace duodim;
using namespace std;
vector<ContactConstraint> ContactConstraint::withContacts(vector<Contact> newContacts)
vector<ContactConstraint> ContactConstraint::withContacts(vector<Collision> newContacts)
{
vector<ContactConstraint> retVal;
for (auto c: newContacts)
......@@ -18,7 +18,7 @@ vector<ContactConstraint> ContactConstraint::withContacts(vector<Contact> newCon
return retVal;
}
vector<ContactConstraint> ContactConstraint::withPersistentContacts(vector<ContactConstraint> oldConstraints, vector<Contact> newContacts)
vector<ContactConstraint> ContactConstraint::withPersistentContacts(vector<ContactConstraint> oldConstraints, vector<Collision> newContacts)
{
vector<ContactConstraint> newConstraints = withContacts(newContacts);
const float PERSISTENT_DISTANCE = 0.01f;
......@@ -37,7 +37,7 @@ vector<ContactConstraint> ContactConstraint::withPersistentContacts(vector<Conta
return newConstraints;
}
ContactConstraint::ContactConstraint(Contact contact) : contact(contact) {}
ContactConstraint::ContactConstraint(Collision contact) : contact(contact) {}
void ContactConstraint::initializeVelocity(Body a, Body b)
{
......
#include "NarrowPhase.hpp"
#include "Circle.hpp"
#include "ConvexPolygon.hpp"
#include "Rectangle.hpp"
#include "Shape.hpp"
using namespace duodim;
CollisionCallback Dispatch[ShapeType::ECOUNT][ShapeType::ECOUNT] =
{
{
NarrowPhase::twoCircles, NarrowPhase::circlePolygon
},
{
NarrowPhase::polygonCircle, NarrowPhase::twoPolygons
}
};
void NarrowPhase::twoCircles(Collision* c, Body* a, Body* b)
{
Circle* ca = reinterpret_cast<Circle*>(a->getShape());
Circle* cb = reinterpret_cast<Circle*>(b->getShape());
Vector2D<float> normal = a->getTransform().getPosition() - b->getTransform().getPosition();
float sqDist = normal.squaredMagnitude();
float rSum = ca->getRadius() + cb->getRadius();
if (sqDist >= pow(rSum, 2))
{
c->
}
}
\ No newline at end of file
#include "AxisAlignedBoundingBox.hpp"
#include "Body.hpp"
#include "BoundsTree.hpp"
using namespace duodim;
Node::Node() : body(Body()), bounds(AxisAlignedBoundingBox()) {}
Node::Node(Body body, AxisAlignedBoundingBox bounds) : body(body), bounds(bounds) {}
AxisAlignedBoundingBox Node::getBounds() { return bounds; }
Body Node::getData() { return body; }
unsigned int Node::getHeight() { return height; }
unsigned int Node::getParentId() { return parent; }
unsigned int Node::getLeftChildId() { return left; }
unsigned int Node::getRightChildId() { return right; }
bool Node::isLeaf() { return left == UINT_MAX; }
void Node::setBounds(AxisAlignedBoundingBox b) { bounds = b; }
void Node::setHeight(unsigned int h) { height = h; }
\ No newline at end of file
......@@ -10,7 +10,7 @@
using namespace duodim;
Body::Body()
: transform(Transform()), material(Material