This is our next game development article. We continue a series of articles on game development in HTML5 using canvas. Today I will show how to apply some physics to your project (with using Box2D). Box2D is popular open source engine that simulates 2D physics for applications. 2D Physics Engine is a hot topic in game development. With the help of physics engine, we can easily create a playable game by just defining an environment and a simple rule.
Here you can read our previous lesson: Developing Your First HTML5 Game – Lesson 7.
Here are our demo and downloadable package:
Ok, download the example files and lets start coding !
Step 0. Pre-phase
First, you have to download Box2D library here.
Step 1. HTML
Today we have to link all necessary library files to our project.
index.html
04 | <meta charset="utf-8" /> |
05 | <title>HTML5 Game Development - Lesson 8 | Script Tutorials</title> |
06 | <link href="css/main.css" rel="stylesheet" type="text/css" /> |
07 | <script src="js/protoclass.js"></script> |
08 | <script src="js/jquery-1.6.min.js"></script> |
10 | <script src='js/box2d/common/b2Settings.js'></script> |
11 | <script src='js/box2d/common/math/b2Vec2.js'></script> |
12 | <script src='js/box2d/common/math/b2Mat22.js'></script> |
13 | <script src='js/box2d/common/math/b2Math.js'></script> |
14 | <script src='js/box2d/collision/b2AABB.js'></script> |
15 | <script src='js/box2d/collision/b2Bound.js'></script> |
16 | <script src='js/box2d/collision/b2BoundValues.js'></script> |
17 | <script src='js/box2d/collision/b2Pair.js'></script> |
18 | <script src='js/box2d/collision/b2PairCallback.js'></script> |
19 | <script src='js/box2d/collision/b2BufferedPair.js'></script> |
20 | <script src='js/box2d/collision/b2PairManager.js'></script> |
21 | <script src='js/box2d/collision/b2BroadPhase.js'></script> |
22 | <script src='js/box2d/collision/b2Collision.js'></script> |
23 | <script src='js/box2d/collision/Features.js'></script> |
24 | <script src='js/box2d/collision/b2ContactID.js'></script> |
25 | <script src='js/box2d/collision/b2ContactPoint.js'></script> |
26 | <script src='js/box2d/collision/b2Distance.js'></script> |
27 | <script src='js/box2d/collision/b2Manifold.js'></script> |
28 | <script src='js/box2d/collision/b2OBB.js'></script> |
29 | <script src='js/box2d/collision/b2Proxy.js'></script> |
30 | <script src='js/box2d/collision/ClipVertex.js'></script> |
31 | <script src='js/box2d/collision/shapes/b2Shape.js'></script> |
32 | <script src='js/box2d/collision/shapes/b2ShapeDef.js'></script> |
33 | <script src='js/box2d/collision/shapes/b2BoxDef.js'></script> |
34 | <script src='js/box2d/collision/shapes/b2CircleDef.js'></script> |
35 | <script src='js/box2d/collision/shapes/b2CircleShape.js'></script> |
36 | <script src='js/box2d/collision/shapes/b2MassData.js'></script> |
37 | <script src='js/box2d/collision/shapes/b2PolyDef.js'></script> |
38 | <script src='js/box2d/collision/shapes/b2PolyShape.js'></script> |
39 | <script src='js/box2d/dynamics/b2Body.js'></script> |
40 | <script src='js/box2d/dynamics/b2BodyDef.js'></script> |
41 | <script src='js/box2d/dynamics/b2CollisionFilter.js'></script> |
42 | <script src='js/box2d/dynamics/b2Island.js'></script> |
43 | <script src='js/box2d/dynamics/b2TimeStep.js'></script> |
44 | <script src='js/box2d/dynamics/contacts/b2ContactNode.js'></script> |
45 | <script src='js/box2d/dynamics/contacts/b2Contact.js'></script> |
46 | <script src='js/box2d/dynamics/contacts/b2ContactConstraint.js'></script> |
47 | <script src='js/box2d/dynamics/contacts/b2ContactConstraintPoint.js'></script> |
48 | <script src='js/box2d/dynamics/contacts/b2ContactRegister.js'></script> |
49 | <script src='js/box2d/dynamics/contacts/b2ContactSolver.js'></script> |
50 | <script src='js/box2d/dynamics/contacts/b2CircleContact.js'></script> |
51 | <script src='js/box2d/dynamics/contacts/b2Conservative.js'></script> |
52 | <script src='js/box2d/dynamics/contacts/b2NullContact.js'></script> |
53 | <script src='js/box2d/dynamics/contacts/b2PolyAndCircleContact.js'></script> |
54 | <script src='js/box2d/dynamics/contacts/b2PolyContact.js'></script> |
55 | <script src='js/box2d/dynamics/b2ContactManager.js'></script> |
56 | <script src='js/box2d/dynamics/b2World.js'></script> |
57 | <script src='js/box2d/dynamics/b2WorldListener.js'></script> |
58 | <script src='js/box2d/dynamics/joints/b2JointNode.js'></script> |
59 | <script src='js/box2d/dynamics/joints/b2Joint.js'></script> |
60 | <script src='js/box2d/dynamics/joints/b2JointDef.js'></script> |
61 | <script src='js/box2d/dynamics/joints/b2DistanceJoint.js'></script> |
62 | <script src='js/box2d/dynamics/joints/b2DistanceJointDef.js'></script> |
63 | <script src='js/box2d/dynamics/joints/b2Jacobian.js'></script> |
64 | <script src='js/box2d/dynamics/joints/b2GearJoint.js'></script> |
65 | <script src='js/box2d/dynamics/joints/b2GearJointDef.js'></script> |
66 | <script src='js/box2d/dynamics/joints/b2MouseJoint.js'></script> |
67 | <script src='js/box2d/dynamics/joints/b2MouseJointDef.js'></script> |
68 | <script src='js/box2d/dynamics/joints/b2PrismaticJoint.js'></script> |
69 | <script src='js/box2d/dynamics/joints/b2PrismaticJointDef.js'></script> |
70 | <script src='js/box2d/dynamics/joints/b2PulleyJoint.js'></script> |
71 | <script src='js/box2d/dynamics/joints/b2PulleyJointDef.js'></script> |
72 | <script src='js/box2d/dynamics/joints/b2RevoluteJoint.js'></script> |
73 | <script src='js/box2d/dynamics/joints/b2RevoluteJointDef.js'></script> |
74 | <script src="js/script.js"></script> |
78 | <h2>HTML5 Game Development - Lesson 8</h2> |
81 | <div class="container"> |
82 | <canvas id="game" width="800" height="600"></canvas> |
Step 2. CSS
css/main.css
I won’t publish CSS styles today, there are only a few page layout styles. You can find this file in our package.
Step 3. JS
js/jquery-1.6.min.js and js/protoclass.js
Both libraries available in our package. Next file is most important – it is our main code of our game:
js/script.js
007 | function getRand(x, y) { |
008 | return Math.floor(Math.random()*y)+x; |
012 | world = createWorld(); |
014 | canvas = document.getElementById('game'); |
015 | ctx = canvas.getContext('2d'); |
016 | canvasWidth = parseInt(canvas.width); |
017 | canvasHeight = parseInt(canvas.height); |
019 | createGround(canvasWidth / 2, canvasHeight - iBorder, canvasWidth / 2, iBorder, 0); |
020 | createGround(iBorder, canvasHeight / 2, iBorder, canvasHeight / 2, 0); |
021 | createGround(canvasWidth - iBorder, canvasHeight / 2, iBorder, canvasHeight / 2, 0); |
028 | function addObjects() { |
029 | var iVar = getRand(1, 2); |
031 | var x = getRand(100, 600); |
033 | var r = getRand(10, 40); |
034 | createCircleAt(x, y, r); |
035 | } else if (iVar == 2) { |
036 | var x = getRand(100, 600); |
038 | var w = getRand(5, 40); |
039 | var h = getRand(5, 40); |
040 | createBoxAt(x, y, w, h); |
043 | setTimeout(addObjects, 500); |
047 | world.Step(1.0 / 60, 1); |
048 | ctx.clearRect(0, 0, canvasWidth, canvasHeight); |
050 | drawWorld(world, ctx); |
052 | setTimeout(frame, 10); |
055 | function createWorld() { |
057 | var worldAABB = new b2AABB(); |
058 | worldAABB.minVertex.Set(-1000, -1000); |
059 | worldAABB.maxVertex.Set(1000, 1000); |
061 | var gravity = new b2Vec2(0, 200); |
065 | return new b2World(worldAABB, gravity, doSleep); |
068 | function createGround(x, y, width, height, rotation) { |
070 | var groundSd = new b2BoxDef(); |
071 | groundSd.extents.Set(width, height); |
072 | groundSd.restitution = 0.4; |
073 | var groundBd = new b2BodyDef(); |
074 | groundBd.AddShape(groundSd); |
075 | groundBd.position.Set(x, y); |
076 | groundBd.rotation = rotation * Math.PI / 180; |
077 | return world.CreateBody(groundBd); |
080 | function createBoxAt(x, y, w, h) { |
081 | var boxSd = new b2BoxDef(); |
083 | boxSd.friction = 1.0; |
084 | boxSd.restitution = .5; |
085 | boxSd.extents.Set(w, h); |
087 | var boxBd = new b2BodyDef(); |
088 | boxBd.AddShape(boxSd); |
089 | boxBd.position.Set(x,y); |
090 | return world.CreateBody(boxBd); |
093 | function createCircleAt(x, y, r) { |
094 | var boxSd = new b2CircleDef(); |
096 | boxSd.friction = 1.0; |
097 | boxSd.restitution = .5; |
100 | var boxBd = new b2BodyDef(); |
101 | boxBd.AddShape(boxSd); |
102 | boxBd.position.Set(x,y); |
103 | return world.CreateBody(boxBd); |
106 | function drawWorld(world, context) { |
107 | for (var b = world.m_bodyList; b != null; b = b.m_next) { |
108 | for (var s = b.GetShapeList(); s != null; s = s.GetNext()) { |
109 | drawShape(s, context); |
114 | function drawShape(shape, context) { |
115 | context.strokeStyle = '#0000ff'; |
116 | context.fillStyle = 'rgba(100, 100, 255, 0.8)'; |
118 | switch (shape.m_type) { |
119 | case b2Shape.e_circleShape: |
121 | var pos = circle.m_position; |
122 | var r = circle.m_radius; |
125 | var dtheta = 2.0 * Math.PI / segments; |
126 | context.moveTo(pos.x + r, pos.y); |
127 | for (var i = 0; i < segments; i++) { |
128 | var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta)); |
129 | var v = b2Math.AddVV(pos, d); |
130 | context.lineTo(v.x, v.y); |
133 | context.lineTo(pos.x + r, pos.y); |
134 | context.moveTo(pos.x, pos.y); |
135 | var ax = circle.m_R.col1; |
136 | var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y); |
137 | context.lineTo(pos2.x, pos2.y); |
139 | case b2Shape.e_polyShape: |
141 | var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0])); |
142 | context.moveTo(tV.x, tV.y); |
143 | for (var i = 0; i < poly.m_vertexCount; i++) { |
144 | var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i])); |
145 | context.lineTo(v.x, v.y); |
147 | context.lineTo(tV.x, tV.y); |
I have added my comments everywhere, hope that all this code is pretty understandable.
Conclusion
And that’s it! You have just completed our new lesson with HTML5 and Box2D. Congratulations!