Sunday, July 15, 2012

Physics

I did a quick UML of the Physics Engine portion of SBEngine.  I love the idea of UML but, I really need to brush up on it.  I'll do that at some point, make sure my arrows are pointing from A to B instead of B to A and what not.  That doesn't really matter for now, what does matter is that it's all diagrammed out and it's going to be interesting to implement.


The main component of any Physics Engine is the Collisions.  Collisions are traditionally split into two phases: Broad and Narrow.  The Broad phase does fast, inaccurate calculations to weed out the collisions that definitely won't happen, the narrow phase does slow, accurate calculations and passes the results to be handled elsewhere (generally by the Objects that collided).  The Broad phase is further broken down into Partitioning/Sorting and Bounding Volume Collisions.

Now, the Narrow phase and BVC subphase both accomplish what they set out to do and little more.

The Partitioning/Sorting phase, though, can accomplish much more than what it set out to do (weed out impossible collisions.)  What it can do, however, is dependent upon the implementation.  For instance, finding out what is next to a specific object (for AI reasons) is very easy in a Spatial Hash Grid, a little harder in a QuadTree and very annoying in Sort & Sweep (Don't worry, the specifics aren't important now, and I'll cover them in another post sometime.)  So how do we approach this from a design perspective.

What we want is a Physics Engine class that you can configure.  The Physics Engine should be the Gateway into everything.  That said, you should be able to pick what the underlying Broad Phase implementation is but, you shouldn't have to get that implementation every time you want to get the implementation specific function.  Ideally the Physics Engine's interface would change depending on the implementation that you choose.

How I wanted to do this:


template < class BroadPhaseImplementation >
class PhysicsEngine : public BroadPhaseImplementation{
...
};

This is policy based class design.  What's good about it?  It fits this problem perfectly.  If I want to route Drawing through a culling process in my HashGrid, I just expose the public function in HashGrid.  That way that funtion will be in PhysicsEngine<HashGrid> but not in PhysicsEngine<NotHashGrid>.

What I'm going to end up doing:


Now, a large reason I'm building this engine is to have something out there for XNA/PSM development.  This means I'm going to have to use C# and C# does not allow inheritance of their template-equivalent generics.  This means I've had to go about it in a much less 'open' manner.

Every PhysicsImplementation will inherit from the PhysicsImplementation interface.  They'll also potentially inherit from different strategies (like a IGetAdjacency strategy).  The Physics Engine will inherit from all of Strategy interfaces.  If the Implementation supports a particular strategy any call to that strategies functions (PhysicsEngine.GetAdjacency() for instance) will be routed to the implementation.  If the implementation doesn't support it, it'll throw an exception.

Why is this worse:


Runtime errors instead of compile time errors is the big thing.  If you tried calling a function that HashGrid had on a Sort&Sweep PhysicsEngine in the Policy based design, it just wouldn't compile.  In this case it will compile but it will through a run time error.

Extensible; if a new implementation comes to the forefront that happens to allow something that no other implementation before it does, I'll have to create an interface for it, a router for it, have it and the PhysicEngine inherit from the interface.  In the policy based design I could just add the function to the implementation and be done with it. 

I'll post the UML when it's a bit more correct.


No comments:

Post a Comment