Box2DCrates
To simplify development, Moscrif offers framework game 2D classes built from box2D native classes .Class PhysicsWorld is main class, which contains all other physics objects like bodies and joints. PhysicalWorld has same properties as real world like gravity on x and y axis, specified in object constructor or set by PhysicsWorld.setGravity method.
All objects interacting in the physics world are defined as body with different physical properties. Moscrif supports three types of bodies:
#static
Static body does not move under simulation and behaves as infinite mass. Static bodies can be moved manually by PhysicsBody.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 a kinematic body is moved by setting its velocity. A kinematic body behaves as if it has 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 PhysicsBody.setPosition, but normally they move according to forces. A 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.
In Moscrif we can create body by PhysicsBody.addPolygonBody, or PhysicsBody. addCircleBody.
Joints are used to constrain bodies to the world or to each other. There are several different types of joints, with different behaviours. In our application, we use mouse joint to move crates to finger position. We create mouse joint using PhysicsWorld.createMouseJoint. MaxForce property is used to prevent violent reactions when multiple dynamic bodies interact and damping ratio is used to create a spring/damper effect similar to the distance joint.
Practically, this joint does not response directly to mouse or finger interaction. It allows setting position by b2MouseJoint.setTarget, where body tries to get while still interacting with other box2d bodies.
If device runs sample support accelerometer sensor, the gravity is adapted to real device position. For more information about sensors, see Sensors sample.
include "lib://box2d/physicsScene.ms" // create native application window
var app = new Moscrif.Window();
app._terminate = false; app.onStart = function()
{
// creates paint used t draw information about fps
this._paint = new Paint();
this._paint.color = 0xff000000;
this._paint.textSize = 15; this._mouseJoint = null; // creates physics world
var xGravity = 0.;
var yGravity = -9.8;
var sleep = false;
var enableCollisions = true;
this._world = PhysicsScene.create(xGravity, yGravity, sleep, enableCollisions); // load crates image into memory
var imgBox = Bitmap.fromFile("app://box.png"); // creates paint for drawing of ground
var paint = new Paint();
paint.color = 0xaabbccdd; // create ground
var (width, height) = (System.width, 50);
this._ground = this._world.addPolygonBody(null, #static, 0.0 /*density*/, 5.2/*friction*/, 0.3/*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*/, 1.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*/, 1.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*/, 1.0/*bounce*/, width, height);
topMantinel.setPosition(System.width/2, (topMantinel.height/2)); // 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.3/*friction*/, 0.03/*bounce*/, imgBox.width, imgBox.height);
body.setPosition((System.width / (5)) * (i%4 + 1) + rand(10), (System.height-(130+(i%5)*130) - rand(30)) - height/2, 0);
this._bodies.push(body);
} 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();
}
} app.onProcess = function()
{
// return zero when quit requested
if (this._terminate)
return 0;
// calculate physics
this._world.step(1.0 / 40.0, 4, 8);
this._world.clearForces();
this.invalidate();
return 1;
} app.onPointerPressed = function(sender, x, y)
{
// if user cliked to quit button quit application
if (y > (System.height - 50)) {
app._terminate = true;
return;
} 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)) {
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);
}
} } app.onPointerDragged = function(sender, x, y)
{
if (this._mouseJoint != null) {
var b2y = (System.height-y) / this._world.scale;
var b2x = x / this._world.scale;
this._mouseJoint.setTarget(b2x, b2y);
}
} app.onPointerReleased = function(sender, x, y)
{
//destroy mouse joint when user release the crate
if(this._mouseJoint != null)
this._world.destroyJoint(this._mouseJoint);
this._mouseJoint = null;
} app.onKeyPressed = function(sender, key)
{
app._terminate = (key == #back || key == #end || key == #ok || key == #menu);
} app.onDraw = function(sender, canvas)
{
// clear window using solid color
canvas.clear(0xff999999);
// draw physics world
this._world.draw(canvas);
// this._world.doDebugDraw(canvas);
// draw infos
canvas.drawText(String.printf("FPS: %.2f", System.avgFPS), 30, 50, app._paint);
canvas.drawText("drag box, turn device or tap here to quit", 30, System.height - 30, app._paint);
} // initilaizes - allow FPS
app.init(true);
// runs main application object
app.run();
License
This article, along with any associated source codes and files, is licensed under The BSD License
|