Skip to content

Archive

Tag: game physics

Most 3D applications use a scenegraph that stores scene node coordinates and we need a convenient way to update these coordinates from the physical simulation. In this case the simulation contains a dynamic object which moves ‘on its own’, being subject to gravity, collisions and other forces.

Often we want to animate objects ourselves, but we still want other objects to bounce off such objects, so we create a kind of alias or reference to the object we’re animating. Such an alias or reference is made into a kinematic object. A kinematic object still has physical properties (e.g. friction) that help determine how dynamic objects interact with it.

This article is a work in progress. Please refer to the motion state tutorial on the Bullet wiki. In theory motion states and kinematic bodies are ‘pretty simple’. I often find it easier to use dynamic bodies out of the box and rely on the default motion state.

The motion state

All bodies in the simulation are setup with a motion state.

The motion state allows sharing a node’s transform between the physics engine and the renderer. btMotionState is a small interface that specifies a getter/setter pair. The bullet API calls the getter to retrieve the shared transform and calls the setter to assign it.

Kinematic objects aren’t animated by the simulation, ‘we do it ourselves’. How do we let the simulation know that these objects have moved?

  1. Create a rigid body that will ‘stand for’ the kinematic object. This will be a kind of ‘alias’ or ‘reference’ to the object we’re animating, so we need to disable dynamics for this object (so it won’t be influenced by gravity or other objects).
  2. implement getWorldTransform() so that an up to date transform is returned whenever the simulation calls that function.
  3. Implement setWorldTransform() so that you (or the engine, if interpolating) can set the transform.
  4. Make the object ‘kinematic’ (see below)

Configuration:

There are two steps to ‘make an object kinematic’.

body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);

This flag tells the engine that the object is kinematic – so it shouldn’t move under the influence of gravity or because of colliding with other objects.

body->setActivationState(DISABLE_DEACTIVATION);

This prevents the object from ‘falling asleep’. Normally objects that haven’t moved in a while aren’t processed and keep sleeping until something bumps into them, or something that they’re in contact with wakes them up. Since kinematic objects aren’t affected by forces, we need to prevent them from falling asleep.

Back to dynamic state (UNTESTED)

body->setCollisionFlags( body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT));

body->activate(true); // or try… body->forceActivationState(ACTIVE_FLAG)

Tips and Caveats

  • Avoid relying on how many times or when the motion state’s get/set methods are accessed. Even if your object is not kinematic, the motion state’s getter may be called after the initial simulation step (TESTED).
  • If you ‘teleport’ a dynamic object, set the object’s transform by calling body->getWorldTransform().setOrigin(); even if you have removed the body from the simulation, after adding this object again the transform underlying your motion state may be overridden by a call to setWorldTransform before getWorldTransform is called by the engine.
  • In my experience it would appear that kinematic objects are somewhat less reliable than dynamic objects. I often seen tunneling effects that disappear if I use a dynamic object instead. Once again testing in a sandbox can be very helpful in such cases.

In the Bullet Physics Library, collision shapes are used to detect collisions between physical bodies.

You can get a feel of what’s available by looking at the inheritance diagram (from the Bullet docs). Depending on the workflow you’re implementing, just using meshes may be a quick-fix. However meshes have several disadvantages, which is why geometric primitives are thrown in:

  • Performance – colliding meshes can be slow
  • Reliability – high speed objects are more likely to miss/fall through when colliding with meshes. This can be fixed using ‘continuous collision detection’ or stepping the simulation slower, but it may reduce performance even more.
  • Memory – Primitives use very little memory.

Convex/Concave

Convex shapes tend to process collisions faster:

  • cone, capsule, sphere, box, cylinder …

Concave shapes tend to process collisions slower

  • Banana, bowl, ring, coffee cup…

If your mesh is convex (boulder?) or mainly interacts with objects 5-10 times bigger than itself, btConvexPointCloudShape has better performance than btBvhTriangleMeshShape.

If we model a coffee cup using a convex point cloud, we can’t shoot  a bullet through the handle(*). But there’s no effective difference when simulating a cup falling on the ground (either way it won’t shatter like the real one, which is sad).

(*) got this example from Wikipedia

Code samples

Collision mesh

To create a collision mesh, we can use…

Example:

#include “btBulletDynamicsCommon.h”

