Final result of Box2D Chapter 1
I mention in my last post that Todd Kerpelman created a set of Box2D video tutorials (http://www.kerp.net/box2d/), I just finished up the first chapter and here is what I came up with…
As you can see it isn’t a whole lot, just a bunch of boxes falling down, but damn does it look good
.
Here is the source code for the project
package
{
import Box2D.Collision.b2AABB;
import Box2D.Collision.Shapes.b2PolygonDef;
import Box2D.Common.Math.b2Vec2;
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2BodyDef;
import Box2D.Dynamics.b2DebugDraw;
import Box2D.Dynamics.b2World;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import fl.controls.Button;
import flash.events.MouseEvent;
/**
* Final result of Todd Kerpelman's chapter 1 box2d video tutorial
* (http://www.kerp.net/box2d/).
* The code here is pretty much line for line from Kerpelman's tutorial
* I added a small modification so the simulation may be restarted when
* the user clicks the restart button in the top left of the screen.
* @author Edgar Miranda
*/
public class HelloBoxWorld extends MovieClip
{
protected var _world:b2World;
// Ratio of pixels to meters
public static const RATIO:Number = 40;
// Number of frames until we launch another crate
private var _nextCrateIn: int;
// Button to restart simulation
public var restartButton: Button;
public function HelloBoxWorld()
{
// 1. Set up the world
setupWorld();
// 2. Creating walls and floor
createWallsAndFloor();
setupDebugDraw();
_nextCrateIn = 0;
addEventListener(Event.ENTER_FRAME, newFrameEvent);
// Put the restart button on the top most index
// so it isn't covered by the falling crates
addChild(restartButton);
// Event listener in order to restart
// simulation when the restart button is pressed
restartButton.addEventListener(MouseEvent.CLICK, onRestartButtonClick)
}
private function onRestartButtonClick(e: MouseEvent): void {
// Remember that the world counts as one body so you
// want to remove bodies until there is only one body left
while (_world.GetBodyCount() > 1) {
_world.DestroyBody(_world.GetBodyList());
}
// recreate the walls again
createWallsAndFloor();
// set to default value
_nextCrateIn = 0;
}
private function setupDebugDraw():void
{
var spriteToDrawOn:Sprite = new Sprite();
addChild(spriteToDrawOn);
var artistForHire:b2DebugDraw = new b2DebugDraw();
artistForHire.m_sprite = spriteToDrawOn;
artistForHire.m_drawScale = RATIO;
artistForHire.SetFlags(b2DebugDraw.e_shapeBit);
artistForHire.m_lineThickness = 2.0;
artistForHire.m_fillAlpha = 0.6;
_world.SetDebugDraw(artistForHire);
}
private function newFrameEvent(e:Event):void
{
_world.Step( 1.0 / 30, 10);
// Every few frames, until a certain numer of crates have been added
if (_nextCrateIn-- <= 0 && _world.m_bodyCount < 80) {
// add a random create to the world
addARandomCrate();
_nextCrateIn = 1;
}
//trace("Falling crate is at", _fallingCrate.GetPosition().x, ",", _fallingCrate.GetPosition().y);
}
private function addARandomCrate():void
{
// Add a falling block to the world.
var fallingCrateDef:b2PolygonDef = new b2PolygonDef();
fallingCrateDef.SetAsBox(randomInt(5, 40) / RATIO, randomInt(5, 40) / RATIO);
fallingCrateDef.friction = 0.8;
fallingCrateDef.restitution = 0.3;
fallingCrateDef.density = 0.7;
// Set it to, 250, -30
var fallingBodyDef:b2BodyDef = new b2BodyDef();
fallingBodyDef.position.Set(randomInt(15, 530) / RATIO, randomInt(-100, -10) / RATIO);
fallingBodyDef.angle = randomInt(0,360) * Math.PI / 180;
var fallingCrate:b2Body = _world.CreateBody(fallingBodyDef);
fallingCrate.CreateShape(fallingCrateDef);
fallingCrate.SetMassFromShapes();
}
// Return a random number between lowVal and highVal, INCLUSIVE
private function randomInt(lowVal:int, highVal:int): int
{
if (lowVal <= highVal) {
return (lowVal + Math.floor(Math.random() * (highVal - lowVal + 1)));
}else
{
throw(new Error("OMG! Wrong values passed to randomInt!!"));
}
}
private function createWallsAndFloor():void
{
// Create the shape (polygon) definition
var bigLongShapeDef: b2PolygonDef = new b2PolygonDef();
bigLongShapeDef.vertexCount = 4;
b2Vec2(bigLongShapeDef.vertices[0]).Set(0 / RATIO, 0 / RATIO);
b2Vec2(bigLongShapeDef.vertices[1]).Set(550 / RATIO, 0 / RATIO);
b2Vec2(bigLongShapeDef.vertices[2]).Set(550 / RATIO, 10 / RATIO);
b2Vec2(bigLongShapeDef.vertices[3]).Set(0 / RATIO, 10 / RATIO);
bigLongShapeDef.friction = 0.5;
bigLongShapeDef.restitution = 0.3;
bigLongShapeDef.density = 0.0;
// Create the body definition
var floorBodyDef:b2BodyDef = new b2BodyDef();
floorBodyDef.position.Set(0 / RATIO, 390 / RATIO);
// Create the body
var floorBody:b2Body = _world.CreateBody(floorBodyDef);
// Create the shape
floorBody.CreateShape(bigLongShapeDef);
floorBody.SetMassFromShapes();
var tallSkinnyShape:b2PolygonDef = new b2PolygonDef();
tallSkinnyShape.SetAsBox( 5 / RATIO, 195 / RATIO);
tallSkinnyShape.friction = .5;
tallSkinnyShape.restitution = 0.3;
tallSkinnyShape.density = 0.0;
var wallBodyDef:b2BodyDef = new b2BodyDef();
wallBodyDef.position.Set(5 / RATIO, 195 / RATIO);
var leftWall:b2Body = _world.CreateBody(wallBodyDef);
leftWall.CreateShape(tallSkinnyShape);
leftWall.SetMassFromShapes();
wallBodyDef.position.Set(545 / RATIO, 195 / RATIO);
var rightWall:b2Body = _world.CreateBody(wallBodyDef);
rightWall.CreateShape(tallSkinnyShape);
rightWall.SetMassFromShapes();
//trace("My world now has", _world.m_bodyCount, "bodies in it! Wow!");
}
private function setupWorld():void
{
// 1. Set up the size of the universe
var universeSize:b2AABB = new b2AABB();
universeSize.lowerBound.Set( -3000 / RATIO, -3000 / RATIO);
universeSize.upperBound.Set( 3000 / RATIO, 3000 / RATIO);
// 2. Define gravity
var gravity: b2Vec2 = new b2Vec2(0, 9.8);
// 3. Ignore sleeping objects
var ignoreSleeping:Boolean = true;
_world = new b2World(universeSize, gravity, ignoreSleeping);
//trace("My world has", _world.GetBodyCount(), "bodies in it!");
}
}
}
You can get the Zip file containing all the project resources (source code, FLA, FlashDevelop project file) by clicking the link below.
Box2dChapter1_EdgarMirandadotnet.zip
My next goal is to finish up chapter 2, which is a bit longer then chapter 1 (50 lessons instead of 22). I’m currently on chapter 2 lesson 4, and I’m aiming to do around 5-10 lessons a day. I find it it’s easier to learn if I do about an hour or so of lessons each day instead of doing the whole batch in a day or two, there is also so much I can take of just watching video tutorials all day
.
Look out for my final result for chapter 2!