Crea il tuo primo gioco con HTML5

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.


Cos'è Box2D?

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..


Passaggio 1: configurazione del progetto

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".

  • box2dutils.js - è una copia e incolla da alcune demo che vengono con box2dlib, ed è importante per le funzioni di disegno (spiegherò anche alcune parti importanti qui).
  • game.js - il gioco, a sua volta; qui è dove creiamo le piattaforme, il giocatore, applichiamo le interazioni da tastiera, ecc.

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) 

Passaggio 2: sviluppo del gioco

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););

Box2DWorld - ecco perché siamo qui

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.


Torna a 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 box2dutils.js, abbiamo creato una funzione, chiamata createBox. Questo crea un corpo rettangolo statico.

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)

Box2DBody

UN Box2DBody ha alcune caratteristiche uniche:

  • Può essere statico (non influenzato dagli impatti delle collisioni), cinematico (non è influenzato dalle collisioni, ma può essere spostato dal mouse, ad esempio) o dinamico (interagisce con qualsiasi cosa)
  • Deve avere una definizione di forma e dovrebbe indicare come appare l'oggetto
  • Può avere più di un faro, che indica come l'oggetto interagirà con le collisioni
  • La sua posizione è impostata dal centro dell'oggetto, non dal bordo superiore sinistro come fanno molti altri motori.

Revisione del codice:

  1. Qui, creiamo una definizione di forma che sarà un quadrato o un rettangolo e imposteremo la sua densità (con quale frequenza verrà spostata, o ruotata per forza).
  2. Abbiamo installato il 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.
  3. Imposta metà della dimensione della mia scatola (è una linea dal punto di posizione, o il punto centrale dell'oggetto verso un angolo)
  4. Creiamo la definizione del corpo e aggiungiamo ad essa la definizione della forma della scatola.
  5. Imposta la posizione.
  6. Crea il corpo nel mondo e restituisci il suo valore.

Creazione del corpo della palla del giocatore

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?

  1. Crea la forma, il fissaggio e la definizione del sensore
  2. Crea la definizione del corpo
  3. Aggiungi al tuo corpo la forma, i dispositivi o i sensori (non spiegato in questo articolo)
  4. Crea il corpo nel mondo

Box2DCircle

Come ho notato prima, questo segue lo stesso processo di creazione di una scatola, ma ora devi impostare alcuni nuovi parametri.

  • raggio - Questa è la lunghezza di una linea dal centro del cerchio a qualsiasi punto sul suo bordo.
  • restituzione - Come la palla perderà, o guadagnerà forza quando si scontra con un altro corpo.
  • attrito - Come rotolerà la palla.

Box2DBody - Altre proprietà

  • smorzamento è usato per ridurre la velocità del corpo - c'è smorzamento angolare e smorzamento lineare.
  • dormire nella casella 2D, i corpi possono dormire per risolvere i problemi di prestazioni. Ad esempio, supponiamo stiate sviluppando un gioco platform e il livello è definito da uno schermo 6000x400. Perché è necessario eseguire la fisica per oggetti fuori dallo schermo? Non lo fai; questo è il punto! Quindi la scelta corretta è metterli a dormire e migliorare le prestazioni del tuo gioco.

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.


Passaggio 3: tempo di rendering

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); 

Cosa realizziamo qui:

  1. Insegnato a box2dWorld per eseguire simulazioni di fisica
  2. Schermo di tela cancellato e disegnare di nuovo
  3. Esegui il 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.


Step 4 - Interattività

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!


Passaggio 5: messaggio "You Win"

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; 
  • La prima condizione determina se il giocatore cade e deve essere riportato al punto di partenza (sopra la piattaforma ovest).
  • La seconda condizione controlla se il giocatore è sopra la seconda piattaforma e ha vinto la partita. Ecco il 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.