// … DIY: put this code in a function or class method…

btTriangleMesh* data = new btTriangleMesh();

btVector3 A(0.0f,0.0f,0.0f);

btVector3 B(1.0f,0.0f,0.0f);

btVector3 C(0.0f,0.0f,1.0f);

data->addTriangle(A,B,C,false); // false, don’t remove duplicate vertices

// true for using quantization; true for building the BVH

btBvhTriangleMeshShape* shape=new btBvhTriangleMeshShape(data,true,true);

The flags (quantization, BVH) have to do with internal optimizations, I just use the recommended defaults.

Note: I once idiotically created degenerate meshes (each triangle used 3 times the same point). A mesh setup in this awful way may sometimes generate collisions and cause fancy restitution effects. Before you start looking everywhere else for ways to fix tunneling and restitution, make sure your mesh is correctly setup (sigh).

Sphere

float radius=2.5f;

btCollisionShape* shape = new btSphereShape(radius);

Capsule

float totalHeight=5.0f;

float radius=1.0f;

btCollisionShape* shape = new btCapsuleShape(radius,totalHeight-radius*2.0f);

A capsule looks like a medicine pill standing upright. You can use btCapsuleShapeX / btCapsuleShapeZ if you want a different orientation. You could also use btMultiSphereShape if you want to create ‘thick segments’ with round caps (without using a transform) or other interesting things (rounded cuboids and such…)

Workflow notes

If you don’t want your setup to be completely game/application specific, simple techniques can be used to select the right primitives.

In my 3D editor, I use layers to hold various kinds of objects. So I have a layer for actors, another for the terrain, etc…

  • If you don’t need much realism, capsules are a popular choice for actors (another time, I’ll explain why I prefer using spheres).
  • boxes or spheres may be a good choice if you want to include collectible items in your simulation.

Instead of, or in combination with layers, you can use reference metrics to help you decide how an object should be represented:

  • large, concave objects (e.g, weird shaped platforms and such) may require ad-hoc meshes with as few triangles as possible (use a triangle mesh)
  • medium sized objects may use convex point clouds.
  • small objects can use box, cylinder or sphere primitives. If you don’t want your objects to roll, boxes and cylinders are a better choice.
  • fast, small objects (projectiles) can miss collisions easily. Using an elongated ‘dash-arrow-shaped-thing’ (triangle or cylinder) eliminates this problem.

‘Reference metrics’ means that you pass a descriptor defining ‘large, medium, small and fast’ to the class that builds your collision shapes. Then we can use the same factory over and over with game specific metrics. If you simulate very large or very small objects (‘not human scale’), you should worry about scaling (link to the Bullet wiki).

Next time…

Gravity’s fun. Applying forces and shoving bodies around is more fun. Next time we’ll look into dynamic and kinematic behavior.

This article is meant to provide a quick introduction to my ‘Bullet diaries’.

I’d like to review it but in short I only want to say this:

  • If you’re familiar with game programming but feel anxious about integrating with a physics engine, maybe you should consider trying something out anyway, because it needn’t be too difficult.
  • A lot of game programming is about generating events in response to collisions. Writing fast, efficient code for this isn’t easy, even if you just collide spherical or square bounds. It would appear that a physics engine can help a lot.

A quick list of open source physics engines

Expectations

I have moving platforms in my games. I want actors to jump and fall. If I feel comfortable with physics integration there are other responsibilities that may (or may not) be trusted to a physics engine.

I already have a system for moving platforms. I’m still motivated because my code requires cleaning up memory management, tuning performance and refactoring (sigh). Good time to consider alternatives.

I have expectations:

  1. Dynamics simulationdeal breaker: Manage falling actors, actor collisions, projectiles etc… if writing code for this using a physics engine isn’t to hard, then I’ll be happy to leave my own code behind.
  2. Kinematics – Help with moving platforms and similar; or at least integrate reasonably well with objects that we want to ‘move ourselves’
  3. Keep actors from ‘diving into the terrain’. This can be done fairly easily and reliably without a physics engine. I hope the physics engine I pick can do it faster, and it will still be reliable (no ‘falling through the ground’). Otherwise actors may need to be ‘half dynamic’, ‘half kinematic’ – a gray zone that should worry game programmers.
  4. More generally, help with the walking and navigation system. I put enough work into my navigation system to know that (a) there is more to navigation than just physics and (b) waypoint interpolation of some kind can often be used to manage NPC navigation faster than a physics engine ever could.
  5. Detecting ‘active area collisions’. Maybe you want to start a song, or spawn NPCs, when the PC enters specified bounds. May seem odd, but if the engine we’re using benefits optimized collision detection for simple shapes, there may not be a need to roll our own code for this. Depending on the engine structure, we may instantiate a separate simulation for this.

