
Combining Easel.js and Box2d in Canvas
Before starting this tutorial it is assumed that you have a basic knowledge of how box2d and easel both work. If you are new to the box2d world, please read through this awesome series of box2d orientation and tutorials from Seth Ladd. If you are new to easel, please check out the documentation so you can get an idea of how to add objects to the stage and understand the overall display hierarchy (hint: it shares several things in common with Flash coding).
Ok, now that that's out of the way, let's dig in. What we're going to create is create a simple demo that rains pink birds like so
View in browser - Download source code
Since we assume a basic understanding of box2d and easel we're going to skip the setup code and dive right in to combining the two frameworks. If you'd like a refresher on that simply download the demo zip or view the source on the demo page.
Now in Easel.js it's extremely simple to add an object to the stage at a specified position. Here's how we add birds to the screen from the ticker (loop) function
Note: all code below is non-functional excerpts from demo.js. For working code, download the zip.
1 2 3 4 5 6 7 | var tick = function(dt, paused) { birdDelayCounter++; if(birdDelayCounter % 10 === 0) { // delay so it doesn't spawn a bird on every frame birdDelayCounter = 0; birds.spawn(); } } |
1 2 3 4 5 6 7 8 | var spawn = function() { var birdBMP = new Bitmap("images/bird.png"); birdBMP.x = Math.round(Math.random()*500); birdBMP.y = -30; birdBMP.regX = 25; // important to set origin point to center of your bitmap birdBMP.regY = 25; stage.addChild(birdBMP); } |
regX and regY (origin point) are important when tying your easel object into box2d. This is because box2d objects have an origin point in the center as opposed to the top left like easel display objects.
Now that we have our images being added to the stage it's time to send 'em over to box2d for further awesomeness.
1 | box2d.createBird(birdBMP); |
1 2 3 4 5 6 7 8 9 10 11 12 13 | var createBird = function(skin) { var birdFixture = new b2FixtureDef; birdFixture.density = 1; birdFixture.restitution = 0.6; birdFixture.shape = new b2CircleShape(24 / SCALE); // half of bird.png width divided by world scale for right size var birdBodyDef = new b2BodyDef; birdBodyDef.type = b2Body.b2_dynamicBody; birdBodyDef.position.x = skin.x / SCALE; // divide skin x and y by box2d scale to get right position birdBodyDef.position.y = skin.y / SCALE; var bird = world.CreateBody(birdBodyDef); bird.CreateFixture(birdFixture); bodies.push(bird); } |
...Actors! Actors are the meat and potatoes of having a visual box2d demo. Basically they have to run during the game loop and translate the box2d body metric positions back to pixel positions. Lets create one.
1 2 | var actor = new actorObject(bird, skin); bird.SetUserData(actor); // set actor as userdata of body so we can get at it later if we need to |
1 2 3 4 5 6 7 8 9 10 | var actorObject = function(body, skin) { this.body = body; this.skin = skin; this.update = function() { // translate box2d positions to pixels this.skin.rotation = this.body.GetAngle() * (180 / Math.PI); this.skin.x = this.body.GetWorldCenter().x * SCALE; this.skin.y = this.body.GetWorldCenter().y * SCALE; } actors.push(this); } |
1 2 3 4 | // within physics loop before world.step for(var i=0, l=actors.length; i<l; i++) { actors<i>.update(); } |
If you want to remove the body AND it's skin together at some point you can add the body to an array to be removed. Bodies must be removed before each world.step.
1 2 3 4 5 6 7 8 9 10 11 | // before step for(var i=0, l=bodiesToRemove.length; i<l; i++) { removeActor(bodiesToRemove<i>.GetUserData()); // get the actor object in the user data of the body and send to removeActor function bodiesToRemove<i>.SetUserData(null); world.DestroyBody(bodiesToRemove<i>); } // after step if(bodies.length > 30) { bodiesToRemove.push(bodies[0]); bodies.splice(0,1); } |
1 2 3 4 | var removeActor = function(actor) { stage.removeChild(actor.skin); actors.splice(actors.indexOf(actor),1); } |
View demo - Download source
If anyone has any optimization suggestions or other was to accomplish this please don't hesitate to leave comments.
by Arjen on Apr 17th 2012 at 3:00am
by Luxamillion on Apr 17th 2012 at 10:09am
by Son Tran on Apr 22nd 2012 at 10:29pm
by Guile on Jan 9th 2013 at 9:43am
by Danny on Jan 18th 2013 at 3:04am
But chrome supports requestAnimationFrame so this should work, right? And from what I can figure out, it's something that I'd like to be using where it's available.
http://www.createjs.com/Docs/EaselJS/classes/Ticker.html#property_useRAF
Thanks for putting up this example, it's helping me figure things out, slowly!
by Dodoy on Feb 15th 2013 at 8:25pm
by Luxamillion on Feb 15th 2013 at 8:38pm