This post was originally published at Tutorial: Solutions to Common Physics Issues
This guest tutorial comes to you courtesy of Matt Webster, a.k.a. “HoraceBury.” Matt is a Development Manager working in central London. He has over 15 years of experience building enterprise sites in .NET and Java, but he prefers Corona to build games and physics-based apps. As a Corona Labs Ambassador, Matt has organized Corona meet-ups in London and looks forward to a productive 2015. Matt’s first game in Corona was Tiltopolis, a hybrid twist on the classics Columns and Tetris.
When working with Corona’s Box2D-based physics engine, developers sometimes attempt to perform actions which “fight against” the basis of a simulated physics engine. Similarly, some developers expect the physics engine to behave differently than they expect it to, and become frustrated when it doesn’t. In this tutorial, I’ll outline several of these scenarios and discuss potential solutions.
Controlling the Position of an Object in Box2D
Dynamic objects in the Box2D physics engine are under the constant control of the physics engine, at least while not asleep. If you attempt to change their x or y positional values and move them with your own code, you are forcing the engine to accept a different world position for its own managed objects. As a result, sometimes the engine’s own internal values will effectively “break” during computation. In short, forcing the physics engine to accept different positions for its bodies is effectively fighting the engine for control, and while this is not technically illegal, you should exercise caution and understand the effect of positional overrides.
One potential method of controlling the position of physics bodies is to use the physics engine itself. This can be done by attaching a touch joint to the body and controlling the x/y position of the joint (not the body) via touchJoint:setTarget(), thus moving the body in lock-step. In this manner, you use the physics engine to control the position of the body instead of fighting against it.
It has been mentioned that a static body can be used to absolutely position a dynamic body by attaching the dynamic body to the static body via a weld joint, then moving the static body to the desired position. However, this is similarly inadvisable due to the reasons above (moving the static body forcibly against the engine’s intent).
On Scene Reset, Physics Objects “Reset Wrong” or Don’t Stop Moving
Some games provide a “sandbox” environment which allows the player to edit a scene, for example, by moving physical objects around and then testing the results with the simulation in motion. When the player is finished testing, the objects are expected to reset back to the player’s edited positions, but some developers find that “resetting” their physics scene is problematic because the physics bodies do not stay in their starting positions.
This issue is related to the first topic, but there is another factor to consider: 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, momentum and other internal Box2D values cannot.
The best way to prevent objects from moving with accumulated energy is to outright destroy and rebuild them. For example, in the sandbox scenario described above, you could use non-physics display objects during the editing phase, then create the physics bodies only when the player decides to test the simulation.
Sometimes this is not possible, however, so an alternative solution is similar to the first: create a touch joint on each object. This is an especially good solution because each body can listen, on its own free will, for “freeze/reset” and “unfreeze/play” events. When the “freeze/reset” event is received, you can temporarily turn off the physics body, move the object back to its starting position using .x and .y positioning, and then turn the body back on. At the same time, add a touch joint to keep the object in place. Then, when the “unfreeze/play” event is received, simply remove the touch joint and the body will run free again.
Why do Stacks of Blocks Keep Falling Down?
In Angry Birds™ and related clones, physical objects are stacked — sometimes precariously — on top of each other. Because all objects in the Box2D world contain inertia, even building a tower of simple blocks can be perilous, since the blocks may shudder and nudge each other out the way, eventually collapsing the tower.
The reason the blocks generate this energy is because they have nowhere to dissipate it except to the blocks around them. Those surrounding blocks then acquire that energy and they must dissipate it again, typically back into the blocks surrounding them. This cycle continues until the energy is dissipated into something that does not return any energy, such as a grounded static object.
One potential solution is to control and minimize the energies that the blocks contain by increasing their linear damping and angular damping values. Usually, this will help the bodies absorb excess energy rather than passing it to their neighbors, resulting in a more stable construction.
Another solution is to hold the blocks in place with touch joints, similar to the solutions above. However, in this case, you probably want the blocks to potentially fall down, so at some point you may want to remove the joints and let the physics simulation proceed unrestricted. Another minor adjustment in this case may be to adjust the damping ratio and frequency of the touch joints — in essence, this can give the joints a slight amount of flexibility and “stretch,” allowing the attached blocks to move slightly about their bounded points, but not so much as to collapse the entire construction.
Where is This Object Going to Go?
Games like Angry Birds™, again, have another interesting element where the flight path of projectiles is shown before the launch takes place. While this is a common feature in many games, it can be difficult to calculate, not because the mathematics for calculating trajectory is unusually difficult, but because the Box2D physics engine is a real world simulation. This means that it does not guarantee the exact same result every time. In fact, it almost guarantees at least a slightly different result every time. Also, predicting trajectory is complicated by other simulated factors such as the weight (area×density) of your projectile.
As you might have guessed, there are multiple ways to solve this issue. The first is to simply control the path of travel with a touch joint, moving the object point by point based on the calculated results from the HyperPhysics link above.
The second is to actually calculate the path for real. I published a previous solution and code example in this tutorial, so I won’t repeat the material here.
The third solution is to throw an invisible “copy” of your physics body which is created with specific collision masks such that it will not collide with anything in its path. In this instance, you allow the body to travel for a given amount of time or distance and plot its travelled course with non-physics graphic objects like vector circles. This has the added benefit of a clean, realistically rendered series of dots or lines which show both the trajectory path and the amount of time it will take to reach its target.
Textured Surfaces are “Impossible”
Imagine a plain (top-down) view of a race track. The race cars rush around and potentially hit different road surface types like mud, ice, dirt, grass, etc. Of course, by default, when one physics object hits another, it will simply bounce off, so we can’t layer standard physics objects on top of each other.
Fortunately, Box2D gives us the sensor body property which can be set in either the physics.addBody() declaration or via the object.isSensor property. Considering a thick, gooey patch of mud on the race track, let’s assume that we’ve got a PNG image of mud with a nice transparent background. Using the graphics.newOutline() function, we can get the outline of the mud for use with a physics body. Then, we can load the image as normal and apply the physics outline as per the documentation. In the same declaration, we’ll set the physics body as a sensor and add a collision listener to it (guide). In this manner, when a car hits the mud, it will not bounce off the mud but rather it will fire a collision event. During the
"began" phase of the collision (the time when the car first hits the mud), we can use one of several methods to apply a muddy drag effect to the car — in this case, we’ll increase the linear damping value for the car which will cause it to slow down. Of course, you may need to reduce the linear damping for other surface types like ice or oil, upon which the car would virtually never slow down.
As a final note, remember that you’ll need to remove or “reset” the base physical properties of the car when it exits the hazardous surfaces. For example, if you increase the linear damping on the car when it enters the muddy patch, you should decrease/reset the linear damping when the car exits the mud (the
"ended" collision phase), so that the car can continue to drive as normal on the race track.
Hopefully this tutorial has illustrated some solutions to common physics issues which you may encounter in your current Corona project. As always, if you have found solutions which work alternatively or better than those I’ve presented, please leave feedback below for the benefit of the entire community.
Continue at source:
This post was originally published at Tutorial: Solutions to Common Physics Issues