HTML5 sta crescendo più velocemente di quanto chiunque avrebbe potuto immaginare. Soluzioni potenti e professionali sono già in fase di sviluppo? anche nel mondo dei giochi! Scopri le centinaia di giochi HTML5 su Envato Market.
Oggi farai il tuo primo gioco usando Box2D e HTML5 tela
etichetta.
Box2D è un motore open source e popolare che simula la fisica 2D per creare giochi e applicazioni. Scritto principalmente in C ++, è stato convertito in numerose lingue da contributori della comunità.
Con gli stessi metodi e oggetti, hai la possibilità di rendere la fisica dei tuoi giochi in molte lingue, come Objective C (iPhone / iPad), Actionscript 3.0 (Web), HTML 5 (Web), ecc..
Per iniziare a sviluppare la tua demo, scarica qui il motore Box2D per HTML5. Quindi, crea un nuovo file HTML con la seguente struttura (copia le directory js e lib dal progetto box2d-js nella cartella del gioco).
Ora, devi inserire i file necessari per eseguire box2D nel tuo file HTML:
Sì, questo è un numero enorme di richieste HTTP!
Si noti che, per la distribuzione, è altamente raccomandato che si concatenano tutte queste risorse in una sola
copione
file.
Quindi, crea altri due script all'interno di / Js /
cartella, chiamata "box2dutils.js"
e "game.js"
.
box2dlib
, ed è importante per le funzioni di disegno (spiegherò anche alcune parti importanti qui).Copia e incolla il seguente codice in box2dutils.js
. Non preoccuparti! Te lo spiego un po 'alla volta!
function drawWorld (world, context) per (var j = world.m_jointList; j; j = j.m_next) drawJoint (j, context); per (var b = world.m_bodyList; b; b = b.m_next) per (var s = b.GetShapeList (); s! = null; s = s.GetNext ()) drawShape (s, context) ; function drawJoint (joint, context) var b1 = joint.m_body1; var b2 = joint.m_body2; var x1 = b1.m_position; var x2 = b2.m_position; var p1 = joint.GetAnchor1 (); var p2 = joint.GetAnchor2 (); context.strokeStyle = '# 00eeee'; context.beginPath (); switch (joint.m_type) case b2Joint.e_distanceJoint: context.moveTo (p1.x, p1.y); context.lineTo (p2.x, p2.y); rompere; case b2Joint.e_pulleyJoint: // TODO break; default: if (b1 == world.m_groundBody) context.moveTo (p1.x, p1.y); context.lineTo (x2.x, x2.y); else if (b2 == world.m_groundBody) context.moveTo (p1.x, p1.y); context.lineTo (x1.x, x1.y); else context.moveTo (x1.x, x1.y); context.lineTo (p1.x, p1.y); context.lineTo (x2.x, x2.y); context.lineTo (p2.x, p2.y); rompere; context.stroke (); function drawShape (shape, context) context.strokeStyle = '# 000000'; context.beginPath (); switch (shape.m_type) case b2Shape.e_circleShape: var circle = shape; var pos = circle.m_position; var r = circle.m_radius; var segment = 16.0; var theta = 0,0; var dtheta = 2.0 * Math.PI / segments; // disegna circle context.moveTo (pos.x + r, pos.y); per (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)
Apri il index.html
file creato in precedenza e aggiungere un tela
elemento (600x400) all'interno del corpo
elemento. Qui lavoreremo con l'API di disegno HTML5:
Inoltre, mentre sei qui, riferimento game.js
e box2dutils.js
.
Questo lo farà per l'HTML! Lavoriamo ora sul divertente codice JavaScript!
Aperto game.js
, e inserisci il codice qui sotto:
// alcune variabili che useremo in questa demo var initId = 0; var player = function () this.object = null; this.canJump = false; ; var mondo; var ctx; var canvasWidth; var canvasHeight; var keys = []; // HTML5 evento onLoad Event.observe (finestra, 'load', function () world = createWorld (); // box2DWorld ctx = $ ('game'). GetContext ('2d'); // 2 var canvasElm = $ ('game'); canvasWidth = parseInt (canvasElm.width); canvasHeight = parseInt (canvasElm.height); initGame (); // 3 step (); // 4 // 5 window.addEventListener ('keydown', handleKeyDown, true); window.addEventListener ('keyup', handleKeyUp, true););
Ok, scopriamo cosa fa questo pezzo di codice!
Box2DWorld è una delle classi che è resa disponibile, attraverso il nucleo di box2d. La sua funzione è semplice: combinare qualunque cosa in una classe. In box2DWorld hai la definizione dei corpi e il gestore delle collisioni del tuo gioco o applicazione.
Mantieni il game.js
e box2dutils.js
i file si aprono e cercano il createWorld ()
funzione dentro box2dutils.js
.
function createWorld () // qui creiamo le nostre impostazioni del mondo per le collisioni var worldAABB = new b2AABB (); worldAABB.minVertex.Set (-1000, -1000); worldAABB.maxVertex.Set (1000, 1000); // imposta gravity vector var gravity = new b2Vec2 (0, 300); var doSleep = true; // inizia il nostro mondo e restituisce il suo valore var world = new b2World (worldAABB, gravity, doSleep); ritorno al mondo;
È abbastanza semplice creare il box2DWorld
.
game.js
Fare riferimento ai numeri commentati nei due blocchi di codice sopra. Al numero due, recuperiamo il tela
il contesto dell'elemento usando l'API selector (assomiglia ai selettori jQuery o MooTools, vero?). Al numero tre, abbiamo una nuova interessante funzione: initGame ()
. Questo è dove creiamo lo scenario.
Copia e incolla il codice qui sotto in game.js
, e poi lo esamineremo insieme.
function initGame () // crea 2 grandi piattaforme createBox (world, 3, 230, 60, 180, true, 'ground'); createBox (world, 560, 360, 50, 50, true, 'ground'); // crea piccole piattaforme per (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);Dentro
function createBox (world, x, y, width, height, fixed, userData) if (typeof (fixed) == 'undefined') fixed = true; // 1 var boxSd = new b2BoxDef (); se (! fixed) boxSd.density = 1.0; // 2 boxSd.userData = userData; // 3 boxSd.extents.Set (larghezza, altezza); // 4 var boxBd = new b2BodyDef (); boxBd.AddShape (boxSd); // 5 boxBd.position.Set (x, y); // 6 return world.CreateBody (boxBd)box2dutils.js
, abbiamo creato una funzione, chiamatacreateBox
. Questo crea un corpo rettangolo statico.
Box2DBody
UN Box2DBody
ha alcune caratteristiche uniche:
dati utente
, di solito si impostano gli oggetti grafici qui, ma in questo esempio, ho appena impostato le stringhe che saranno l'identificatore del tipo dell'oggetto per le collisioni. Questo parametro non influisce sugli algoritmi fisici.Ho codificato il giocatore (palla) direttamente nel game.js
file. Segue la stessa sequenza di creazione di scatole, ma, questa volta, è una palla.
var ballSd = new b2CircleDef (); ballSd.density = 0,1; ballSd.radius = 12; ballSd.restitution = 0,5; ballSd.friction = 1; ballSd.userData = 'giocatore'; var ballBd = new b2BodyDef (); ballBd.linearDamping = .03; ballBd.allowSleep = false; ballBd.AddShape (ballSd); ballBd.position.Set (20,0); player.object = world.CreateBody (ballBd);
Quindi, come creiamo un corpo, passo dopo passo?
Box2DCircle
Come ho notato prima, questo segue lo stesso processo di creazione di una scatola, ma ora devi impostare alcuni nuovi parametri.
Box2DBody
- Altre proprietàAbbiamo già creato il nostro mondo; puoi testare il codice che hai finora. Vedrai il giocatore cadere sopra la piattaforma ovest.
Ora, se hai provato ad eseguire la demo, dovresti chiedertelo, perché la pagina è sterile come la carta bianca?
Ricorda sempre: Box2D non rende; calcola solo la fisica.
Successivamente, rendiamo il box2DWorld.
Apri i tuoi game.js
script e aggiungi il seguente codice:
function step () var stepping = false; var timeStep = 1.0 / 60; var iteration = 1; // 1 world.Step (timeStep, iteration); // 2 ctx.clearRect (0, 0, canvasWidth, canvasHeight); drawWorld (world, ctx); // 3 setTimeout ('step ()', 10);
passo()
funzione di nuovo in dieci millisecondi Con questo bit di codice, stiamo lavorando con la fisica e il disegno. Puoi metterti alla prova e guardare una palla che cade, come dimostrato di seguito:
drawWorld
nel box2dutils.js
function drawWorld (world, context) per (var j = world.m_jointList; j; j = j.m_next) drawJoint (j, context); per (var b = world.m_bodyList; b; b = b.m_next) per (var s = b.GetShapeList (); s! = null; s = s.GetNext ()) drawShape (s, context) ;
Quello che abbiamo scritto sopra è una funzione di debug che disegna il nostro mondo nella tela, utilizzando l'API grafica fornita dall'API Canvas di HTML5.
Il primo ciclo disegna tutte le articolazioni. Non abbiamo usato giunti in questo articolo. Sono un po 'complessi per una prima demo, ma, tuttavia, sono essenziali per i tuoi giochi. Ti permettono di creare corpi molto interessanti.
Il secondo ciclo disegna tutti i corpi, ed è per questo che siamo qui!
function drawShape (shape, context) context.strokeStyle = '# 000000'; context.beginPath (); switch (shape.m_type) case b2Shape.e_circleShape: var circle = shape; var pos = circle.m_position; var r = circle.m_radius; var segment = 16.0; var theta = 0,0; var dtheta = 2.0 * Math.PI / segments; // disegna circle context.moveTo (pos.x + r, pos.y); per (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();
Stiamo scorrendo attraverso ogni vertice dell'oggetto e disegnandolo con linee (context.moveTo
e context.lineTo
). Ora, è utile avere un esempio? ma non così utile nella pratica. Quando usi la grafica, devi solo prestare attenzione al posizionamento dei corpi. Non è necessario eseguire il loop dei vertici, come fa questa demo.
Un gioco senza interattività è un film e un film con interattività è un gioco.
Sviluppiamo la funzionalità della freccia della tastiera per saltare e muovere la palla.
Aggiungi il seguente codice al tuo game.js
file:
function handleKeyDown (evt) keys [evt.keyCode] = true; function handleKeyUp (evt) keys [evt.keyCode] = false; // disabilita lo scrolling verticale dalle frecce :) document.onkeydown = function () return event.keyCode! = 38 && event.keyCode! = 40
Con handleKeyDown
e handleKeyUp
, abbiamo impostato un schieramento
che tiene traccia di ogni chiave che l'utente digita. Con document.onkeydown
, disabilitiamo la funzione di scorrimento verticale nativa del browser per le frecce su e giù. Hai mai giocato a un gioco HTML5 e quando salti, il giocatore, i nemici e gli oggetti vanno fuori dallo schermo? Non sarà un problema ora.
Aggiungi questo prossimo bit di codice all'inizio del tuo passo()
funzione:
handleInteractions ();
E fuori, dichiarare la funzione:
function handleInteractions () // freccia su // // var collision = world.m_contactList; player.canJump = false; if (collision! = null) if (collision.GetShape1 (). GetUserData () == 'player' || collision.GetShape2 (). GetUserData () == 'player') if ((collision.GetShape1 () .GetUserData () == 'ground' || collision.GetShape2 (). GetUserData () == 'ground')) var playerObj = (collision.GetShape1 (). GetUserData () == 'player'? Collision.GetShape1 () .GetPosition (): collision.GetShape2 (). GetPosition ()); var groundObj = (collision.GetShape1 (). GetUserData () == 'ground'? collision.GetShape1 (). GetPosition (): collision.GetShape2 (). GetPosition ()); se (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);
Il pezzo più complicato del codice qui sopra è il primo, dove controlliamo una collisione e scriviamo alcune condizioni per determinare se il Shape1
o il shape2
è il giocatore. Se lo è, verifichiamo se Shape1
o shape2
è un terreno oggetto
. Di nuovo, se è così, il giocatore è in collisione con il terreno. Successivamente, controlliamo se il giocatore è fuori terra. Se è così, allora il giocatore può saltare.
Sulla seconda riga commentata (2), recuperiamo il LinearVelocity
del giocatore.
Le regioni terze e successive commentate verificano se le frecce vengono premute e regolano di conseguenza il vettore di velocità.
Nella quinta regione, impostiamo il giocatore con il nuovo vettore di velocità.
Le interazioni sono ora fatte! Ma non c'è un obiettivo, saltiamo, saltiamo, saltiamo? e saltare!
Aggiungi il codice qui sotto all'inizio del tuo LinearVelocity
funzione:
if (player.object.GetCenterPosition (). y> canvasHeight) player.object.SetCenterPosition (new b2Vec2 (20,0), 0) else if (player.object.GetCenterPosition (). x> canvasWidth-50) showWin (); ritorno;
showWin ()
funzione.function showWin () ctx.fillStyle = '# 000'; ctx.font = '30px verdana'; ctx.textBaseline = 'top'; ctx.fillText ('Ye! you made it!', 30, 0); ctx.fillText ('grazie, andersonferminiano.com', 30, 30); ctx.fillText ('@ andferminiano', 30, 60);
E questo è tutto! Hai appena completato il tuo primo gioco semplice con HTML5 e Box2D. Congratulazioni!
Se hai bisogno di una soluzione più semplice, puoi controllare la selezione di giochi HTML5 su Envato Market, molti dei quali sono dotati di codice sorgente che puoi esaminare e personalizzare per soddisfare le tue esigenze.