Commit 652a2f71 authored by Leon's avatar Leon

WIP engine

parent 13afaf79
#ifndef INCLUDE_ENGINE_H
#define INCLUDE_ENGINE_H
#include <optional>
using namespace std;
namespace duodim
{
class Engine
{
const float fps = 75.f;
const float dt = 1 / fps;
public:
static Engine& getInstance();
Engine();
Engine(Engine const&) = delete;
int run();
void stop();
void operator =(Engine const&) = delete;
private:
float accumulator = 0;
bool running = false;
};
}
#endif
\ No newline at end of file
#ifndef INCLUDE_WORLD_HPP
#define INCLUDE_WORLD_HPP
#include <list>
#ifndef INCLUDE_WORLD_H
#define INCLUDE_WORLD_H
#include <optional>
#include <unordered_map>
#include "Body.hpp"
using namespace std;
......@@ -10,14 +11,21 @@ namespace duodim
class World
{
public:
static World& getInstance();
static float gravityConst;
World();
~World();
World(World 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;
private:
list<Body> bodies;
static optional<World> instance;
vector<unsigned int> bodyKeys;
unordered_map<unsigned int, Body> bodies;
void updateKeys();
};
}
#endif
\ No newline at end of file
#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
#ifndef INCLUDE_BROAD_PHASE_H
#define INCLUDE_BROAD_PHASE_H
#include <vector>
#include "AxisAlignedBoundingBox.hpp"
#include "Body.hpp"
using namespace std;
namespace duodim
{
struct CollisionPair {
Body* a;
Body* b;
}
class BroadPhase
{
public:
static BroadPhase& getInstance();
BroadPhase();
BroadPhase(BroadPhase const&) = delete;
void operator =(BroadPhase const&) = delete;
void generatePairs(vector<Body> bodies);
private:
vector<CollisionPair> pairs = {};
bool isBoxesCollide(AxisAlignedBoundingBox a, AxisAlignedBoundingBox b);
};
}
#endif
\ No newline at end of file
#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
#ifndef INCLUDE_CONTACT_H
#define INCLUDE_CONTACT_H
#include "Vector2D.hpp"
namespace duodim
{
/**
* Describes a physical contact between two Bodies in 2D space.
*/
class Contact
{
public:
Contact(Vector2D<float> position, Vector2D<float> normal, float penetration);
/**
* Get the 2D space position of the contact.
*/
Vector2D<float> getPosition();
/**
*
*/
Vector2D<float> getNormal();
/**
*
*/
Vector2D<float> getTangent();
/**
*
*/
float getPenetration();
private:
Vector2D<float> position;
Vector2D<float> normal;
Vector2D<float> tangent;
float penetration;
};
}
#endif
\ No newline at end of file
#ifndef INCLUDE_CONTACT_CONSTRAINT_H
#define INCLUDE_CONTACT_CONSTRAINT_H
#include <vector>
#include "Body.hpp"
#include "Contact.hpp"
using namespace std;
namespace duodim
{
/**
* Not exactly sure what this thing exactly does, yet.
* TODO: find out what exactly this thing does.
*/
class ContactConstraint
{
const float RESTITUTION_VELOCITY_SLOP = 0.5f;
const float PENETRATION_SLOP = 0.005f;
const float BAUMGARTE = 0.1f;
public:
/**
* For a given vector of Contacts, return a vector of ContactConstraints that carry the contacts.
* @param newContacts given vector of Contacts
* @return a vector of ContactConstraints
*/
static vector<ContactConstraint> withContacts(vector<Contact> 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.
* @param oldConstraints given vector of existing constraints
* @param newContacts given vector of Contacts
* @return a vector of ContactConstraints
*/
static vector<ContactConstraint> withPersistentContacts(vector<ContactConstraint> oldConstraints, vector<Contact> newContacts);
/**
* ContactConstraint constructor.
* @param contact the associated Contact.
*/
ContactConstraint(Contact contact);
/**
* Return this constraint's contact.
*/
Contact getContact();
/**
* Perform initial velocity calculations for two given bodies.
* @param a first Body
* @param b second Body
*/
void initializeVelocity(Body a, Body b);
/**
* Apply collision impulses for two given bodies.
* @param a first Body
* @param b second Body
*/
void warmStartVelocity(Body a, Body b);
void solveVelocity(Body a, Body b);
void solvePosition(Body a, Body b);
private:
Contact contact;
float normalImpulse = 0.f;
float tangentImpulse = 0.f;
float normalMass = 0.f;
float tangentMass = 0.f;
float restitution = 0.f;
float frictionCoefficient = 0.f;
};
}
#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
#ifndef INCLUDE_BODY_HPP
#define INCLUDE_BODY_HPP
#include "Transform.hpp"
#include "Bounds.hpp"
#ifndef INCLUDE_BODY_H
#define INCLUDE_BODY_H
#include "AxisAlignedBoundingBox.hpp"
#include "Material.hpp"
#include "Vector2D.hpp"
#include "Shape.hpp"
#include "Transform.hpp"
#include "Vector2D.hpp"
namespace duodim
{
struct BodyPair {
unsigned int aId;
unsigned int bId;
};
class Body
{
public:
Body(Material material, Shape shape);
Body(Material material, Shape shape, float density);
Body(Vector2D<float> position, Material material, Shape shape);
Body(Vector2D<float> position, Material material, Shape shape, float density);
Body(float posX, float posY, Material material, Shape shape);
Body(float posX, float posY, Material material, Shape shape, float density);
Body();
Body(Shape* shape);
Body(Material material);
Body(Material material, Shape* shape);
Body(Vector2D<float> position);
Body(Vector2D<float> position, Shape* shape);
Body(Vector2D<float> position, Material material);
Body(Vector2D<float> position, Material material, Shape* shape);
Body(float posX, float posY);
Body(float posX, float posY, Shape* shape);
Body(float posX, float posY, Material material);
Body(float posX, float posY, Material material, Shape* shape);
Shape getShape();
Material getMaterial();
Shape* getShape();
Transform getTransform();
Vector2D<float> getVelocity();
float getAngularVelocity();
float getMass();
float getInverseMass();
float getInverseInertia();
float getDensity();
unsigned int getId();
bool isStatic();
void addForce(Vector2D<float> f);
......@@ -31,7 +50,7 @@ namespace duodim
void setPosition(Vector2D<float> p);
void setShape(Shape s);
void setDensity(const float d);
void setId(const unsigned int i);
void update();
void integrateForce(const float deltaTime);
void integrateVelocity(const float deltaTime);
......@@ -42,8 +61,8 @@ namespace duodim
Vector2D<float> velocity = Vector2D<float>();
Vector2D<float> force = Vector2D<float>();
Shape shape;
Bounds bounds;
Shape* shape;
AxisAlignedBoundingBox bounds;
Material material;
float angularVelocity = 0.f;
......@@ -57,6 +76,8 @@ namespace duodim
float density;
unsigned int id = 0u;
void initialize();
};
}
......
......@@ -5,12 +5,18 @@ namespace duodim
class Material
{
public:
Material(float friction, float restitution);
static Material wood() = Material(0.f, .2f, .3f);
static Material bouncyBall() = Material(0.f, .8f, .3f);
static Material superBall() = Material(0.f, .95f, .3f);
Material();
Material(float friction, float restitution, float density);
float getFriction();
float getRestitution();
float getDensity();
private:
float friction;
float restitution;
float density;
};
}
#endif
\ No newline at end of file
#ifndef INCLUDE_CIRCLE_HPP
#define INCLUDE_CIRCLE_HPP
#include "AxisAlignedBoundingBox.hpp"
#include "Shape.hpp"
#include "Bounds.hpp"
namespace duodim
{
class Circle : public Shape
......@@ -13,7 +11,7 @@ namespace duodim
Circle(float radius);
~Circle();
Bounds getBounds(const Vector2D<float> position);
AxisAlignedBoundingBox getBounds(const Vector2D<float> position);
MassAndInertia getMassAndInertia(const float density);
float getRadius();
void setRadius(float r);
......
#ifndef INCLUDE_CONVEX_POLYGON_HPP
#define INCLUDE_CONVEX_POLYGON_HPP
#include <list>
#include <optional>
#include "AxisAlignedBoundingBox.hpp"
#include "Shape.hpp"
#include "Transform.hpp"
......@@ -17,7 +17,7 @@ namespace duodim
ConvexPolygon(list<Vector2D<float>> vertices);
~ConvexPolygon();
Bounds getBounds(const optional<Transform> transformOpt);
AxisAlignedBoundingBox getBounds(const optional<Transform> transformOpt);
MassAndInertia getMassAndInertia(const float density);
list<Vector2D<float>> getVertices();
......
#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
......@@ -15,7 +14,7 @@ namespace duodim
Rectangle(float dim);
~Rectangle();
Bounds getBounds(const optional<Transform> transformOpt);
AxisAlignedBoundingBox getBounds(const optional<Transform> transformOpt);
MassAndInertia getMassAndInertia(const float density);
float getHeight();
......
#ifndef INCLUDE_SHAPE_HPP
#define INCLUDE_SHAPE_HPP
#ifndef INCLUDE_SHAPE_H
#define INCLUDE_SHAPE_H
#include <optional>
#include <string>
#include "Bounds.hpp"
#include "AxisAlignedBoundingBox.hpp"
#include "Transform.hpp"
using namespace std;
namespace duodim
{
struct MassAndInertia {
......@@ -18,7 +15,7 @@ namespace duodim
class Shape
{
public:
virtual Bounds getBounds(optional<Transform> transformOpt);
virtual AxisAlignedBoundingBox getBounds(optional<Transform> transformOpt);
virtual MassAndInertia getMassAndInertia(const float density);
string getName();
......
#ifndef INCLUDE_BOUNDS_H
#define INCLUDE_BOUNDS_H
#ifndef INCLUDE_AXIS_ALIGNED_BOUNDING_BOX_H
#define INCLUDE_AXIS_ALIGNED_BOUNDING_BOX_H
#include "Vector2D.hpp"
namespace duodim
{
class Bounds
class AxisAlignedBoundingBox
{
public:
static Bounds fromCenterAndExtents(Vector2D<float> center, const Vector2D<float> extents);
static Bounds asUnion(Bounds a, Bounds b);
Bounds();
Bounds(const Vector2D<float> min, const Vector2D<float> max);
static AxisAlignedBoundingBox fromCenterAndExtents(Vector2D<float> center, const Vector2D<float> extents);
static AxisAlignedBoundingBox asUnion(AxisAlignedBoundingBox a, AxisAlignedBoundingBox b);
AxisAlignedBoundingBox();
AxisAlignedBoundingBox(Vector2D<float> min, Vector2D<float> max);
Vector2D<float> getMin();
Vector2D<float> getMax();
Vector2D<float> getCenter();
Vector2D<float> getExtents();
Bounds expandBy(const float factor);
AxisAlignedBoundingBox expandBy(const float factor);
float getPerimeter();
bool intersects(const Bounds o);
bool contains(const Bounds o);
bool intersects(const AxisAlignedBoundingBox o);
bool contains(const AxisAlignedBoundingBox o);
private:
Vector2D<float> min;
Vector2D<float> max;
......
#include <optional>
#include "Engine.hpp"
#include "World.hpp"
using namespace duodim;
using namespace std;
Engine& Engine::getInstance()
{
static Engine instance;
return instance;
}
Engine::Engine() {}
int Engine::run()
{
running = true;
World& world = World::getInstance();
float frameStart = 0.f; // GetCurrentTime();
while (running)
{
const float currentTime = 0.f; // GetCurrentTime();
accumulator += currentTime - frameStart;
frameStart = currentTime;
if (accumulator > .2f)
{
accumulator = .2f;
}
// Avoid spiral of death and clamp dt, thus clamping
// how many times the UpdatePhysics can be called in
// a single game loop.
while (accumulator > dt) {
world.update(dt);
accumulator -= dt;
}
// Render();
}
}
void Engine::stop()
{
running = false;
}
\ No newline at end of file
#include <optional>
#include <unordered_map>
#include "World.hpp"
#include "Body.hpp"
using namespace duodim;
using namespace std;
World& World::getInstance()
{
static World instance;
return instance;
}
World::World() : bodies({}) {}
optional<Body> World::getBody(unsigned int id)
{
return bodies.find(id) == bodies.end() ? nullopt : optional<Body>{bodies[id]};
}
float World::gravityConst = -9.81f;
bool World::addBody(Body body)
{
unsigned int startId = body.getId();
for (unsigned int i = 0; i < bodyKeys.size(); i++)
{
if (startId >= bodyKeys[i])
{
startId++;
}
else
{
i = bodyKeys.size();
}
}
body.setId(startId);
bodies[startId] = body;
updateKeys();
return true;
}
bool World::removeBody(Body body)
{
bodies.erase(body.getId());
updateKeys();
return true;
}
void World::update(float deltaTime)
{
for(auto b : bodies)
{
b.second.update();
}
}
void World::updateKeys()
{
bodyKeys.clear();
for (auto kv : bodies)
{
bodyKeys.push_back(kv.first);
}
}
\ No newline at end of file
#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
#include <vector>
#include "AxisAlignedBoundingBox.hpp"
#include "Body.hpp"
#include "BroadPhase.hpp"
using namespace duodim;
using namespace std;
BroadPhase& BroadPhase::getInstance()
{
static BroadPhase instance;
return instance;
}
BroadPhase::BroadPhase() {}
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 j = bodies.begin(); j != bodies.end(); j = bodies.next())
{
Body* a = &i->getData();
Body* b = &j->getData();