Daniel Stokes

How to add 2D Physics to CreateJs

October 25th 2019 1:55pm
Updated: November 8th 2019 4:23pm

Web Dev Game Dev

Intro

Adding the Box2D physics library to your create js game can open up the possibilities for exciting gameplay. Using a physics system creates a consistent simulation experience and as a result players can more easily and intuitively predict movement and interactions.

We will be using box2Dweb. If you are interested in implementing this project in typescript see below for details on that. There is a package available online that includes types for box2dweb for quick and easy programming.

https://github.com/hecht-software/box2dweb

Steps

Once the box2dweb library has been included there are just a few steps you need to do.

  1. create a physics world
    Think of the physics world just like the createjs stage. The phyics world unlike the createjs stage doesn't work with pixel units and we must introduce a scaling variable to link the different scales. Also the y axis in box2d increases when you go upwards unlike createjs but this difference can be mitigated by using a positive gravity value.

  2. Create our physics objects
    createjs graphics
    createRigidBody
    createRigidbodyFixture

  3. Add physics objects to physics world

  4. Perform game update
    update() physics world
    update graphics to match physics object


Example Javascript Code


index.html

	<head>

<script>
var module = {}; 
</script>

<script src="https://cdn.jsdelivr.net/npm/box2dweb@2.1.0-b/box2d.min.js"></script>

<script src="https://code.createjs.com/1.0.0/createjs.min.js"></script>


</head>
<body onload="">
    <canvas id="demoCanvas" width="400" height="400"></canvas>
    <script src="main.js"></script>
</body>
	

main.js

	var Box2D = module.exports; 
var physicsScale = 30
var fps = 60;
let canvas = document.getElementById("demoCanvas");
	

let stage = new createjs.Stage(canvas);
stage.enableMouseOver(20);
createjs.Ticker.framerate = fps;

var scene = new createjs.Container();

stage.addChild(scene);

var graphic = new createjs.Shape();
graphic.graphics.beginFill("red").drawRect(0, 0, 32,32);
graphic.regX = 32 * 0.5;
graphic.regY = 32 * 0.5;		
graphic.x = 50;
graphic.y = 16;
scene.addChild(graphic);

var graphic2 = new createjs.Shape();
graphic2.graphics.beginFill("green").drawRect(0, 0, 400,50);
graphic2.regX = 400 * 0.5;
graphic2.regY = 50 * 0.5;		
graphic2.x = 100;
graphic2.y = 162;


scene.addChild(graphic2);

stage.update();

var gravity = new Box2D.Common.Math.b2Vec2(0,9);
var doSleep = false;
var physicsWorld = new Box2D.Dynamics.b2World( gravity, doSleep);


function createBodyDefinition(type, fixedRotation, linearDamping, x, y){
	let rbDefinition = new Box2D.Dynamics.b2BodyDef();
	rbDefinition.type = type;
	rbDefinition.fixedRotation = fixedRotation;
	rbDefinition.linearDamping = linearDamping;
	rbDefinition.position = new Box2D.Common.Math.b2Vec2(x / physicsScale, y / physicsScale)
	return rbDefinition;
}

function createPlatformFixtureDef(shape, friction, restitution, density, isSensor, userData){
	let pFDefinition = new Box2D.Dynamics.b2FixtureDef();
	pFDefinition.shape = shape;
	pFDefinition.friction = friction;
	pFDefinition.restitution = restitution;
	pFDefinition.density = density;
	pFDefinition.isSensor = isSensor;
	pFDefinition.userData = userData;
	return pFDefinition;
}

var rigidbody;

var rigidbodyDefinition = createBodyDefinition(Box2D.Dynamics.b2Body.b2_dynamicBody, false, 0 , graphic.x,graphic.y);

var platformFixtureDef = createPlatformFixtureDef(Box2D.Collision.Shapes.b2PolygonShape.AsBox( 16 / physicsScale, 16 / physicsScale), 1, 0 ,10, false, {'name':'box'});

//creates rigidbody in our physics world
rigidbody = physicsWorld.CreateBody(rigidbodyDefinition);

rigidbody.CreateFixture(platformFixtureDef);


var rbGround;

var rigidbodyDefinition2 = createBodyDefinition(Box2D.Dynamics.b2Body.b2_staticBody, false, 0 , graphic2.x,graphic2.y);

//creates rigidbody in our physics world
rbGround = physicsWorld.CreateBody(rigidbodyDefinition2);

var platformFixtureDef2 = createPlatformFixtureDef(Box2D.Collision.Shapes.b2PolygonShape.AsBox( 200 / physicsScale, 25 / physicsScale), 10, 0 ,10, false,  {'name':'ground'});

rbGround.CreateFixture(platformFixtureDef2);
rbGround.SetAngle( 0.5 );



function Update(){	
  
	//update physics world -- box2dweb does all the magic for us here
  if(physicsWorld != undefined){
    physicsWorld.Step(1/ fps , 10, 10);

    //update the graphic to match the physics body
    var position = rigidbody.GetPosition();
      graphic.rotation = rigidbody.GetAngle() * (180 / Math.PI)
    graphic.x = position.x * physicsScale ;
    graphic.y = position.y * physicsScale ;
		
		position = rbGround.GetPosition();
      graphic2.rotation = rbGround.GetAngle() * (180 / Math.PI)
    graphic2.x = position.x * physicsScale ;
    graphic2.y = position.y * physicsScale ;
  }
	
	stage.update();
}

createjs.Ticker.on("tick", Update);
	

If you are using typescript in your project then you can install a types definition for box2dweb

there used to be a types definition here: https://github.com/jbaldwin/box2dweb.d.ts but that looks to be removed so try out this: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/box2d instead.

If you make any projects with create js and or box2d please share them with me on twitter!

Comments