Here is a really great blog post on the subject of common physics problems, though I'll try to tackle even trickier issues below: http://coronalabs.com/blog/2011/08/08/solutions-to-common-physics-challenges/
- How do I control the position of an object in Box2D?
Dynamic objects in the Box2D physics engine are under the constant control (at least, while not asleep) of the physics engine. If you attempt to change their .x or .y values and move them with your own code you are trying to force the engine to accept a different world position for it's own, managed objects. Because of this change, sometimes it's own internal values will effectively break during computation and the result is that, in Corona SDK, the display objects will be lost from their physics object.
In short, forcing the physics engine to accept different positions for it's bodies is fighting the engine for control and it will break.
The way to control the position of physics bodies is to use the engine to position the them itself. This can be done by attaching a touch joint to the body and controlling the position of the joint and thus the position of the body.
It has been mentioned that static bodies can be used to absolutely position dynamic bodies, via a weld joint, but this is similarly inadvisable due to the the reasons above.
- How can I group the physics bodies like I do with display objects?
Many developers want to group many physics objects into a single display group so that they can move them all together. The physics engine uses the top level display group as the starting 0,0 point for all physics bodies, so trying to move a display object's parent group will not work, because 0,0 never moves.
Grouping the display objects which have physics bodies attached into display groups is not a problem. You just can't move the parent groups at all. This is usually fine because moving a physics body should be done using a touch joint, which will cause any bodies attached by physics joints to move with it.
- When I reset my physics scene the objects don't stop moving or reset wrong!
Description:Some games provide a sandbox environment which allows the player to edit a scene. Whenever the player chooses they can hit a run button and test their scene. They physics objects will move around and then reset back to the player's edited positions, rather than continuing to roll around uncontrolled. Some developers find that resetting their physics scene is a problem because the physics bodies do not want to stay where they should.
This problem is similar to the first problem discussed, but there is also one confusing factor: once physics bodies have been allowed to move, by collision impact, gravity or some other force, they will have built up energy and while energy can be mostly dissipated there will be momentum and other internal, Box2D values which cannot. The best way to avoid objects moving off on their own is to simply destroy them and rebuild. Use a non-physics body display object during the editing and create the physics bodies only when the player hits Run. Sometimes this is not possible. The solution here is also similar to the first problem- simply weld your objects in place either by creating a weld joint between the body and a static object or by using a touch joint. The touch joint is a great solution because you can have each body listening, on it's own free will, to the Runtime (or even the current scene, if you're using Composer) for freeze/reset and unfreeze/play events. When the freeze/reset event is received the physics on the body is turned off, the display object is moved absolutely (using .x and .y positioning) and the body turned back on. A touch joint is then added and used to keep the object in place. object.isFixedRotation=true can even be used to stop rotation. When the unfreeze/play event is received the touch joint is removed (and isFixedRotation=false) and the body runs free again.
- Why do stacks of blocks keep falling down?
In Angry Birds, and so many clones, objects are stacked - sometimes precariously - on top of each other and need to be knocked over. Because all objects in the Box2D world contain inertia, density and various energies, building a tower of even simple squares can be perilous. For now clear reason they will shudder and push each other out the way, collapsing the tower.
The reason the blocks generate this energy is that they have nowhere to dissipate it other than the blocks around them. Those blocks then acquire that energy and need to dissipate it again, back into the blocks surrounding them. The pattern continues until the blocks fall onto something which does not return any energy or they simply drop off the screen. There are two things at play here and the solution, again, is similar to our first problem's solution. Firstly, all objects have energies that may (depending on your particular scenario) need to be controlled (these are the afore-mentioned inertia, density and gravity.) Secondly, holding objects down is usually a good way to make sure they don't wander off on their own. However, here we want the blocks to be able to fall down, just not when they feel like it. One popular solution is to weld them in place or even set their object.bodyType to "static". Static objects do not move and they absorb all energies applied to them. This can be a problem because, as anyone attempting to build a Box2D-Corona rag doll demo has discovered, static objects will absorb all your motion and tear otherwise reliable physics joints apart. The other solution is to set their linear and angular damping values to something small. Usually, this will help the bodies absorb any excess energy, rather than passing it to their neighbours. A compromise on the "nail them down" solution is to simply hold them in place with a touch joint (so useful!) until a pre-collision event occurs, then remove the joint. The best advice is simple: Never use static bodies if you can possibly avoid it. This will be explained in the next problem...
- Where is this object going to go?
Angry Birds, again, has another interesting element where the flight path of one of the moody projectiles is shown before the launch takes place. This is a common feature in many games but is a very difficult thing to calculate. This difficulty comes not because the mathematics for calculating trajectory is difficult (see: http://hyperphysics.phy-astr.gsu.edu/hbase/traj.html#tra12) but because the Box 2D physics engine is a real world simulation. This means that it does not guarantee the same result every time. In fact, it pretty much guarantees at least a slightly different result every time. It is also because other environmental factors, such as the weight (simplified: area*density) of your physics body, need to be taken into account.
As you might have guessed, there are many ways to solve this problem. The first is simply to control the path of travel with a touch joint (see the first problem for why absolute positioning is not a good idea) after calculating it using the HyperPhysics link above. The second is to actually calculate the path for real. A great resource here is the iForce2D site: http://www.iforce2d.net/b2dtut/projected-trajectory which deals with Box2D physics in many scenarios, though mostly with C++. However, the solutions are easy to translate. The third solution is to throw an invisible copy of our physics body which is created with collision masks such that it will not collide with anything in it's path. Allow the body to travel for a given amount of time or distance and plot it's travelled course with non-physics graphics objects. This gives the benefit of a nice, realistically animated series of dots or lines showing not just the path but the time taken, as well.
- Textured surfaces are impossible!
Imagine a plan (top-down) view of a race track. The race cars rush round and need to hit different road surface types. We're talking mud, ice, grass, etc. Of course, when one object hits another, with Box 2D, it will simply bounce off, so we can't layer physics objects on top of each other.
Box 2D does give us sensors with the use of body.isSensor=true and this property can be set not just at creation time, but at any time. For this problem, we'll just set it at creation time. Taking just thick, gooey mud as the problem, let's say we've got a PNG of mud with a nice transparent background. Use the graphics.newOutline() function to get the physics outline of the mud. Then load the image as normal and apply the physics outline as per the documentation. Set the physics body to be a sensor and add a collision listener. When a car hits the mud it will not bounce off the mud but simply fire a collision event. You can now use one of many methods to apply the muddy drag effect to the car. We'll go with: Simply increase the linearDamping value of the car by a tiny amount to see the car slow down. You'll have to play around with the values to get the right effect, but if the mud needs to be layered on top of more mud you can have each muddy layer increase the amount of drag and make the ground even worse to drive through.