Required know-how

I had a quick read through the bullet docs. To meet the above expectations, I need basic knowledge of the following:

  • Setting up and iterating a simulation with simple shapes (boxes, spheres, capsules, …).
  • Setting up kinematic bodies – bodies that move around without being influenced by physics, but may deflect other objects
  • Setting up collision meshes.
  • Getting notified when collisions occur.
  • A way to tell the engine which objects will never collide, either because we allow them to pass through each other or because we just know they never get a chance to collide at all.

It’s probably too early to close the list. I’ll go first through the items that worry me a little more. No point in doing the easy stuff first, only to discover that we can’t do the hard things we really need to rely on.

This is a rough introduction to the Bullet physics engine.

I keep this article for reference. If you want a clean setup for building bullet as an iOS ready static library, please check this post.

You’re crying out for a physics engine. You wanna make one of these gimmicky, fashionable and ever profitable physics puzzlers, right?

If it’s a 2D engine you’re after, try Box 2D (<= links to a pocket gamer article!), it’s free, worth millions to some.

I sweated over my laptop 4 hours putting this together. It’s not so very difficult, but it’s summer and it’s HOT.

The bigger they come… (1.30 pm)

I decided to have a shot at building Bullet for a start.

Downloading the source isn’t a problem; the archive itself is… …varied. Lots of stuff at the root level, and a promising ‘src’ folder.

I approached the “build issue” (with a pig) head on. I made a new project in XCode, added all files from the src folder, and started building.

Don’t do this (use => this article instead.)

I removed many things that stood in the way:

  • “imbsdk”/ folders
  • make files

Then the build started bumping on #include “foo/bar/file.h” style commands. Makes sense, because adding all the files the way I did puts all files ‘at the same level’, so there’s no need for a ‘foo/bar/’ unless you expect a collision. I didn’t expect a file-space collision, and I was right. Yea, I moronically search-killed all foo/bar/ sections from all files.

There’s another couple of libs I didn’t like. The multi-threaded library trashed the build and doesn’t seem that promising just yet. There’s also the mini-cl thing. I dunno what that is except it uses the multithreaded lib headers, so I unchecked a couple more files from that mini-cl thingy.

Yay. I built bullet, I haven’t read the docs or anything yet. I don’t even know if the build is any use to nothing since I trashed stuff on my way. But hey, it’s building, right?

Surgery time: ~35 minutes

Examples, any? (2.45 pm)

I searched for sample code in the archive. Maybe what I was looking for was a quick ‘falling ball world’ with stdout logs to explain what’s going on. I know it’s unpretty but it does away with the need to show things and I didn’t expect GL-ES ready code in the demos either.

Then I found:

  • The Bullet user manual [link now fixed]
  • Their hello world tutorial.
    (please have a look, the remainder of this article is about getting this example to compile and run in an Objective C environment).
  • This (although ‘it’ may be out of date).

They do have an article showing how to include Bullet in an MacOS-X project. It looks like it would take no more than 10 minutes. I skip-read that it causes a framework to be generated. I may be wrong, but I don’t think we can include any framework other than what ships directly with iOS devices. We need static libraries, right?

Clock ticking (3.45)

I did nothing impressive in the past hour. I pasted the example from that hello world tutorial (link, above) in a char testBullet() function. I put that in a *.cpp file, not just wishfully but because the includes won’t compile as C (well, it is C++ code – and by the way that didn’t work, see below… ).

Surely I made a sample project to contain this stuff. Any project template will do, just for a test. So I created a project, pasted the code in test_bullet.cpp which contained this char testIt() method (don’t google these names, follow the link to the tutorial instead).

Calling this cpp code from an objective C class caused a linkage error, leading to a shocking discovery.

Interlude

I like the hello balls or watchamacallit example A LOT. Because it has this line in it:

