Skip to content

Instantly share code, notes, and snippets.

@Ripley6811
Created August 6, 2013 07:04
Show Gist options
  • Save Ripley6811/6162691 to your computer and use it in GitHub Desktop.
Save Ripley6811/6162691 to your computer and use it in GitHub Desktop.
A CodePen by Jay W Johnson. Boy in the rain - CreateJS and Box2DWeb example. Raindrops are small circular dynamic bodies. Umbrella is a kinematic body (ignores gravity).
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="https://dl.dropboxusercontent.com/u/49722688/packages/Box2dWeb-2.1.a.3.min.js"></script>
</body>
</html>
"use strict";
document.body.style.margin = "0px";
document.body.style.backgroundColor = "#000";
var canvas = document.getElementById("canvas");
canvas.style.background = "rgb(40,50,80)";
canvas.width = window.innerWidth || document.body.clientWidth;
canvas.height = 500;
var ctx = canvas.getContext("2d");
function init(){
// Set the function to run each frame and FPS
createjs.Ticker.addEventListener("tick", tick);
createjs.Ticker.setFPS(60);
createjs.Ticker.useRAF = false;
}
// Draw to buffer
var buffer = document.createElement('canvas');
buffer.width = canvas.width;
buffer.height = canvas.height;
buffer.style.visibility='hidden';
var bufferCtx = buffer.getContext('2d');
// Box2D scaling (affects max velocity of particles)
var SCALE = 30;
var Vec = Box2D.Common.Math.b2Vec2;
var stage = new createjs.Stage("canvas");
var world = new Box2D.Dynamics.b2World(
new Vec(0, 15) // Gravity vector in physics world
);
// Array for Raindrop objects
var rain = [];
var MAX_DROPS = 800;
// Class: Raindrop
function Raindrop() {
// Set the CreateJS update method
// Add Box2D physics body
this.body = (function(){
var bodyDef = new Box2D.Dynamics.b2BodyDef();
bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody;
bodyDef.position.Set( Math.random()*canvas.width*1.1 / SCALE, 0); // World coordinates
var body = world.CreateBody(bodyDef);
body.CreateFixture(Raindrop.prototype.fixDef);
return body;
}());
}; // Raindrop class
Raindrop.prototype.onTick = function() {
// Slow horizontal velocity to create dripping effect
var v = this.body.GetLinearVelocity();
if (v.y < 300/SCALE || v.x > 0){
this.body.SetLinearVelocity(new Vec(v.x*0.9,v.y));
}
// UPDATE IMAGE POSITION TO MATCH BOX2D BODY
this.x = this.body.GetPosition().x * SCALE;
this.y = this.body.GetPosition().y * SCALE;
return this.y;
}
Raindrop.prototype.fixDef = (function() {
console.log("Raindrop prototype fixdef");
var fixDef = new Box2D.Dynamics.b2FixtureDef();
fixDef.shape = new Box2D.Collision.Shapes.b2CircleShape(1/SCALE);
fixDef.shape.SetLocalPosition(new Vec(0, 0));
fixDef.density = 0.1;
fixDef.friction = 0.0;
fixDef.restitution = 0.0;
fixDef.filter.categoryBits = 0x0001;
fixDef.filter.maskBits = 0x0002;
return fixDef;
}());
// Class: Boy
function Boy() {
// Createjs Shape
var view = new createjs.Bitmap("https://dl.dropboxusercontent.com/u/49722688/images/boy_umbrella.png");
view.set({
// Set the "center" of this object
regX : 0 / 2,
regY : 0 / 2,
// Set the CreateJS update method
onTick : function() {
// Move boy after walking off screen
var v = this.body.GetPosition();
if (v.x < -300/SCALE){
this.body.SetPosition(new Vec(canvas.width/SCALE, v.y));
}
// UPDATE IMAGE POSITION AND ROTATION TO MATCH BOX2D BODY
this.x = this.body.GetPosition().x * SCALE;
this.y = this.body.GetPosition().y * SCALE;
},
// Add Box2D physics body
body : (function(){
var bodyDef = new Box2D.Dynamics.b2BodyDef();
bodyDef.type = Box2D.Dynamics.b2Body.b2_kinematicBody;
bodyDef.fixedRotation = true; // Prevent any rotation
bodyDef.position.Set( canvas.width/2/SCALE, 240/SCALE); // World coordinates
var body = world.CreateBody(bodyDef);
var fixDef = new Box2D.Dynamics.b2FixtureDef();
fixDef.shape = new Box2D.Collision.Shapes.b2PolygonShape;
var vertices = [
new Vec(88/SCALE, 36/SCALE),
new Vec(114/SCALE, 35/SCALE),
new Vec(140/SCALE, 38/SCALE),
new Vec(160/SCALE, 44/SCALE),
new Vec(183/SCALE, 56/SCALE),
new Vec(202/SCALE, 70/SCALE),
new Vec(213/SCALE, 81/SCALE),
new Vec(229/SCALE, 103/SCALE),
new Vec(238/SCALE, 123/SCALE),
new Vec(246/SCALE, 148/SCALE),
new Vec(252/SCALE, 170/SCALE),
new Vec(253/SCALE, 191/SCALE),
/* new Vec(107/SCALE, 254/SCALE),
new Vec(73/SCALE, 213/SCALE),
new Vec(77/SCALE, 203/SCALE),
new Vec(84/SCALE, 202/SCALE),
new Vec(123/SCALE, 161/SCALE),
new Vec(103/SCALE, 144/SCALE),
new Vec(100/SCALE, 126/SCALE),
new Vec(107/SCALE, 120/SCALE),
new Vec(104/SCALE, 106/SCALE),
new Vec(110/SCALE, 96/SCALE),
new Vec(126/SCALE, 89/SCALE),*/
];
fixDef.shape.SetAsArray(vertices, 12);
fixDef.density = 1.0;
fixDef.friction = 0.3;
fixDef.restitution = 0.0;
fixDef.filter.categoryBits = 0x0002;
fixDef.filter.maskBits = 0x0001;
body.CreateFixture(fixDef);
return body;
}())
});
return view;
}; // Boy class
var boy = new Boy();
stage.addChild(boy);
var yOffset = 0;
console.log(boy.body.GetPosition());
function tick(){
// BOX2D WORLD: PHYSICS STEP FORWARD THEN CLEAR FORCES
world.Step(
1 / 60 //frame-rate
, 4 //velocity iterations
, 4 //position iterations
);
world.ClearForces();
var v = boy.body.GetPosition();
boy.body.SetPosition(new Vec(v.x-1/120,v.y+Math.cos(yOffset)/200));
yOffset += 0.06;
// Add rain drops
for (var i = 0; i < 16 && rain.length < MAX_DROPS; i++) {
var drop = new Raindrop();
var r = Math.random();
drop.body.SetLinearVelocity(new Vec(-100/SCALE-r*2,400/SCALE-r));
//stage.addChild(drop);
rain.push(drop);
}
// Remove rain drops
for (var i = rain.length-1; i >= 0; i--){
if (rain[i].y > canvas.height){
//wait
rain[i].body.SetLinearVelocity(new Vec(-100/SCALE,400/SCALE));
rain[i].body.SetPosition(new Vec(Math.random()*canvas.width*1.1 / SCALE, 0));
//world.DestroyBody(rain[i].body);
//rain.splice(i,1);
//rain[i].body.SetPosition(canvas.width/2,canvas.height/2);
}
}
console.log(rain.length, "raindrops");
bufferCtx.strokeStyle = '#aaf';
for (var i = 0; i < rain.length; i++){
var r = rain[i];
bufferCtx.beginPath();
//fillRect and "flooring" force drawing to single pixel.
//Using fillRect instead of rect improved performance.
bufferCtx.moveTo(~~r.x, ~~r.y);
//r.onTick(); // Update position
if (r.y < r.onTick()){
bufferCtx.lineTo(~~r.x, ~~r.y);
bufferCtx.stroke();
}
}
stage.update();
ctx.drawImage(buffer, 0, 0);
bufferCtx.clearRect(0, 0, canvas.width, canvas.height);
}
// Run the animation
init();
canvas = {
position: absolute;
top: 0;
left: 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment