Membangun Game Pertama Anda dengan HTML5
Indonesian (Bahasa Indonesia) translation by ⚡ Rova Rindrata (you can also view the original English article)
HTML5 tumbuh lebih cepat daripada yang bisa dibayangkan siapa pun. Solusi hebat dan profesional sudah dikembangkan... bahkan di dunia game! Hari ini, Anda akan membuat game pertama Anda menggunakan Box2D dan tag canvas
HTML5.
Apa itu Box2D?
Box2D adalah mesin populer dan open source yang mensimulasikan fisika 2D untuk pembuatan game dan aplikasi. Terutama ditulis di C++, telah diubah ke banyak bahasa oleh kontributor komunitas.
Dengan metode dan objek yang sama, Anda memiliki kemampuan untuk membuat fisika permainan Anda dalam banyak bahasa, seperti Objective C (iPhone/iPad), Actionscript 3.0 (Web), HTML 5 (Web), dll.
Langkah 1 - Menyiapkan Proyek Anda
Untuk mulai mengembangkan demo Anda, unduh mesin Box2D untuk HTML5 di sini. Selanjutnya, buat file HTML baru dengan struktur berikut (salin direktori js dan lib dari proyek box2d-js ke folder permainan Anda).



Sekarang, Anda harus memasukkan file yang diperlukan untuk menjalankan box2D ke file HTML Anda:
1 |
|
2 |
<!--[if IE]><script src="lib/excanvas.js"></script><![endif]-->
|
3 |
<script src="lib/prototype-1.6.0.2.js"></script> |
4 |
<!-- box2djs -->
|
5 |
<script src='js/box2d/common/b2Settings.js'></script> |
6 |
<script src='js/box2d/common/math/b2Vec2.js'></script> |
7 |
<script src='js/box2d/common/math/b2Mat22.js'></script> |
8 |
<script src='js/box2d/common/math/b2Math.js'></script> |
9 |
<script src='js/box2d/collision/b2AABB.js'></script> |
10 |
<script src='js/box2d/collision/b2Bound.js'></script> |
11 |
<script src='js/box2d/collision/b2BoundValues.js'></script> |
12 |
<script src='js/box2d/collision/b2Pair.js'></script> |
13 |
<script src='js/box2d/collision/b2PairCallback.js'></script> |
14 |
<script src='js/box2d/collision/b2BufferedPair.js'></script> |
15 |
<script src='js/box2d/collision/b2PairManager.js'></script> |
16 |
<script src='js/box2d/collision/b2BroadPhase.js'></script> |
17 |
<script src='js/box2d/collision/b2Collision.js'></script> |
18 |
<script src='js/box2d/collision/Features.js'></script> |
19 |
<script src='js/box2d/collision/b2ContactID.js'></script> |
20 |
<script src='js/box2d/collision/b2ContactPoint.js'></script> |
21 |
<script src='js/box2d/collision/b2Distance.js'></script> |
22 |
<script src='js/box2d/collision/b2Manifold.js'></script> |
23 |
<script src='js/box2d/collision/b2OBB.js'></script> |
24 |
<script src='js/box2d/collision/b2Proxy.js'></script> |
25 |
<script src='js/box2d/collision/ClipVertex.js'></script> |
26 |
<script src='js/box2d/collision/shapes/b2Shape.js'></script> |
27 |
<script src='js/box2d/collision/shapes/b2ShapeDef.js'></script> |
28 |
<script src='js/box2d/collision/shapes/b2BoxDef.js'></script> |
29 |
<script src='js/box2d/collision/shapes/b2CircleDef.js'></script> |
30 |
<script src='js/box2d/collision/shapes/b2CircleShape.js'></script> |
31 |
<script src='js/box2d/collision/shapes/b2MassData.js'></script> |
32 |
<script src='js/box2d/collision/shapes/b2PolyDef.js'></script> |
33 |
<script src='js/box2d/collision/shapes/b2PolyShape.js'></script> |
34 |
<script src='js/box2d/dynamics/b2Body.js'></script> |
35 |
<script src='js/box2d/dynamics/b2BodyDef.js'></script> |
36 |
<script src='js/box2d/dynamics/b2CollisionFilter.js'></script> |
37 |
<script src='js/box2d/dynamics/b2Island.js'></script> |
38 |
<script src='js/box2d/dynamics/b2TimeStep.js'></script> |
39 |
<script src='js/box2d/dynamics/contacts/b2ContactNode.js'></script> |
40 |
<script src='js/box2d/dynamics/contacts/b2Contact.js'></script> |
41 |
<script src='js/box2d/dynamics/contacts/b2ContactConstraint.js'></script> |
42 |
<script src='js/box2d/dynamics/contacts/b2ContactConstraintPoint.js'></script> |
43 |
<script src='js/box2d/dynamics/contacts/b2ContactRegister.js'></script> |
44 |
<script src='js/box2d/dynamics/contacts/b2ContactSolver.js'></script> |
45 |
<script src='js/box2d/dynamics/contacts/b2CircleContact.js'></script> |
46 |
<script src='js/box2d/dynamics/contacts/b2Conservative.js'></script> |
47 |
<script src='js/box2d/dynamics/contacts/b2NullContact.js'></script> |
48 |
<script src='js/box2d/dynamics/contacts/b2PolyAndCircleContact.js'></script> |
49 |
<script src='js/box2d/dynamics/contacts/b2PolyContact.js'></script> |
50 |
<script src='js/box2d/dynamics/b2ContactManager.js'></script> |
51 |
<script src='js/box2d/dynamics/b2World.js'></script> |
52 |
<script src='js/box2d/dynamics/b2WorldListener.js'></script> |
53 |
<script src='js/box2d/dynamics/joints/b2JointNode.js'></script> |
54 |
<script src='js/box2d/dynamics/joints/b2Joint.js'></script> |
55 |
<script src='js/box2d/dynamics/joints/b2JointDef.js'></script> |
56 |
<script src='js/box2d/dynamics/joints/b2DistanceJoint.js'></script> |
57 |
<script src='js/box2d/dynamics/joints/b2DistanceJointDef.js'></script> |
58 |
<script src='js/box2d/dynamics/joints/b2Jacobian.js'></script> |
59 |
<script src='js/box2d/dynamics/joints/b2GearJoint.js'></script> |
60 |
<script src='js/box2d/dynamics/joints/b2GearJointDef.js'></script> |
61 |
<script src='js/box2d/dynamics/joints/b2MouseJoint.js'></script> |
62 |
<script src='js/box2d/dynamics/joints/b2MouseJointDef.js'></script> |
63 |
<script src='js/box2d/dynamics/joints/b2PrismaticJoint.js'></script> |
64 |
<script src='js/box2d/dynamics/joints/b2PrismaticJointDef.js'></script> |
65 |
<script src='js/box2d/dynamics/joints/b2PulleyJoint.js'></script> |
66 |
<script src='js/box2d/dynamics/joints/b2PulleyJointDef.js'></script> |
67 |
<script src='js/box2d/dynamics/joints/b2RevoluteJoint.js'></script> |
68 |
<script src='js/box2d/dynamics/joints/b2RevoluteJointDef.js'></script> |
Ya, itu sejumlah besar permintaan HTTP!
Perlu diketahui bahwa, untuk penerapannya, sangat disarankan agar Anda menggabungkan semua sumber ini ke dalam satu file
script
.
Selanjutnya, buat dua skrip lagi di dalam folder /js/
, yang disebut "box2dutils.js"
dan "game.js"
.
- box2dutils.js - ini adalah copy dan paste dari beberapa demo yang disertakan dengan
box2dlib
, dan penting untuk fungsi menggambar (saya juga akan menjelaskan beberapa bagian penting di sini). - game.js - permainannya itu sendiri; di sinilah kita menciptakan platform, pemain, menerapkan interaksi keyboard, dll.
Salin dan tempel kode berikut ke box2dutils.js
. Jangan khawatir! Saya akan menjelaskannya sedikit demi sedikit!
1 |
|
2 |
|
3 |
function drawWorld(world, context) { |
4 |
for (var j = world.m_jointList; j; j = j.m_next) { |
5 |
drawJoint(j, context); |
6 |
}
|
7 |
for (var b = world.m_bodyList; b; b = b.m_next) { |
8 |
for (var s = b.GetShapeList(); s != null; s = s.GetNext()) { |
9 |
drawShape(s, context); |
10 |
}
|
11 |
}
|
12 |
}
|
13 |
function drawJoint(joint, context) { |
14 |
var b1 = joint.m_body1; |
15 |
var b2 = joint.m_body2; |
16 |
var x1 = b1.m_position; |
17 |
var x2 = b2.m_position; |
18 |
var p1 = joint.GetAnchor1(); |
19 |
var p2 = joint.GetAnchor2(); |
20 |
context.strokeStyle = '#00eeee'; |
21 |
context.beginPath(); |
22 |
switch (joint.m_type) { |
23 |
case b2Joint.e_distanceJoint: |
24 |
context.moveTo(p1.x, p1.y); |
25 |
context.lineTo(p2.x, p2.y); |
26 |
break; |
27 |
|
28 |
case b2Joint.e_pulleyJoint: |
29 |
// TODO
|
30 |
break; |
31 |
|
32 |
default: |
33 |
if (b1 == world.m_groundBody) { |
34 |
context.moveTo(p1.x, p1.y); |
35 |
context.lineTo(x2.x, x2.y); |
36 |
}
|
37 |
else if (b2 == world.m_groundBody) { |
38 |
context.moveTo(p1.x, p1.y); |
39 |
context.lineTo(x1.x, x1.y); |
40 |
}
|
41 |
else { |
42 |
context.moveTo(x1.x, x1.y); |
43 |
context.lineTo(p1.x, p1.y); |
44 |
context.lineTo(x2.x, x2.y); |
45 |
context.lineTo(p2.x, p2.y); |
46 |
}
|
47 |
break; |
48 |
}
|
49 |
context.stroke(); |
50 |
}
|
51 |
function drawShape(shape, context) { |
52 |
context.strokeStyle = '#000000'; |
53 |
context.beginPath(); |
54 |
switch (shape.m_type) { |
55 |
case b2Shape.e_circleShape: |
56 |
{
|
57 |
var circle = shape; |
58 |
var pos = circle.m_position; |
59 |
var r = circle.m_radius; |
60 |
var segments = 16.0; |
61 |
var theta = 0.0; |
62 |
var dtheta = 2.0 * Math.PI / segments; |
63 |
// draw circle
|
64 |
context.moveTo(pos.x + r, pos.y); |
65 |
for (var i = 0; i < segments; i++) { |
66 |
var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta)); |
67 |
var v = b2Math.AddVV(pos, d); |
68 |
context.lineTo(v.x, v.y); |
69 |
theta += dtheta; |
70 |
}
|
71 |
context.lineTo(pos.x + r, pos.y); |
72 |
|
73 |
// draw radius
|
74 |
context.moveTo(pos.x, pos.y); |
75 |
var ax = circle.m_R.col1; |
76 |
var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y); |
77 |
context.lineTo(pos2.x, pos2.y); |
78 |
}
|
79 |
break; |
80 |
case b2Shape.e_polyShape: |
81 |
{
|
82 |
var poly = shape; |
83 |
var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0])); |
84 |
context.moveTo(tV.x, tV.y); |
85 |
for (var i = 0; i < poly.m_vertexCount; i++) { |
86 |
var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i])); |
87 |
context.lineTo(v.x, v.y); |
88 |
}
|
89 |
context.lineTo(tV.x, tV.y); |
90 |
}
|
91 |
break; |
92 |
}
|
93 |
context.stroke(); |
94 |
}
|
95 |
|
96 |
|
97 |
function createWorld() { |
98 |
var worldAABB = new b2AABB(); |
99 |
worldAABB.minVertex.Set(-1000, -1000); |
100 |
worldAABB.maxVertex.Set(1000, 1000); |
101 |
var gravity = new b2Vec2(0, 300); |
102 |
var doSleep = true; |
103 |
var world = new b2World(worldAABB, gravity, doSleep); |
104 |
return world; |
105 |
}
|
106 |
|
107 |
function createGround(world) { |
108 |
var groundSd = new b2BoxDef(); |
109 |
groundSd.extents.Set(1000, 50); |
110 |
groundSd.restitution = 0.2; |
111 |
var groundBd = new b2BodyDef(); |
112 |
groundBd.AddShape(groundSd); |
113 |
groundBd.position.Set(-500, 340); |
114 |
return world.CreateBody(groundBd) |
115 |
}
|
116 |
|
117 |
function createBall(world, x, y) { |
118 |
var ballSd = new b2CircleDef(); |
119 |
ballSd.density = 1.0; |
120 |
ballSd.radius = 20; |
121 |
ballSd.restitution = 1.0; |
122 |
ballSd.friction = 0; |
123 |
var ballBd = new b2BodyDef(); |
124 |
ballBd.AddShape(ballSd); |
125 |
ballBd.position.Set(x,y); |
126 |
return world.CreateBody(ballBd); |
127 |
}
|
128 |
|
129 |
function createBox(world, x, y, width, height, fixed, userData) { |
130 |
if (typeof(fixed) == 'undefined') fixed = true; |
131 |
var boxSd = new b2BoxDef(); |
132 |
if (!fixed) boxSd.density = 1.0; |
133 |
|
134 |
boxSd.userData = userData; |
135 |
|
136 |
boxSd.extents.Set(width, height); |
137 |
var boxBd = new b2BodyDef(); |
138 |
boxBd.AddShape(boxSd); |
139 |
boxBd.position.Set(x,y); |
140 |
return world.CreateBody(boxBd) |
141 |
}
|
Langkah 2 - Mengembangkan Game
Buka file index.html
yang telah Anda buat sebelumnya, dan tambahkan elemen canvas
(600x400) di dalam elemen body
. Di sinilah kita akan bekerja dengan API menggambar HTML5:
1 |
|
2 |
<canvas id="game" width='600' height='400'></canvas> |
Juga, saat Anda berada di sini, referensikan game.js
dan box2dutils.js
.
1 |
|
2 |
<script src='js/box2dutils.js'></script> |
3 |
<script src='js/game.js'></script> |
Itu akan melakukannya untuk HTML! Mari kerjakan JavaScript yang menyenangkan sekarang juga!
Buka game.js
, dan masukkan kode di bawah ini:
1 |
|
2 |
// some variables that we gonna use in this demo
|
3 |
var initId = 0; |
4 |
var player = function(){ |
5 |
this.object = null; |
6 |
this.canJump = false; |
7 |
};
|
8 |
var world; |
9 |
var ctx; |
10 |
var canvasWidth; |
11 |
var canvasHeight; |
12 |
var keys = []; |
13 |
|
14 |
// HTML5 onLoad event
|
15 |
Event.observe(window, 'load', function() { |
16 |
world = createWorld(); // box2DWorld |
17 |
ctx = $('game').getContext('2d'); // 2 |
18 |
var canvasElm = $('game'); |
19 |
canvasWidth = parseInt(canvasElm.width); |
20 |
canvasHeight = parseInt(canvasElm.height); |
21 |
initGame(); // 3 |
22 |
step(); // 4 |
23 |
|
24 |
// 5
|
25 |
window.addEventListener('keydown',handleKeyDown,true); |
26 |
window.addEventListener('keyup',handleKeyUp,true); |
27 |
});
|
Box2DWorld - itulah mengapa kita ada di sini
Oke, mari kita cari tahu apa isi kode ini!
Box2DWorld adalah salah satu kelas yang tersedia, melalui inti box2d. Fungsinya sederhana: menggabungkan semuanya menjadi satu kelas. Di box2DWorld, Anda memiliki definisi tubuh dan manajer benturan dari permainan atau aplikasi Anda.
Jaga file game.js
dan box2dutils.js
terbuka, dan cari fungsi createWorld()
di dalam box2dutils.js
.
1 |
|
2 |
function createWorld() { |
3 |
// here we create our world settings for collisions
|
4 |
var worldAABB = new b2AABB(); |
5 |
worldAABB.minVertex.Set(-1000, -1000); |
6 |
worldAABB.maxVertex.Set(1000, 1000); |
7 |
// set gravity vector
|
8 |
var gravity = new b2Vec2(0, 300); |
9 |
var doSleep = true; |
10 |
// init our world and return its value
|
11 |
var world = new b2World(worldAABB, gravity, doSleep); |
12 |
return world; |
13 |
}
|
Ini cukup sederhana untuk membuat box2DWorld
.
Kembali ke game.js
Lihat nomor komentar di dua blok kode di atas. Pada nomor dua, kita mengambil konteks elemen canvas
dengan menggunakan API penyeleksi (terlihat seperti penyeleksi jQuery atau MooTools, bukan?). Pada nomor tiga, kita memiliki fungsi baru yang menarik: initGame()
. Di sinilah kita menciptakan pemandangannya.
Salin dan sisipkan kode di bawah ini ke dalam game.js
, lalu kita akan mengulasnya bersama-sama.
1 |
|
2 |
function initGame(){ |
3 |
// create 2 big platforms
|
4 |
createBox(world, 3, 230, 60, 180, true, 'ground'); |
5 |
createBox(world, 560, 360, 50, 50, true, 'ground'); |
6 |
|
7 |
// create small platforms
|
8 |
for (var i = 0; i < 5; i++){ |
9 |
createBox(world, 150+(80*i), 360, 5, 40+(i*15), true, 'ground'); |
10 |
}
|
11 |
|
12 |
// create player ball
|
13 |
var ballSd = new b2CircleDef(); |
14 |
ballSd.density = 0.1; |
15 |
ballSd.radius = 12; |
16 |
ballSd.restitution = 0.5; |
17 |
ballSd.friction = 1; |
18 |
ballSd.userData = 'player'; |
19 |
var ballBd = new b2BodyDef(); |
20 |
ballBd.linearDamping = .03; |
21 |
ballBd.allowSleep = false; |
22 |
ballBd.AddShape(ballSd); |
23 |
ballBd.position.Set(20,0); |
24 |
player.object = world.CreateBody(ballBd); |
25 |
|
26 |
}
|
27 |
|
28 |
<p> Inside <code>box2dutils.js</code>, we've created a function, called <code>createBox</code>. This creates a static rectangle body. </p> |
29 |
|
30 |
function createBox(world, x, y, width, height, fixed, userData) { |
31 |
if (typeof(fixed) == 'undefined') fixed = true; |
32 |
//1
|
33 |
var boxSd = new b2BoxDef(); |
34 |
if (!fixed) boxSd.density = 1.0; |
35 |
//2
|
36 |
boxSd.userData = userData; |
37 |
//3
|
38 |
boxSd.extents.Set(width, height); |
39 |
|
40 |
//4
|
41 |
var boxBd = new b2BodyDef(); |
42 |
boxBd.AddShape(boxSd); |
43 |
//5
|
44 |
boxBd.position.Set(x,y); |
45 |
//6
|
46 |
return world.CreateBody(boxBd) |
47 |
}
|
Box2DBody
Box2DBody
memiliki beberapa karakteristik unik:
- Hal ini dapat bersifat statis (tidak terpengaruh oleh dampak benturan), kinematik (tidak terpengaruh benturan, namun dapat dipindah oleh mouse Anda, misalnya), atau dinamis (berinteraksi dengan segalanya)
- Harus memiliki definisi bentuk, dan harus menunjukkan bagaimana objeknya muncul
- Mungkin ada lebih dari satu perlengkapan, yang menunjukkan bagaimana objeknya akan berinteraksi dengan benturan
- Posisinya diatur oleh pusat objek Anda, bukan tepi kiri atas seperti banyak mesin lainnya.
Meninjau kodenya:
- Di sini, kita membuat satu definisi bentuk yang akan berbentuk persegi atau persegi panjang, dan mengatur kerapatannya (seberapa sering ia akan dipindahkan, atau diputar dengan kekuatan).
- Kami mengatur
userData
, biasanya Anda mengatur objek grafis di sini, namun dalam contoh ini, saya hanya mengatur string yang akan menjadi pengidentifikasi dari tipe objek untuk tabrakan. Parameter ini tidak mempengaruhi algoritma fisika. - Mengatur setengah dari ukuran kotak saya (ini adalah garis dari titik posisi, atau titik pusat objek ke sebuah sudut)
- Kami menciptakan definisi body, dan menambahkan definisi bentuk kotak.
- Mengatur posisi.
- Membuat body di world dan mengembalikan nilainya.
Membuat Body Bola Pemain
Saya telah mengkodekan pemain (bola) langsung di file game.js
. Ini mengikuti urutan yang sama dari pembuatan kotak, tapi, kali ini, ini adalah sebuah bola.
1 |
|
2 |
var ballSd = new b2CircleDef(); |
3 |
ballSd.density = 0.1; |
4 |
ballSd.radius = 12; |
5 |
ballSd.restitution = 0.5; |
6 |
ballSd.friction = 1; |
7 |
ballSd.userData = 'player'; |
8 |
var ballBd = new b2BodyDef(); |
9 |
ballBd.linearDamping = .03; |
10 |
ballBd.allowSleep = false; |
11 |
ballBd.AddShape(ballSd); |
12 |
ballBd.position.Set(20,0); |
13 |
player.object = world.CreateBody(ballBd); |
Jadi bagaimana kita menciptakan tubuh, selangkah demi selangkah?
- Membuat bentuk, perlengkapan dan definisi sensor
- Membuat definisi tubuh
- Menambahkan ke tubuh bentuk, perlengkapan atau sensor Anda (tidak dijelaskan dalam artikel ini)
- Membuat tubuh di dunia
Box2DCircle
Seperti yang saya catat sebelumnya, ini mengikuti proses pembuatan yang sama dari sebuah kotak, tapi sekarang Anda harus mengatur beberapa parameter baru.
- radius - Ini adalah panjang garis dari tengah lingkaran ke titik manapun di tepiannya.
- restitution - Bagaimana bola akan kehilangan, atau mendapatkan kekuatan saat bertabrakan dengan tubuh lain.
- friction - Bagaimana bola akan berguling.
Box2DBody
- Lebih Banyak Properti
- damping digunakan untuk mengurangi kecepatan tubuh - ada redaman sudut dan redaman linier.
- sleep di box2D, tubuh bisa sleep untuk memecahkan masalah kinerja. Sebagai contoh, misalkan Anda sedang mengembangkan game platform, dan levelnya ditentukan oleh layar 6000x400. Mengapa Anda perlu melakukan fisika untuk objek yang berada di luar layar? Anda tidak perlu; itulah intinya! Jadi pilihan yang tepat adalah membuat mereka dalam kondisi sleep, dan memperbaiki performa permainan Anda.
Kita sudah menciptakan dunia kita; Anda bisa menguji kode yang Anda miliki sejauh ini. Anda akan melihat pemain jatuh di atas platform barat.
Nah, jika Anda mencoba menjalankan demonya, Anda pasti bertanya-tanya, mengapa halaman itu gersang seperti kertas putih?