std::cout << “sphere height: “ << trans.getOrigin().getY() << std::endl;

For whatever obscure reason this great classic glitched my build. So I substituted a greater classic:

printf(“sphere height: %f\n”,trans.getOrigin().getY());

Overall the test didn’t go too well, expect it worked (ha!).

I muddled endlessly over the “btBulletDynamicsCommon.h” include. This includes this, this and that, and cutting and pasting the include folders into Build Settings > User Header Search Paths takes AGES (If you now a better way, absolutely please leave a comment after this post)

The shocking discovery

I started considering mournfully how I don’t really know how to bridge C++ and Objective C. Then I found a doc claiming that…

you can dump whatever C++ you want in an Objective C file as long as you substitute .mm to .m

Not believing it one bit, I renamed my .cpp file to .mm; wrapped my test code as a class function, like this:

#include “TestBullet.h”

#include <stdio.h>

#include “btBulletDynamicsCommon.h”

@implementation TestBullet

+(BOOL)test{

// Welcome to C++land.

// Paste here sample code found at the bottom of that page.

// …

// … what are you waiting for?

}

@end

Supernaturally, this compiles without twisting a nail.

Understanding is nothing (4.42pm)

The world is unfair. I picked bullet first because of all the hype surrounding it (July 2011).  I’m sure there are many decent physics engines out there, but that is that.

Other than producing a nasty project file that can build the library, I know nothing about Bullet physics. Feels good, in a kind of way.

Looking at the fine print below – a mantra much simpler than the sample code – there’s a couple of things we can infer:

  • There is a ball. Likely, a solid thing. That’s a bit cheated from the console output but let’s believe it.
  • There is gravity. Gravity’s good.
  • There is a ground abstraction. Ground is good.
  • No input file or likewise cheat. Everything is setup programatically.

Their sample code is 65 lines long. Didn’t expect anything better (sigh). For better and for worse, the tutorial explains this step by step. Maybe I’ll understand if I set a few hours aside to read it.

Attaching to process 2589.

sphere height: 49.997223
sphere height: 49.991669
sphere height: 49.983334
sphere height: 49.972221
sphere height: 49.958332
sphere height: 49.941666
sphere height: 49.922222
sphere height: 49.900002
sphere height: 49.875000
sphere height: 49.847221
sphere height: 49.816666
sphere height: 49.783333
sphere height: 49.747223
sphere height: 49.708336
sphere height: 49.666668
sphere height: 49.622223
sphere height: 49.575001
sphere height: 49.525002
sphere height: 49.472225
sphere height: 49.416668
sphere height: 49.358334
sphere height: 49.297222
sphere height: 49.233334
sphere height: 49.166668
sphere height: 49.097225
sphere height: 49.025002
sphere height: 48.950001
sphere height: 48.872223
sphere height: 48.791668
sphere height: 48.708336
sphere height: 48.622223
sphere height: 48.533333
sphere height: 48.441666
sphere height: 48.347221
sphere height: 48.250000
sphere height: 48.150002
sphere height: 48.047222
sphere height: 47.941666
sphere height: 47.833332
sphere height: 47.722221
sphere height: 47.608334
sphere height: 47.491669
sphere height: 47.372223
sphere height: 47.250000
sphere height: 47.125000
sphere height: 46.997223
sphere height: 46.866669
sphere height: 46.733334
sphere height: 46.597221
sphere height: 46.458332
sphere height: 46.316666
sphere height: 46.172222
sphere height: 46.025002
sphere height: 45.875000
sphere height: 45.722221
sphere height: 45.566666
sphere height: 45.408333
sphere height: 45.247223
sphere height: 45.083336
sphere height: 44.916668
sphere height: 44.747223
sphere height: 44.575001
sphere height: 44.400002
sphere height: 44.222225
sphere height: 44.041668
sphere height: 43.858334
sphere height: 43.672222
sphere height: 43.483334
sphere height: 43.291668
sphere height: 43.097225
sphere height: 42.900002
sphere height: 42.700001
sphere height: 42.497223
sphere height: 42.291668
sphere height: 42.083336
sphere height: 41.872223
sphere height: 41.658333
sphere height: 41.441666
sphere height: 41.222221
sphere height: 41.000000
sphere height: 40.775002
sphere height: 40.547222
sphere height: 40.316666
sphere height: 40.083332
sphere height: 39.847221
sphere height: 39.608334
sphere height: 39.366665
sphere height: 39.122219
sphere height: 38.874996
sphere height: 38.624996
sphere height: 38.372219
sphere height: 38.116665
sphere height: 37.858330
sphere height: 37.597218
sphere height: 37.333328
sphere height: 37.066662
sphere height: 36.797218
sphere height: 36.524998
sphere height: 36.249996
sphere height: 35.972218
sphere height: 35.691662
sphere height: 35.408329
sphere height: 35.122219
sphere height: 34.833328
sphere height: 34.541660
sphere height: 34.247215
sphere height: 33.949993
sphere height: 33.649994
sphere height: 33.347218
sphere height: 33.041660
sphere height: 32.733326
sphere height: 32.422215
sphere height: 32.108326
sphere height: 31.791658
sphere height: 31.472214
sphere height: 31.149992
sphere height: 30.824991
sphere height: 30.497213
sphere height: 30.166658
sphere height: 29.833324
sphere height: 29.497213
sphere height: 29.158325
sphere height: 28.816658
sphere height: 28.472214
sphere height: 28.124992
sphere height: 27.774992
sphere height: 27.422215
sphere height: 27.066660
sphere height: 26.708326
sphere height: 26.347216
sphere height: 25.983326
sphere height: 25.616659
sphere height: 25.247215
sphere height: 24.874992
sphere height: 24.499992
sphere height: 24.122215
sphere height: 23.741659
sphere height: 23.358326
sphere height: 22.972216
sphere height: 22.583326
sphere height: 22.191660
sphere height: 21.797216
sphere height: 21.399994
sphere height: 20.999994
sphere height: 20.597218
sphere height: 20.191662
sphere height: 19.783329
sphere height: 19.372219
sphere height: 18.958330
sphere height: 18.541664
sphere height: 18.122219
sphere height: 17.699997
sphere height: 17.274998
sphere height: 16.847219
sphere height: 16.416664
sphere height: 15.983332
sphere height: 15.547221
sphere height: 15.108333
sphere height: 14.666666
sphere height: 14.222222
sphere height: 13.775001
sphere height: 13.325001
sphere height: 12.872224
sphere height: 12.416669
sphere height: 11.958336
sphere height: 11.497225
sphere height: 11.033337
sphere height: 10.566670
sphere height: 10.097226
sphere height: 9.625005
sphere height: 9.150005
sphere height: 8.672228
sphere height: 8.191673
sphere height: 7.708341
sphere height: 7.222230
sphere height: 6.733342
sphere height: 6.241676
sphere height: 5.747232
sphere height: 5.250010
sphere height: 4.750011
sphere height: 4.247234
sphere height: 3.741679
sphere height: 3.233346
sphere height: 2.722236
sphere height: 2.208348
sphere height: 1.691682
sphere height: 1.172238
sphere height: 0.650017
sphere height: 0.720013
sphere height: 0.787232
sphere height: 0.851673
sphere height: 0.913337
sphere height: 0.972222
sphere height: 1.028330
sphere height: 1.081660
sphere height: 1.132212
sphere height: 1.179986
sphere height: 1.224983
sphere height: 1.267202
sphere height: 1.306643
sphere height: 1.343306
sphere height: 1.377192
sphere height: 1.408299
sphere height: 1.436629
sphere height: 1.462181
sphere height: 1.484956
sphere height: 1.504952
sphere height: 1.522171
sphere height: 1.536612
sphere height: 1.548276
sphere height: 1.557161
sphere height: 1.563269
sphere height: 1.566599
sphere height: 1.567151
sphere height: 1.564925
sphere height: 1.559922
sphere height: 1.552141
sphere height: 1.541582
sphere height: 1.528245
sphere height: 1.512130
sphere height: 1.493238
sphere height: 1.471568
sphere height: 1.447120
sphere height: 1.419895
sphere height: 1.389891
sphere height: 1.357110
sphere height: 1.321551
sphere height: 1.283214
sphere height: 1.242100
sphere height: 1.198208
sphere height: 1.151538
sphere height: 1.102090
sphere height: 1.049864
sphere height: 0.994861
sphere height: 0.995889
sphere height: 0.996711
sphere height: 0.997369
sphere height: 0.997895
sphere height: 0.998316
sphere height: 0.998653
sphere height: 0.998922
sphere height: 0.999138
sphere height: 0.999310
sphere height: 0.999448
sphere height: 0.999559
sphere height: 0.999647
sphere height: 0.999717
sphere height: 0.999774
sphere height: 0.999819
sphere height: 0.999855
sphere height: 0.999884
sphere height: 0.999907
sphere height: 0.999926
sphere height: 0.999941
sphere height: 0.999953
sphere height: 0.999962
sphere height: 0.999970
sphere height: 0.999976
sphere height: 0.999981
sphere height: 0.999984
sphere height: 0.999988
sphere height: 0.999990
sphere height: 0.999992
sphere height: 0.999994
sphere height: 0.999995
sphere height: 0.999996
sphere height: 0.999997
sphere height: 0.999997
sphere height: 0.999998
sphere height: 0.999998
sphere height: 0.999999
sphere height: 0.999999
sphere height: 0.999999
sphere height: 0.999999
sphere height: 0.999999
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000

