Over the last week, I've done quite a bit of work on bouyancy. It's an interesting problem, one that always appears simpler than it really is. The basic concept, that gravity (i.e. soy.bodies.fields.Monopole) effects bodies based on their mass minus their displacement, is deceptively concise.
First, you have to find a way to calculate all the displacements before you try to do gravity calculations. In this case, it required moving the gravity calculations into _commit() and adding action list population to _exert(). This allowed me to leave the displacement math in Bouyancy, storing the information in the bmass tag on effected bodies. However, this leaves yet another problem; all those tags are getting set, but nothing is out there unsetting them. Thankfully, we have Bouyancy._give() to the rescue, ready to clear up all those pesky tags in the cycles where Bouyancy is going to be repopulating them.
Unfortunately, our deceptively simple problem isn't done with us yet. We still don't have a good way to actually calculate displacement. As ODE doesn't have support for this, we have to write an approximation of sorts, and whichever way we do it, some cases are going to lose out. I settled on using pointDepth and a generalized Shape._radius() fuction to estimate how much of the shape of the body was within the Bouyancy field, but I welcome any input on improvements.
Wednesday, August 8, 2007
While things have been pretty quiet recently, I've been getting things done, albeit to an empty theater. There are now several field types that work. While building them, I've added several features to the field system. There are now four functions that can be either defined or not:
- int _apply()
- This function performs the field activation for universal fields (fields not confined to one area).
- int _exert(other)
- This function is called when a field must be applied to a body it effects. Its return value indicates whether exertion was final (i.e. does not need _commit() to be called).
- void _give(mode)
- At the beginning of each field cycle, this function is called. As for mode, 1 means we're in a physics cycle, 0 means we're in a universal cycle.
- void _commit()
- At the end of each physics cycle, this function is called if _exert ever returned 0 (for non-completeness). In the non-collide physics cycle (for universal fields), the Field._apply() function performs a vital part here - careful while overriding it.