Complete HTML5 Totem destroyer engine using PhysicsJS
Talking about Totem Destroyer game, Game development, HTML5 and Javascript.
Back home and finally with a good internet connection, I am blogging again after the longest “no post” period in the story of the blog.
We are about to see a full Totem destroyer engine made using PhysicsJS, a new interesting javascript physics engine I reviewed in this post.
The engine has very nice features such as an intuitive way to create and skin bodies and a smart collision detection, but I’m finding it a bit unstable with stacked bodies, as you are about to see, because it feels a bit trembling.
Anyway, this is the totem destroyer prototype, featuring:
* Static (or “fixed”, as the engine calls them) and dynamic bodies
* Custom images applied to bodies
* Mouse interaction
* Collision detection
You should know how to play it: remove bricks by clicking on them and don’t let the totem hit the ground (anyway, make it fall to see what happens). Darker bricks cannot be removed.
As said, it looks a bit trembling, at least with 0.5.4 version. One idea would be making all bodies fixed until the first brick is removed, but I hope future versions will fix this issue without any workaround.
Here is the fully commented source code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PhysicsJS</title>
<script src="physicsjs-full.js"></script>
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<style>
body {
margin:0px;
background-color:black;
}
.gameover{
background-color:red;
}
</style>
<script>
$(document).ready(function(){
// world declaration
var world = Physics();
// creation of the renderer which will draw the world
var renderer = Physics.renderer("canvas",{
el: "canvasid", // canvas element id
width: 640, // canvas width
height: 480, // canvas height
meta: false // setting it to "true" will display FPS
});
// adding the renderer to the world
world.add(renderer);
// what happens at every iteration step? We render (show the world)
world.subscribe("step",function(){
world.render();
});
// this is the default gravity
var gravity = Physics.behavior("constant-acceleration");
// adding gravity to the world
world.add(gravity);
// bodies will react to forces such as gravity
world.add(Physics.behavior("body-impulse-response"));
// enabling collision detection among bodies
world.add(Physics.behavior("body-collision-detection"));
world.add(Physics.behavior("sweep-prune"));
// adding the ground
var ground = Physics.body("convex-polygon",{
x: 320,
y: 470,
fixed: true,
vertices: [
{x:0, y:0},
{x:0, y:20},
{x:640, y:20},
{x:640, y:0}
],
restitution:0.2,
cof:1
});
// assigning a custom attribute to the ground body
ground.objType="ground";
// image representing the ground body
ground.view = new Image();
ground.view.src = "ground.png";
world.add(ground);
// adding bricks and totem with a function
addBrick(380,440,[{x:0, y:0},{x:0, y:40},{x:40, y:40},{x:40, y:0}],"destroyable","brick");
addBrick(260,440,[{x:0, y:0},{x:0, y:40},{x:40, y:40},{x:40, y:0}],"destroyable","brick");
addBrick(320,400,[{x:0, y:0},{x:0, y:40},{x:160, y:40},{x:160, y:0}],"destroyable","brick4x1");
addBrick(320,360,[{x:0, y:0},{x:0, y:40},{x:80, y:40},{x:80, y:0}],"unbreakable","solid2x1");
addBrick(300,320,[{x:0, y:0},{x:0, y:40},{x:120, y:40},{x:120, y:0}],"destroyable","brick3x1");
addBrick(320,260,[{x:0, y:0},{x:0, y:80},{x:160, y:80},{x:160, y:0}],"unbreakable","solid4x2");
addBrick(320,190,[{x:0, y:0},{x:0, y:60},{x:40, y:60},{x:40, y:0}],"totem","totem");
// checking for collisions
world.subscribe("collisions:detected", function(data){
// looping through all collisions
for (var i=0; i < data.collisions.length; i++){
theCollision = data.collisions[i];
// check if the totem touched the ground
if (theCollision.bodyA.objType=="ground" && theCollision.bodyB.objType=="totem"){
$("#canvasid").addClass("gameover");
}
// same as before, did not use an "or" for a layout purpose
if (theCollision.bodyB.objType=="ground" && theCollision.bodyA.objType=="totem"){
$("#canvasid").addClass("gameover");
}
}
});
$("#canvasid").click(function(e){
// checking canvas coordinates for the mouse click
var offset = $(this).offset();
var px = e.pageX - offset.left;
var py = e.pageY - offset.top;
// this is the way physicsjs handles 2d vectors, similar at Box2D's b2Vec
var mousePos = Physics.vector();
mousePos.set(px,py);
// finding a body under mouse position
var body = world.findOne({
$at: mousePos
})
if(body && body.objType=="destroyable"){
// there is a body under mouse position and can be destroyed, let's remove it
world.removeBody(body);
}
})
// handling timestep
Physics.util.ticker.subscribe(function(time,dt){
world.step(time);
});
Physics.util.ticker.start();
// function to generate bricks
function addBrick(x,y,vertices,type,image){
var brick = Physics.body("convex-polygon",{
x:x,
y:y,
vertices:vertices,
restitution:0,
cof:1,
mass:0.5
});
brick.objType=type;
brick.view = new Image();
brick.view.src = image+".png";
world.add(brick);
}
})
</script>
</head>
<body>
<canvas id="canvasid" width="640" height="480"></canvas>
</body>
</html>
And of course you can download the entire project with all required files.
Nice to meet you again!
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.