If DIY means do it yourself, what does DDIY stand for?

DDIY – Don’t do it yourself

A daunting task

If you skimmed through my ‘simple game physics’ articles you would normally expect this to go into sample code or at least explanations regarding collisions and restitution, and so forth. My physics component demonstrated some of these behaviors. It wasn’t great, still useful in a limited way.

Integrating a physics engine was a daunting task. Until the day I actually tried, picked the Bullet physics engine and well - I thought it was alright. By the look of it, basic integration took about 10 days, leaving many loose ends but looking very promising.

Not in vain

Trying to roll my own physics component made it a lot easier and safer to integrate a third party library in place of my own, simplified physics component:

  • My component provided an integration template. I kept the semantics I used, switched my physics classes to interfaces and provided Objective C ++ wrappers for the library objects I needed.
  • I understood the kind of problems the library was trying to solve.

I’m guessing trying 2 libraries instead of just one may be the better way around in this case. While I would probably recommend this approach if you’re starting up, I don’t regret approaching the problem the way I did.

Pros and cons

Before going any further, there’s one point that we ought to clear right away: just because you want ‘simple physics’ doesn’t mean a physics engine will get in your way or integrating with one will be slower than rolling your own. Even if your physics are very simple (e.g. typical 3D RPG), the cost of integration is probably lower than your development cost. Additionally, a good engine like Bullet will make simple things easy and benefit high performance. Integration doesn’t just save the ‘raw development cost’. It saves you the cost of testing, debugging and optimizing your code. Additionally, it is forward looking and opens possibilities (e.g soft body dynamics) that will unlock as hardware becomes faster and your projects become more ambitious.

Reasons to roll your own:

  • The dynamics you’re implementing are truly alien. In other words, you somehow can demonstrate that an engine based on newtonian physics will get in your way altogether.
    If you’re coding a block-world where everything occupies exactly one square on a grid, then there’s no benefit to using a physics library.
  • You need very high performance based on a super-simplified model and can spend the time optimizing your code.

Reasons to integrate

  • You want newtonian dynamics, either advanced or basic (collisions, restitution, forces)
  • You want good performance at low cost

Reading further

Read Expectations: what a physics engine can do for us, then if you follow more recent articles, I give guidance about building and using the Bullet Physics Engine. Bullet is open source and free; I’m liking it so far.

Testing the technology you’re integrating with is important. This applies to Bullet and I think it would equally apply to, say, a game/rendering engine or an XML library.

After a short break in Paris, I’m finding my game physics module where I left it: unfinished. I’m afraid this post isn’t all too informative, but I’ve renewed my commitment to keeping this blog a developer’s diary…

PhysicalModel, for all it’s worth…

I tried to have a look at how PhysicalModel could be implemented. The idea behind PhysicalModel was to have a protocol giving access to physical bodies and/or colliders. This uses a well known pattern: instead of adding the items we want to process to a list or set, we have a protocol specifying how the items are being accessed (a kind of iterator). But frankly I doubt whether the pattern is relevant here. For the sake of efficiency we’d probably allocate an old style array of pointers and iterate that instead, because it’s much faster. For the sake of simplicity, we’d just use an NSArray.

What partakes the physical model?