Selalu ingat: Box2D tidak me-render; ia hanya menghitung fisika.
Langkah 3 - Waktunya Me-render
Selanjutnya, mari kita me-render box2DWorld.
Buka skrip game.js
Anda, dan tambahkan kode berikut:
1 |
|
2 |
function step() { |
3 |
|
4 |
var stepping = false; |
5 |
var timeStep = 1.0/60; |
6 |
var iteration = 1; |
7 |
// 1
|
8 |
world.Step(timeStep, iteration); |
9 |
// 2
|
10 |
ctx.clearRect(0, 0, canvasWidth, canvasHeight); |
11 |
drawWorld(world, ctx); |
12 |
// 3
|
13 |
setTimeout('step()', 10); |
14 |
}
|
Apa yang kita capai disini:
- Menginstruksikan box2dWorld untuk melakukan simulasi fisika
- Membersihkan layar kanvas dan menggambar lagi
- Menjalankan fungsi
step()
lagi dalam sepuluh milidetik
Dengan sedikit kode ini, kita sekarang bekerja dengan fisika dan menggambar. Anda bisa mengujinya sendiri, dan melihat bola jatuh, seperti yang ditunjukkan di bawah ini:



drawWorld
di box2dutils.js
1 |
|
2 |
function drawWorld(world, context) { |
3 |
for (var j = world.m_jointList; j; j = j.m_next) { |
4 |
drawJoint(j, context); |
5 |
}
|
6 |
for (var b = world.m_bodyList; b; b = b.m_next) { |
7 |
for (var s = b.GetShapeList(); s != null; s = s.GetNext()) { |
8 |
drawShape(s, context); |
9 |
}
|
10 |
}
|
11 |
}
|
Apa yang telah kami tulis di atas adalah fungsi debug yang menggambar dunia kita ke dalam kanvas, menggunakan API grafis yang disediakan oleh API Canvas HTML5.
Perulangan pertama menggambar semua sambungan. Kami tidak menggunakan sambungan dalam artikel ini. Mereka agak rumit untuk demo pertama, tapi tetap saja itu penting untuk game Anda. Mereka memungkinkan Anda menciptakan tubuh yang sangat menarik.
Perulangan kedua menggambar semua benda, itulah sebabnya mengapa kita ada di sini!
1 |
|
2 |
function drawShape(shape, context) { |
3 |
context.strokeStyle = '#000000'; |
4 |
context.beginPath(); |
5 |
switch (shape.m_type) { |
6 |
case b2Shape.e_circleShape: |
7 |
{
|
8 |
var circle = shape; |
9 |
var pos = circle.m_position; |
10 |
var r = circle.m_radius; |
11 |
var segments = 16.0; |
12 |
var theta = 0.0; |
13 |
var dtheta = 2.0 * Math.PI / segments; |
14 |
// draw circle
|
15 |
context.moveTo(pos.x + r, pos.y); |
16 |
for (var i = 0; i < segments; i++) { |
17 |
var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta)); |
18 |
var v = b2Math.AddVV(pos, d); |
19 |
context.lineTo(v.x, v.y); |
20 |
theta += dtheta; |
21 |
}
|
22 |
context.lineTo(pos.x + r, pos.y); |
23 |
|
24 |
// draw radius
|
25 |
context.moveTo(pos.x, pos.y); |
26 |
var ax = circle.m_R.col1; |
27 |
var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y); |
28 |
context.lineTo(pos2.x, pos2.y); |
29 |
}
|
30 |
break; |
31 |
case b2Shape.e_polyShape: |
32 |
{
|
33 |
var poly = shape; |
34 |
var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0])); |
35 |
context.moveTo(tV.x, tV.y); |
36 |
for (var i = 0; i < poly.m_vertexCount; i++) { |
37 |
var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i])); |
38 |
context.lineTo(v.x, v.y); |
39 |
}
|
40 |
context.lineTo(tV.x, tV.y); |
41 |
}
|
42 |
break; |
43 |
}
|
44 |
context.stroke(); |
45 |
}
|
Kami melakukan perulangan melalui setiap simpul objek dan menggambarnya dengan garis (context.moveTo
dan context.lineTo
). Nah, ini berguna untuk memiliki sebuah contoh... tapi tidak begitu berguna dalam latihan. Bila Anda menggunakan grafis, Anda hanya perlu memperhatikan posisi tubuh. Anda tidak perlu melakukan perulangan pada simpul, seperti demo ini.
Langkah 4 - Interaktivitas
Sebuah game tanpa interaktivitas adalah sebuah film, dan sebuah film dengan interaktivitas adalah sebuah permainan.
Mari kembangkan fungsi panah keyboard untuk melompat dan memindahkan bola.
Tambahkan kode berikut ke file game.js
Anda:
1 |
|
2 |
function handleKeyDown(evt){ |
3 |
keys[evt.keyCode] = true; |
4 |
}
|
5 |
|
6 |
|
7 |
function handleKeyUp(evt){ |
8 |
keys[evt.keyCode] = false; |
9 |
}
|
10 |
|
11 |
// disable vertical scrolling from arrows :)
|
12 |
document.onkeydown=function(){return event.keyCode!=38 && event.keyCode!=40} |
Dengan handleKeyDown
dan handleKeyUp
, kami mengatur sebuah array
yang melacak setiap tombol yang diketikkan pengguna. Dengan document.onkeydown
, kita menonaktifkan fungsi scroll vertikal bawaan browser untuk panah atas dan bawah. Pernahkah Anda memainkan game HTML5, dan saat Anda melompat, pemain, musuh dan objek berada diluar layar? Itu tidak akan menjadi masalah sekarang.
Tambahkan sedikit kode berikut ke awal fungsi step()
Anda:
1 |
|
2 |
handleInteractions(); |
Dan di luar, nyatakan fungsinya:
1 |
|
2 |
function handleInteractions(){ |
3 |
// up arrow
|
4 |
// 1
|
5 |
var collision = world.m_contactList; |
6 |
player.canJump = false; |
7 |
if (collision != null){ |
8 |
if (collision.GetShape1().GetUserData() == 'player' || collision.GetShape2().GetUserData() == 'player'){ |
9 |
if ((collision.GetShape1().GetUserData() == 'ground' || collision.GetShape2().GetUserData() == 'ground')){ |
10 |
var playerObj = (collision.GetShape1().GetUserData() == 'player' ? collision.GetShape1().GetPosition() : collision.GetShape2().GetPosition()); |
11 |
var groundObj = (collision.GetShape1().GetUserData() == 'ground' ? collision.GetShape1().GetPosition() : collision.GetShape2().GetPosition()); |
12 |
if (playerObj.y < groundObj.y){ |
13 |
player.canJump = true; |
14 |
}
|
15 |
}
|
16 |
}
|
17 |
}
|
18 |
// 2
|
19 |
var vel = player.object.GetLinearVelocity(); |
20 |
// 3
|
21 |
if (keys[38] && player.canJump){ |
22 |
vel.y = -150; |
23 |
}
|
24 |
|
25 |
// 4
|
26 |
// left/right arrows
|
27 |
if (keys[37]){ |
28 |
vel.x = -60; |
29 |
}
|
30 |
else if (keys[39]){ |
31 |
vel.x = 60; |
32 |
}
|
33 |
|
34 |
// 5
|
35 |
player.object.SetLinearVelocity(vel); |
36 |
}
|
Bagian paling rumit dari kode di atas adalah yang pertama, dimana kita memeriksa tumbukan, dan menulis beberapa kondisi untuk menentukan apakah shape1
atau shape2
adalah pemainnya. Jika ya, kita verifikasi jika shape1
atau shape2
adalah object
tanah. Sekali lagi, jika demikian, pemain bertabrakan dengan tanah. Selanjutnya, kita periksa apakah pemain berada di atas tanah. Jika itu yang terjadi, maka pemain bisa melompat.
Pada baris komentar kedua (2), kita mengambil LinearVelocity
pemain.
Daerah komentar yang ketiga dan seterusnya memeriksa jika panah ditekan, dan menyesuaikan vektor kecepatannya.
Di wilayah kelima, kita mengatur pemain dengan vektor kecepatan baru.
Interaksi sekarang sudah selesai! Tapi tidak ada tujuan, kita hanya melompat, melompat, melompat... dan melompat!
Langkah 5 - Pesan "You Win"
Tambahkan kode di bawah ini ke awal fungsi LinearVelocity
Anda:
1 |
|
2 |
if (player.object.GetCenterPosition().y > canvasHeight){ |
3 |
player.object.SetCenterPosition(new b2Vec2(20,0),0) |
4 |
}
|
5 |
else if (player.object.GetCenterPosition().x > canvasWidth-50){ |
6 |
showWin(); |
7 |
return; |
8 |
}
|
- Kondisi pertama menentukan apakah pemain jatuh, dan harus dibawa kembali ke titik awal (di atas platform barat).
- Kondisi kedua memeriksa apakah pemain berada di atas platform kedua, dan memenangkan permainannya. Inilah fungsi
showWin()
.
1 |
|
2 |
function showWin(){ |
3 |
ctx.fillStyle = '#000'; |
4 |
ctx.font = '30px verdana'; |
5 |
ctx.textBaseline = 'top'; |
6 |
ctx.fillText('Ye! you made it!', 30, 0); |
7 |
ctx.fillText('thank you, andersonferminiano.com', 30, 30); |
8 |
ctx.fillText('@andferminiano', 30, 60); |
9 |
}
|
Dan itu saja! Anda baru saja menyelesaikan game sederhana pertama Anda dengan HTML5 dan Box2D. Selamat!