Physics Engine and Object Selection

This is the second part of my post about what I've been working on lately. In the first part, I talked about data structures and serialization. In this post, I talk about the physics engine and object selection via mouse picking.

For Ambienome's physics engine, I'm using SquirL, a Common Lisp port of the popular Chipmunk 2D game physics engine. I'm not far enough along yet to know how well it performs in my own game, but from running the demos, it certainly seems performant enough for my purposes. If it turns out to be somewhat sluggish, many Common Lisp implementations can perform some pretty aggressive optimization, given the right type declarations. As a last resort, I could create an FFI binding to the actual Chipmunk library, although that might not be any faster than a well-optimized Common Lisp port. One benefit of a binding to Chipmunk would be using its new features that have not been ported to SquirL (which hasn't been updated in 2 years).

As I explained in the previous post, a creature in Ambienome is composed of a hierarchy of "parts", or shapes. This hierarchical nature means that a child's transformation (position, rotation, scale) are defined relative to the parent, and the parent's transformation affects all the children (and the children's children, and so on). But, SquirL/Chipmunk only has the concept of a body composed of a flat list of shapes; they don't understand hierarchies. So, when generating the physical representation of a creature, the code must "walk" the hierarchy, converting each part's parent-relative transformation to a root-relative transformation.

Actually, though, not every creature will be made of a single physical body. In SquirL/Chipmunk, each body is a rigid body, meaning its component shapes are not supposed to move relative to each other. Physical joints (springs, pivots, etc. — "constraints" in SquirL/Chipmunk parlance) only connect bodies, not shapes within a body. So, any creature that has parts connected via joints will have to be split up into multiple physical bodies. This would happen automatically behind the scenes, of course; Ambienome users don't need to care about the underlying physical representation.

One potential pitfall is that if a part's transformation is changed, the physical representation of it and everything lower in the hierarchy must be updated or regenerated. If a part is changing often, that could be a significant performance hit, and also cause problems with the physics engine. So, it may be that some creatures will have to be split up into multiple physical bodies, even if they don't use explicit joints. A part that will move or rotate often could be automatically split into a separate physical body, then connected to the main body via a joint (or combination of joints) to hold it in place.

Unfortunately, SquirL/Chipmunk cannot handle scale changes in such a graceful way. So, it would still be necessary to regenerate the physical shapes after a scale change, with all the performance and simulation stability issues that entails. Of course, if that turns out to be a big problem, the ability for behaviors to change scale could be limited in some way. I might even disable it at first, then only add that ability later if it can be done without causing problems.

Two other things that I'll need to address with regards to the physics engine, are static creatures and phantom creatures. Static creatures are creatures that don't move, but other creatures can collide and bounce off of them. SquirL and Chipmunk both support fairly simple (but different) ways of accomplishing that, so the technical side is not a problem. But, I'll have to give some thought to how this option is presented to users. For example, is the user able to make a static creature with non-static limbs, like an anemone whose base doesn't move, but whose tendrils do? This has some implications about how creatures are built and structured; it may be necessary or desirable to explicitly divide creatures into segments (corresponding to SquirL/Chipmunk bodies), which are then divided into parts (corresponding to SquirL/Chipmunk shapes).

Phantom creatures are creatures that do not have a solid form, do not collide or bounce off other creatures, but can still move around. This can be accomplished easily in SquirL/Chipmunk by putting all phantom creatures on a designated layer (so they will not collide with non-phantom creatures), and putting them in the same group (so they will not collide with other phantom creatures). But, just like static creatures, the concept of phantom creatures has implications about how a creature is structured. Can some parts of the creature be phantom, while others are not? Ideally, this should be allowed, but it does suggest that my current concepts of creatures and parts needs to be reformed.

The final topic for this post is object selection via mouse picking. This isn't always related to physics engine, but in this case, I'm planning to leverage the physics engine to make picking easier. SquirL and Chipmunk both have ways to check what shapes intersect a point, and Chipmunk additionally has ways to check for intersection with a line segment, axis-aligned bounding box, or shape.

This does mean, though, that all possibly selectable creatures must be added to the physics engine. If I used a different technique for mouse picking, only creatures that actually participate in the physics simulation would need to be added. But I don't expect this to be much of a problem, because the only creatures that could have stayed out of the simulation would be creatures that are both phantom and static, which I think will be relatively rare.

There are several other picking techniques available. Two popular techniques for OpenGL applications are the GL_SELECTION rendering mode, and unique color rendering. These are certainly feasible, but implementing them would take time and effort I could spend on other things, and would add complexity to my code base. So, I'll save them as backup plans, in case using the physics engine for mouse picking doesn't work out.

Previous post: Data Structures and Serialization Next post: A Rubyist's Impressions of Common Lisp