How do I initialize and maintain the content of PhysicalModel? Nothing explicitly specifies the content of PhysicalModel. We have candidates, but none of these actually describes the model the way I want it to be:

  • I have the cast (the list of actors). To keep things simple i’d like every actor to be modeled as a cylinder.
  • Then we have the terrain. I’d like every platform to be modeled as a special physical body with detailed processing (on a per face basis)
  • Finally, there are a number of elements present in the scenegraph that I would model as obstacles. For these, cylinder/spherical bounds may be enough.

Provisionally, I decided to rebuild the model at the beginning of each chapter. The physical model might need additional maintenance – for example, if actors are added/removed while playing a chapter – but it seems like a decent start. I have a utility class in charge of (re)building the model, looking like this:

@class AntistarCast,WalkableScene,PhysicalModel;

@interface AntistarPhysicalSystemBuilder : NSObject {

}

+(void)buildUsingCast:(AntistarCast*)cast

terrain:(WalkableScene*)terrain

target:(PhysicalModel*)model;

@end

All we have to do to build the model is iterate the terrain/cast and generate physical bodies for matching elements.

Simplifying the model

I had Collider (something other objects can collide with) and PhysicalTarget (can be affected by collisions) protocols. I got rid of that and only kept PhysicalBody. As a result, processing is simplified – each PhysicalBody instance is tested against all other instances for overlaps.

Whether we use separate interfaces or not, we can still reduce overheads - only moving objects need to be tested for collisions. So maybe the distinction between colliders and targets isn’t very useful at this point.

After yesterday’s draft, I tried to implement a simple physical body, PCylinder.

PCylinder implements both <PhysicalTarget> and <Collider>. Depending on how much realism we want, PCylinder can do a number of things as part of collision management. For example – it could be used to prevent cylindrical objects from overlapping with other objects, or it could move cylindrical objects in response to collisions.

I chose PCylinder because it provides a reasonably accurate bounding model for actors – especially bipeds.

But I think this is a little too quick, so let’s backtrack a little and see how we can improve the original model.

The ‘no difference’ simulation

PhysicalSystem, as drafted in the previous session is too preemptive. Instead of addressing collisions at this level, we can just iterate a list of ‘physical bodies’ and call their update function.

Initially, a ‘no difference’ physical simulation would just take updates from the ‘user model’ and endorse them; schematically, we’d have aggregations like:

  • Node3D
    • PhysicalBody

then a user would call:

node3d.location = x;

and the no difference simulation would update physical body (and the user node), so PhysicalBody’s update method would look like this:

u=node3d.location – self.location // extract location update ‘request’.
// do nothing here, don’t modify
u (‘no difference’)
self.location += u;
node3d.location = self.location;

Why this looks pretty dumb, we can use it as a more reliable starting point, whereas the previous model jumps to collision management without preamble.

The no-overlap rule

Given the above, we can apply a simple no-overlap rule, as follows:

  1. extract update request
  2. apply the updated location to the physical body
  3. check for overlap with colliders.
    1. If there is no overlap, apply the updated location to the user node
    2. Otherwise, restore the physical body to it’s previous location and apply the unchanged location to the user node.

As you can see, there are no physics involved here. In fact not just there are no physics, but with 100% motion absorption, the ‘slightest collisions’ cause actors to freeze. This is a very poor way to handle collisions – so bad in fact that players are likely to complain about getting stuck on every obstacle.

Deflections, bouncing and absorption

For PC navigation, the most satisfying is probably a ‘deflection rule’ that corrects the NPC trajectory while avoiding overlaps, and preserves speed completely. this is less like physics, and more like assisted navigation.

We can take bouncing and absorption into account, if it is relevant to the objects we’re modeling, and the style of gameplay we’re designing. Applying these effects to various objects can be fun (e.g: bouncing of a falling rock). Applying them to the PC adds a gameplay element to navigation – it may fulfill a design requirement, add an element of polish or just frustrate players.

Contact model and platforms

Managing contact is essential to walking, rolling and other ‘ground motion’. A simple, reliable contact model assumes that a physical body is either airborne or not. If the object isn’t airborne, it is resting/moving on the ground. For the sake of simplicity and efficiency, we could provide separate implementations of PhysicalBody for platforms (walkable surfaces) and items.

