World
World is the main part of box2D. The box2D world simulates the real world with gravity as we know it. The world is a collection of bodies, fixtures and constraints that interact together. The most important world parts are:
-
Bodies: represent all objects in the world. Each body can have different properties like density, friction, bounce, width, height etc.; causing different behavior of the body.
-
Joints: hold two or more bodies together. Box2D supports several joint types: revolute, prismatic, distance and more. Some joints may have limits and motors.
-
Joint limit: restricts the range of motion of a joint. For example, human elbow only allows a certain range of angles.
-
Joint motor: drives the motion of the connected bodies according to the joint's degrees of freedom. For example, you can use a motor to drive the rotation of the elbow.
In our sample, we created a world using PhysicsScene class. Instance of this class may be created by create function. By default, the gravity is set to real world gravity, but if a device supports acceleration sensor, the gravity changes based on how the device is tilted.
Example: Create physics world
// creates physics world
var xGravity = 0.0; // zero gravity on x axis (horizontally)
var yGravity = -9.8; // real gravity on y axis (vertically)
var sleep = false; // forbit sleeping (bodies fall asleep, when they are in rest) it improves performance
var enableCollisions = true; // enable colisions between two bodies
// create physics scene
this._world = PhysicsScene.create(xGravity, yGravity, sleep, enableCollisions);
Bodies
Bodies portray physical objects in the world. They all have different properties like: density, friction, bounce etc. According to their properties, they have a mass and behave according to physical laws. Their behavior is also affected by a body type. There are three body types supported:
-
#static - static body does not move under simulation and behaves as infinite mass. Static bodies can be moved manually by setPosition. A static body has zero velocity and does not collide with other static or kinematic bodies.
-
#kinematic - kinematic body moves under simulation according to its velocity. Kinematic bodies do not respond to forces. They can be moved manually by the user, but normally, kinematic body is moved by setting its velocity. Kinematic bodies behave as if they had infinite mass, but they do not collide with other static or kinematic bodies.
-
#dynamic - dynamic body is fully simulated. It can be moved manually by setPosition, but normally they move according to forces. Dynamic body can collide with all body types and always has finite, non-zero mass. If you try to set the mass of a dynamic body to zero, it will automatically acquire a mass of one kilogram.
Borders
To prevent a body escape from the playground we need to create borders. Borders are box2d bodies and always static bodies. Due to their static type, they do not move under simulation and collide only with dynamic bodies.
Example: create borders around the playground
// create ground
var (width, height) = (System.width, 50);
this._ground = this._world.addPolygonBody(null, #static, 0.0 /*density*/, 5.2/*friction*/, 0.0/*bounce*/, width, height);
this._ground.setPosition(System.width/2, System.height - height/2);
this._ground.onDraw = :sender, canvas :canvas.drawRect(-sender.width/2, -sender.height/2, sender.width/2, sender.height/2, paint); // create walls (width, height) = (1, System.height);
var leftMantinel = this._world.addPolygonBody(null, #static, 0.0/*density*/, 0.0/*friction*/, 0.0/*bounce*/, width, height);
leftMantinel.setPosition(leftMantinel.width/2, System.height/2); (width, height) = (1, System.height);
var rightMantinel = this._world.addPolygonBody(null, #static, 0.0/*density*/, 0.0/*friction*/, 0.0/*bounce*/, width, height); rightMantinel.setPosition(System.width - (rightMantinel.width/2), System.height/2); (width, height) = (System.width, 1);
var topMantinel = this._world.addPolygonBody(null, #static, 0.0/*density*/, 0.0/*friction*/, 0.0/*bounce*/, width, height);
topMantinel.setPosition(System.width/2, (topMantinel.height/2));
Crates
According to the screen dimensions, our application can fit three or more crates. They are dynamic type, which means that they move according to gravity and also collide with static bodies (borders). The bounce property is set to 0.9. It means that the crates bounce with a small damping. The value 1.0 causes bounce without damping.
Example: create crates
// create crates
var (crateWidth, crateHeight) = (imgBox.width, imgBox.height);
this._bodies = new Array();
// set number of crates acording to screen width
const cratesNum = System.width > 320 ? 12 : 4;
for (var i = 0; i < cratesNum; i++) {
var body = this._world.addPolygonBody(imgBox, #dynamic, 0.9 /*density*/, 0.0/*friction*/, 0.0/*bounce*/, crateWidth, crateHeight);
// place body to random position
body.setPosition((System.width / (5)) * (i%4 + 1) + rand(10), (System.height-(130+(i%5)*130) - rand(30)) - height/2, 0);
// push the body to the array
this._bodies.push(body);
}
Mouse joint
The bodies may be moved by user’s finger movement on the screen. To move the bodies according to the user’s requirement, one needs to implement mouse joint. Mouse joint is one of eight joints supported by box2D in Moscrif and it allows moving bodies to required positions. The mouse joint is created when user taps on a crate on the screen.
Example: pointer pressed event
app.onPointerPressed = function(sender, x, y)
{
.... this._mouseJoint = null;
for(var body in this._bodies) {
// calculate border of body
var (bx, by) = body.getWorldCenter();
var realBx1 = bx - body.width/2;
var realBx2 = bx + body.width/2;
var realBy1 = by - body.height/2;
var realBy2 = by + body.height/2;
// check if user cliked inside dthe body
if ((realBx1 <= x && x <= realBx2) && (realBy1 <= y && y <= realBy2)) {
// create additional joint settings
var mouseJointDef = {
maxForce : 2500,
frequencyHz : 10000,
dampingRatio : 0.0,
targetX : x / this._world.scale,
targetY : (System.height-y) / this._world.scale
};
// crate mouse joint
this._mouseJoint = this._world.createMouseJoint(this._ground, body, mouseJointDef, true);
}
}
}
Every time the users moves their finger, the crate moves as well because we set a new target for mouse joint.
Example: pointer dragged event
app.onPointerDragged = function(sender, x, y)
{
// check if mouse joint exists
if (this._mouseJoint != null) {
// convert screen to box2d coordinates
var b2y = (System.height-y) / this._world.scale;
var b2x = x / this._world.scale;
// set new target to mouse joint
this._mouseJoint.setTarget(b2x, b2y);
}
}
More about mouse joint can be found in Mouse joint sample.
Sensors
This sample also reacts based on device's tilt change. The gravity affecting the crates depends on the device position. The acceleration sensor responds to device tilt. This sensor is managed by Sensor class and raised onDataReceived event when it gets new information about the device tilt. The third parameter of this event is array which contains three values: g-force on X, Y and Z axis.
Example: manage sensors
// check if device supports acceleration sensor
if (Sensor.isAvailable(#acceleration)) {
// create sensor
var sensor = new Sensor(#acceleration, 40);
sensor.onDataReceived = function(sender, timestamp, params)
{
// set gravity acording to device position
this super._world.setGravity(-params[0] * 10., -params[1] * 10.);
};
// start senzor data receiving
sensor.start();
}
More information about sensors is availabale in sensors sample.
|