HTML5 este în creștere mai repede decât oricine ar fi putut imagina. Soluții puternice și profesionale sunt deja dezvoltate? chiar și în lumea jocurilor! Check out sutele de jocuri HTML5 de pe Envato Market.
Astăzi, veți face primul joc utilizând Box2D și HTML5 pânză
etichetă.
Box2D este un motor open source și popular care simulează fizica 2D pentru a face jocuri și aplicații. Mai întâi scris în C ++, a fost convertit în numeroase limbi de către contribuabili din comunitate.
Cu aceleași metode și obiecte, aveți posibilitatea să faceți fizica jocurilor în mai multe limbi, cum ar fi Obiectiv C (iPhone / iPad), Actionscript 3.0 (Web), HTML 5 (Web), etc.
Pentru a începe să vă dezvoltați demo-ul, descărcați aici motorul Box2D pentru HTML5. Apoi, creați un nou fișier HTML cu următoarea structură (copiați directoarele js și lib din proiectul box2d-js în dosarul dvs. de joc).
Acum, trebuie să introduceți fișierele necesare pentru a rula box2D în fișierul HTML:
Da, acesta este un număr mare de cereri HTTP!
Rețineți că, pentru desfășurare, este foarte recomandat să concatenați toate aceste resurse într-una singură
scenariu
fişier.
Apoi, creați încă două script-uri în interiorul / Js /
dosarul, numit "box2dutils.js"
și "game.js"
.
box2dlib
, și este important pentru desenarea funcțiilor (voi explica, de asemenea, câteva părți importante aici).Copiați și lipiți următorul cod box2dutils.js
. Nu vă faceți griji! O să-i explic puțin câte puțin!
funcția drawWorld (lumea, contextul) pentru (var j = world.m_jointList; j; j = j.m_next) tragereJoint (j, context); pentru (var b = lume.m_bodyList; b; b = b.m_next) pentru (var s = b.GetShapeList (); s! = null; s = s.GetNext ; funcția drawJoint (articulație, context) var b1 = joint.m_body1; var b2 = joint.m_body2; var x1 = poziția b1.m; var x2 = poziția b2.m; var p1 = comun.GetAnchor1 (); var p2 = comun.GetAnchor2 (); context.strokeStyle = '# 00eeee'; context.beginPath (); switch (comun.m_type) caz b2Joint.e_distanceJoint: context.moveTo (p1.x, p1.y); context.lineTo (p2.x, p2.y); pauză; cazul b2Joint.e_pulleyJoint: // TODO break; implicit: dacă (b1 == world.m_groundBody) context.moveTo (p1.x, p1.y); context.lineTo (x2.x, x2.y); altfel dacă (b2 == world.m_groundBody) context.moveTo (p1.x, p1.y); context.lineTo (x1.x, x1.y); altfel context.moveTo (x1.x, x1.y); context.lineTo (p1.x, p1.y); context.lineTo (x2.x, x2.y); context.lineTo (p2.x, p2.y); pauză; context.stroke (); funcție drawShape (formă, context) context.strokeStyle = '# 000000'; context.beginPath (); comutator (shape.m_type) caz b2Shape.e_circleShape: var circle = forma; var pos = circle.m_position; var r = circle.m_radius; var = 16,0; var theta = 0,0; var dtheta = 2.0 * Math.PI / segmente; // atrage cercul context.moveTo (pos.x + r, pos.y); pentru (var i = 0; i < segments; i++) var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta)); var v = b2Math.AddVV(pos, d); context.lineTo(v.x, v.y); theta += dtheta; context.lineTo(pos.x + r, pos.y); // draw radius context.moveTo(pos.x, pos.y); var ax = circle.m_R.col1; var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y); context.lineTo(pos2.x, pos2.y); break; case b2Shape.e_polyShape: var poly = shape; var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0])); context.moveTo(tV.x, tV.y); for (var i = 0; i < poly.m_vertexCount; i++) var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i])); context.lineTo(v.x, v.y); context.lineTo(tV.x, tV.y); break; context.stroke(); function createWorld() var worldAABB = new b2AABB(); worldAABB.minVertex.Set(-1000, -1000); worldAABB.maxVertex.Set(1000, 1000); var gravity = new b2Vec2(0, 300); var doSleep = true; var world = new b2World(worldAABB, gravity, doSleep); return world; function createGround(world) var groundSd = new b2BoxDef(); groundSd.extents.Set(1000, 50); groundSd.restitution = 0.2; var groundBd = new b2BodyDef(); groundBd.AddShape(groundSd); groundBd.position.Set(-500, 340); return world.CreateBody(groundBd) function createBall(world, x, y) var ballSd = new b2CircleDef(); ballSd.density = 1.0; ballSd.radius = 20; ballSd.restitution = 1.0; ballSd.friction = 0; var ballBd = new b2BodyDef(); ballBd.AddShape(ballSd); ballBd.position.Set(x,y); return world.CreateBody(ballBd); function createBox(world, x, y, width, height, fixed, userData) if (typeof(fixed) == 'undefined') fixed = true; var boxSd = new b2BoxDef(); if (!fixed) boxSd.density = 1.0; boxSd.userData = userData; boxSd.extents.Set(width, height); var boxBd = new b2BodyDef(); boxBd.AddShape(boxSd); boxBd.position.Set(x,y); return world.CreateBody(boxBd)
Deschide index.html
fișier pe care l-ați creat anterior și adăugați a pânză
element (600x400) în cadrul corp
element. Aici vom lucra cu API-ul de desen HTML5:
De asemenea, în timp ce sunteți aici, referință game.js
și box2dutils.js
.
Asta va face pentru HTML! Să lucrăm la distractivul JavaScript acum!
Deschis game.js
, și introduceți codul de mai jos:
// unele variabile pe care le vom folosi în această demonstrație var initId = 0; var player = funcția () this.object = null; this.canJump = false; ; var lume; var ctx; var canvasWidth; var canvasHeight; tastele var = = []; // HTML5 onLoad eveniment Event.observe (fereastra, 'load', function () world = createWorld (); // box2DWorld ctx = $ ('joc') getContext (2d) $ canvasWidth = parseInt (canvasElm.width); canvasHeight = parseInt (canvasElm.height); initGame (); // 3 step (); // 4 // 5 window.addEventListener ('keydown' handleKeyDown, true); window.addEventListener ('keyup', handleKeyUp, true););
Bine, să ne dăm seama ce face această bucată de cod!
Box2DWorld este una dintre clasele care este pusă la dispoziție, prin intermediul nucleului box2d. Funcția sa este simplă: combinați Tot într-o clasă. În box2DWorld, aveți definirea corpurilor și managerul de coliziuni al jocului sau al aplicației.
Păstrează game.js
și box2dutils.js
fișierele deschise și căutați createWorld ()
funcția în interiorul box2dutils.js
.
funcția createWorld () // aici creăm setările noastre globale pentru coliziuni var worldAABB = new b2AABB (); worldAABB.minVertex.Set (-1000, -1000); worldAABB.maxVertex.Set (1000, 1000); // set vector gravitațional var gravitatea = nou b2Vec2 (0, 300); var doSleep = adevărat; // init lumea noastra si returneaza valoarea ei var = nou b2World (worldAABB, gravitate, doSleep); lumea întoarcerii;
Este foarte simplu să creați box2DWorld
.
game.js
Consultați numerele comentate din cele două blocuri de cod de mai sus. Pe numărul doi, vom prelua pânză
elementul prin folosirea selectorului API (seamănă cu selectorii jQuery sau MooTools, nu?). Pe locul trei, avem o nouă funcție interesantă: initGame ()
. Aici creăm peisajul.
Copiați și inserați codul de mai jos în game.js
, și apoi vom examina împreună.
funcția initGame () // crea 2 platforme mari createBox (lume, 3, 230, 60, 180, true, 'teren'); createBox (lume, 560, 360, 50, 50, adevărat, "teren"); // creați platforme mici pentru (var i = 0; i < 5; i++) createBox(world, 150+(80*i), 360, 5, 40+(i*15), true, 'ground'); // create player ball var ballSd = new b2CircleDef(); ballSd.density = 0.1; ballSd.radius = 12; ballSd.restitution = 0.5; ballSd.friction = 1; ballSd.userData = 'player'; var ballBd = new b2BodyDef(); ballBd.linearDamping = .03; ballBd.allowSleep = false; ballBd.AddShape(ballSd); ballBd.position.Set(20,0); player.object = world.CreateBody(ballBd);Interior
funcția createBox (lume, x, y, lățime, înălțime, fix, userData) if (typeof (fix) == 'undefined') fix = true; // 1 var casetaSd = noua b2BoxDef (); dacă (! fix) boxSd.density = 1.0; // 2 boxSd.userData = userData; // 3 boxSd.extents.Set (lățime, înălțime); // 4 caseta varBD = new b2BodyDef (); boxBd.AddShape (boxSd); // 5 boxBd.position.Set (x, y); // 6 retur world.CreateBody (boxBd)box2dutils.js
, am creat o funcție, numităcreateBox
. Acest lucru creează un corp dreptunghiular static.
Box2DBody
A Box2DBody
are câteva caracteristici unice:
datele utilizatorului
, de obicei configurați obiecte grafice aici, dar în acest exemplu, am setat doar șiruri care vor fi identificatorul tipului de obiect pentru coliziuni. Acest parametru nu afectează algoritmii fizicii.Am codificat jucătorul (mingea) direct în game.js
fişier. Urmează aceeași secvență de creare de cutii, dar, de data aceasta, este o minge.
var ballSd = nou b2CircleDef (); ballSd.density = 0,1; ballSd.radius = 12; Rezoluția bătăii = 0.5; ballSd.friction = 1; ballSd.userData = 'jucător'; var ballBd = noua b2BodyDef (); ballBd.linearDamping = .03; ballBd.allowSleep = false; ballBd.AddShape (ballSd); ballBd.position.Set (20,0); player.object = world.CreateBody (ballBd);
Deci, cum să creăm un corp, pas cu pas?
Box2DCircle
După cum am observat mai devreme, aceasta urmează același proces de creare a unei casete, dar acum trebuie să setați niște parametri noi.
Box2DBody
- Mai multe proprietățiAm creat deja lumea noastră; puteți testa codul pe care îl aveți până acum. Veți vedea că jucătorul va cădea deasupra platformei de vest.
Acum, dacă ați încercat să rulați demo-ul, ar trebui să vă întrebați de ce pagina este goală ca hârtia albă?
Întotdeauna rețineți: Box2D nu face; calculează doar fizica.
Apoi, să redați caseta2DWorld.
Deschide-ți game.js
script și adăugați următorul cod:
pasul funcției () var stepping = false; var timeStep = 1.0 / 60; var iterație = 1; // 1 etapa mondială (etapa de timp, iterație); // 2 ctx.clearRect (0, 0, canvasWidth, canvasHeight); drawWorld (lume, ctx); // 3 setTimeout ('pas ()', 10);
Etapa()
funcționează din nou în zece milisecunde Cu acest cod de cod, lucrăm acum cu fizica și desenul. Puteți să vă testați și să urmăriți o minge care se încadrează, după cum se arată mai jos:
drawWorld
în box2dutils.js
funcția drawWorld (lumea, contextul) pentru (var j = world.m_jointList; j; j = j.m_next) tragereJoint (j, context); pentru (var b = lume.m_bodyList; b; b = b.m_next) pentru (var s = b.GetShapeList (); s! = null; s = s.GetNext ;
Ceea ce am scris mai sus este o funcție de depanare care atrage lumea noastră în pânză, folosind graficul API furnizat de Canvas API-ul HTML5.
Prima buclă atrage toate îmbinările. Nu am folosit articulații în acest articol. Ele sunt un pic complex pentru un prim demo, dar, totuși, ele sunt esențiale pentru jocurile tale. Ele vă permit să creați corpuri foarte interesante.
Cea de-a doua bucla atrage toate corpurile, de aceea suntem aici!
funcția drawShape (formă, context) context.strokeStyle = '# 000000'; context.beginPath (); comutator (shape.m_type) caz b2Shape.e_circleShape: var circle = forma; var pos = circle.m_position; var r = circle.m_radius; var = 16,0; var theta = 0,0; var dtheta = 2.0 * Math.PI / segmente; // atrage cercul context.moveTo (pos.x + r, pos.y); pentru (var i = 0; i < segments; i++) var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta)); var v = b2Math.AddVV(pos, d); context.lineTo(v.x, v.y); theta += dtheta; context.lineTo(pos.x + r, pos.y); // draw radius context.moveTo(pos.x, pos.y); var ax = circle.m_R.col1; var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y); context.lineTo(pos2.x, pos2.y); break; case b2Shape.e_polyShape: var poly = shape; var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0])); context.moveTo(tV.x, tV.y); for (var i = 0; i < poly.m_vertexCount; i++) var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i])); context.lineTo(v.x, v.y); context.lineTo(tV.x, tV.y); break; context.stroke();
Ne întoarcem prin fiecare vârf al obiectului și îl trasăm cu linii (context.moveTo
și context.lineTo
). Acum, este util să aveți un exemplu? dar nu atât de util în practică. Atunci când utilizați grafică, trebuie să acordați atenție poziționării organismelor. Nu aveți nevoie să faceți buclă vertexelor, așa cum face acest demo.
Un joc fără interactivitate este un film, iar un film cu interactivitate este un joc.
Să dezvoltăm funcția săgeată de tastatură pentru a sari și a muta mingea.
Adăugați următorul cod la adresa dvs. game.js
fişier:
funcția handleKeyDown (evt) chei [evt.keyCode] = adevărat; funcția handleKeyUp (evt) chei [evt.keyCode] = false; // dezactivează derularea verticală de la săgeți :) document.onkeydown = funcția () return event.keyCode! = 38 && event.keyCode! = 40
Cu handleKeyDown
și handleKeyUp
, am setat un mulțime
care urmărește fiecare cheie pe care o tipizează utilizatorul. Cu document.onkeydown
, dezactivați funcția de defilare verticală nativă a browserului pentru săgețile sus și jos. Ați jucat vreodată un joc HTML5 și când sari, jucătorul, dușmanii și obiectele vor ieși din ecran? Asta nu va fi o problemă acum.
Adăugați următorul cod de cod la începutul paginii Etapa()
funcţie:
handleInteractions ();
Și în afară, declară funcția:
funcția handleInteractions () // săgeată sus // 1 var collision = world.m_contactList; player.canJump = false; dacă (collision.GetShape1 () GetUserData () == 'player' || collision.GetShape2 () GetUserData () == 'jucător') if (collision.GetShape1 .GetUserData () == 'ground' || collision.GetShape2 () GetUserData () == 'teren')) var playerObj = (collision.GetShape1 () GetUserData () == 'player'? Collision.GetShape1 () .GetPosition (): collision.GetShape2 () .GetPosition ()); var groundObj = (collision.GetShape1 () GetUserData () == 'sol' collision.GetShape1 () GetPosition (): collision.GetShape2 () GetPosition ()); dacă (playerObj.y < groundObj.y) player.canJump = true; // 2 var vel = player.object.GetLinearVelocity(); // 3 if (keys[38] && player.canJump) vel.y = -150; // 4 // left/right arrows if (keys[37]) vel.x = -60; else if (keys[39]) vel.x = 60; // 5 player.object.SetLinearVelocity(vel);
Cea mai complicată parte din codul de mai sus este prima, unde verificăm o coliziune și scriem câteva condiții pentru a determina dacă shape1
sau shape2
este jucătorul. Dacă este, verificăm dacă shape1
sau shape2
este un motiv obiect
. Din nou, dacă da, jucătorul se ciocnește cu solul. Apoi, verificăm dacă jucătorul este deasupra solului. În acest caz, jucătorul poate sări.
În al doilea rând comentat (2), vom prelua LinearVelocity
al jucătorului.
Regiunile 3 și 4 comentate verifică dacă sunt apăsate săgețile și ajustează vectorul de viteză în consecință.
În a cincea regiune, setăm jucătorul cu noul vector de viteză.
Interacțiunile sunt acum terminate! Dar nu există nici un obiectiv, doar să sărim, să sărim, să sarăm? și sari!
Adăugați codul de mai jos la începutul paginii LinearVelocity
funcţie:
dacă player.object.GetCenterPosition (). y> canvasHeight) player.object.SetCenterPosition (nou b2Vec2 (20,0), 0) altceva dacă (player.object.GetCenterPosition () x> canvasWidth-50) showWin (); întoarcere;
showWin ()
funcţie.funcția showWin () ctx.fillStyle = '# 000'; ctx.font = '30px verdana'; ctx.textBaseline = 'top'; ctx.fillText ("Voi ați reușit!", 30, 0); ctx.fillText ("mulțumesc, andersonferminiano.com", 30, 30); ctx.fillText ("@ andferminiano", 30, 60);
Si asta e! Tocmai ați terminat primul joc simplu cu HTML5 și Box2D. Felicitări!
Dacă aveți nevoie de o soluție mai simplă, puteți verifica selecția jocurilor HTML5 de pe Envato Market, dintre care mulți vin cu codul sursă pentru a investiga și personaliza pentru a se potrivi nevoilor dvs..