The crux is that objects will behave quite differently when they’re airborne, and when they’re not.

  • If an object isn’t airborne, we model this object as a ‘contact node’ owned by the platform it is resting on/moving over. This avoids defeating performance overheads.
  • If an airborne object collides with a platform’s walkable surface, it will either bounce or become a contact node.

I’m not your local game physics expert – so if you searched ‘game physics’ this may not be what you’re after. Mostly this article is about the benefits of implementing physical interactions using a separate processing phase, and high level design for this.

I’ve been toying with the idea of having a dedicated processing phase for game physics in Antistar for a long time.

Antistar isn’t a physics puzzler; it does have elements of platform gameplay. Adding jumping, falling and moving platforms means that ‘true’ collisions must be considered. While NPC collisions are typically preempted by avoidance mechanisms (no physics, low level game AIs), there is a physical model, whether explicit or not.

It’s not about realism, it’s about design

Even though game design doesn’t require realistic game physics, having a separate processing phase for physical interactions is attractive. Here is the alternative:

  1. Actuators (classes responsible for state updates) are responsible for updating the location of 3D entities, avoiding collisions and handling contact forces (e.g. what keeps an actor on the ground while walking). So we could have jumping, walking, flying, moving platform actuators and so forth, and each actuator is responsible for invoking collision detection code on an ad-hoc basis. The advantage is that if an object doesn’t move, no work is done, so we have no processing overheads. If we choose this approach game physics of sorts may exist, but not as a separate processing phase.
    => Up to a point it’s OK, but the more physical interactions become complex, the more we see bugs that have to be dealt with on a case basis.
  2. Actuators are only responsible for ‘requesting’ location updates. A separate module is responsible for managing collisions and handling contact forces.
    => More design work upfront, and additional work required to minimize processing overheads; provides a unified approach to handling collisions and contact management

So far I’ve been using choice 1. It worked fairly well with Antistar 1.3/1.3.1 as there was no jumping, and platforms moved only vertically. So I’d say choice 1 is OK if the game doesn’t require complex physics. Many 3D titles on iOS seem to work like that; for example, a lot of 3D shooters and hack-n-slash games could be designed this way.

On the other hand, even a fairly simple 2D platformer would probably benefit from using a separate processing phase for game physics.

Minimal requirements

The minimal requirement for simplistic game physics is that ‘unless otherwise stated’ physical entities shouldn’t overlap. So maybe you’d like to ignore collisions with small objects (e.g. bushes) or NPCs (many 2D platforms do that). But overall we don’t want to see actors going through the terrain, and so forth.

On the design side, requirements are as follows:

  • Ideally, the system should be backwards compatible with existing code. The easiest way to achieve this is to assume that location updates aren’t updating the ‘real’ location. Every time the physical system updates, it would consider that the location determined by actuators is a ‘location request’ and process this against a previously backed up location – that being the ‘effective’ or ‘real’ location.
  • The physics module should be separate from other game modules. So at heart we have a PhysicalSystem (an actuator that processes updates) and a PhysicalModel (an interface that clients implement to expose physical entities to physical system)

A draft design

The draft design can be summarized by a dummy PhysicalSystem implementation:

@interface PhysicalSystem (private)

-(void)update:(id<PhysicalTarget>)target after:(int)ms;

@end

@implementation PhysicalSystem

-(void)step:(int)ms{

for(int i=0;i<[model getTargetCount];i++){

id<PhysicalTarget> target=[model getTarget:i];

[self update:target after:ms];

}

}

-(void)update:(id<PhysicalTarget>)target after:(int)ms{

for(int i=0;i<[model getColliderCount];i++){

id<Collider> collider=[model getCollider:i];

[collider collideWith:target];

}

}

@end

This highlights a few ideas contained in my draft design:

  • I am mostly worried about collision management, and little else (for now).
  • We are manipulating physical entities using protocols/interfaces. At this level there’s no commitment to what the real thing will be, or how it will operate. The system doesn’t have dependencies on scenegraph / navmesh types or other.
  • PhysicalTarget represents a physical object that can move/rotate/deform – could be a ball, or a NPC.
  • Collider represents a physical object that we can collide against.

Separating Collider and PhysicalTarget seems a good idea. A lot of colliders will never move/rotate/deform (e.g. walls, ground) so it seems we might gain in clarity and efficiency starting this way.

[TBC]