HTML5 vokser opp raskere enn noen kunne ha forestilt seg. Kraftige og profesjonelle løsninger utvikles allerede? selv i spillverdenen! Sjekk ut hundrevis av HMHTML5-spill på Envato Market.
I dag lager du ditt første spill ved hjelp av Box2D og HTML5 lerret
stikkord.
Box2D er en åpen kildekode og populær motor som simulerer 2D fysikk for å lage spill og applikasjoner. Primært skrevet i C ++, det har blitt konvertert til mange språk av samfunnsansatte.
Med samme metoder og objekter har du muligheten til å lage spillets fysikk på mange språk, for eksempel Mål C (iPhone / iPad), ActionScript 3.0 (Web), HTML 5 (Web), etc.
For å begynne å utvikle din demo, last ned Box2D-motoren for HTML5 her. Deretter oppretter du en ny HTML-fil med følgende struktur (kopier js og lib-kataloger fra box2d-js-prosjektet til spillmappen din).
Nå må du sette inn de nødvendige filene for å kjøre box2D i HTML-filen din:
Ja, det er et stort antall HTTP-forespørsler!
Vær oppmerksom på at for distribusjon anbefales det sterkt at du sammenkaller alle disse ressursene til en
manus
fil.
Deretter oppretter du to skript inni / Js /
mappe, kalt "box2dutils.js"
og "game.js"
.
box2dlib
, og er viktig for tegning av funksjoner (jeg vil også forklare noen viktige deler her).Kopier og lim inn følgende kode i box2dutils.js
. Ikke bekymre deg! Jeg skal forklare det litt etter litt!
funksjon drawWorld (verden, kontekst) for (var j = world.m_jointList; j; j = j.m_next) drawJoint (j, kontekst); for (var b = world.m_bodyList; b; b = b.m_next) for (var s = b.GetShapeList (); s! = null; s = s.GetNext ()) drawShape (s, kontekst) ; funksjon drawJoint (felles, kontekst) 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 (); bytt (joint.m_type) tilfelle b2Joint.e_distanceJoint: context.moveTo (p1.x, p1.y); context.lineTo (p2.x, p2.y); gå i stykker; tilfelle b2Joint.e_pulleyJoint: // TODO pause; standard: hvis (b1 == world.m_groundBody) context.moveTo (p1.x, p1.y); context.lineTo (x2.x, x2.y); annet hvis (b2 == world.m_groundBody) context.moveTo (p1.x, p1.y); context.lineTo (x1.x, x1.y); ellers context.moveTo (x1.x, x1.y); context.lineTo (p1.x, p1.y); context.lineTo (x2.x, x2.y); context.lineTo (p2.x, p2.y); gå i stykker; context.stroke (); funksjon drawShape (form, kontekst) context.strokeStyle = '# 000000'; context.beginPath (); bryter (shape.m_type) tilfelle b2Shape.e_circleShape: varcirkel = form; var pos = circle.m_position; var r = sirkel.m_radius; var segmenter = 16,0; var theta = 0,0; var dtheta = 2,0 * Math.PI / segmenter; // tegne sirkel context.moveTo (pos.x + r, pos.y); for (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)
Åpne index.html
fil som du tidligere har opprettet, og legg til en lerret
element (600x400) innenfor kropp
element. Dette er hvor vi skal jobbe med HTML5 tegning API:
Også, mens du er her, referanse game.js
og box2dutils.js
.
Det vil gjøre det for HTML! La oss jobbe med det morsomme JavaScript nå!
Åpen game.js
, og sett inn koden nedenfor:
// noen variabler som vi skal bruke i denne demoen var initId = 0; var spiller = funksjon () this.object = null; this.canJump = false; ; var verden; var ctx; var canvasWidth; var canvasheight; var keys = []; // HTML5 onLoad-hendelse Event.observe (vindu, last), funksjon () world = createWorld (); // box2DWorld ctx = $ ('spill'). GetContext ('2d'); // 2 var canvasElm = $ ('spill'); canvasWidth = parseInt (canvasElm.width); canvasHeight = parseInt (canvasElm.height); initGame (); // 3 trinn (); // 4 // 5 window.addEventListener ('keydown' handleKeyDown, true); window.addEventListener ('keyup', handleKeyUp, true););
Ok, la oss finne ut hva denne delen av koden gjør!
Box2DWorld er en av klassene som er tilgjengelig, via kjernen i box2d. Funksjonen er enkel: kombinere alt inn i en klasse. I box2DWorld har du kroppsdefinisjonen og kollisjonssjefen for spillet ditt eller programmet.
Hold game.js
og box2dutils.js
filer åpne, og søk etter createWorld ()
fungere innenfor box2dutils.js
.
funksjon createWorld () // her lager vi våre verdensinnstillinger for kollisjoner var worldAABB = new b2AABB (); worldAABB.minVertex.Set (-1000, -1000); worldAABB.maxVertex.Set (1000, 1000); // sett tyngdekraften vektor var tyngdekraften = ny b2Vec2 (0, 300); var doSleep = true; // init vår verden og returnere sin verdi var world = new b2World (worldAABB, gravity, doSleep); returnere verden;
Det er ganske enkelt å lage box2DWorld
.
game.js
Se de kommenterte tallene i de to blokkene med kode ovenfor. På nummer to, henter vi lerret
elementets kontekst ved hjelp av selector API (ser ut som jQuery eller MooTools selectors, ikke sant?). På nummer tre har vi en ny interessant funksjon: initGame ()
. Det er her vi skaper naturen.
Kopier og lim inn koden under i game.js
, og så vurderer vi det sammen.
funksjon initGame () // lage 2 store plattformer createBox (verden, 3, 230, 60, 180, true, 'ground'); createBox (world, 560, 360, 50, 50, true, 'ground'); // lage små plattformer for (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);Innsiden
funksjon createBox (verden, x, y, bredde, høyde, fast, userData) hvis (typeof (fast) == 'undefined') fast = true; // 1 var boxSd = ny b2BoxDef (); hvis (! fast) boxSd.density = 1.0; // 2 boxSd.userData = userData; // 3 boxSd.extents.Set (bredde, høyde); // 4 var boxBd = new b2BodyDef (); boxBd.AddShape (boxSd); // 5 boxBd.position.Set (x, y); // 6 return world.CreateBody (boxBd)box2dutils.js
, Vi har opprettet en funksjon, kaltcreateBox
. Dette skaper en statisk rektangel kropp.
Box2DBody
EN Box2DBody
har noen unike egenskaper:
brukerdata
, Vanligvis installerer du grafikkobjekter her, men i dette eksempelet installerer jeg bare strenger som vil være identifikatoren for typen objekt for kollisjoner. Denne parameteren påvirker ikke fysikkalgoritmer.Jeg har kodet spilleren (ball) direkte i game.js
fil. Det følger samme rekkefølge med å lage bokser, men denne gangen er det en ball.
var ballSd = ny b2CircleDef (); ballSd.density = 0,1; ballSd.radius = 12; ballSd.restitution = 0.5; ballSd.friction = 1; ballSd.userData = 'player'; var ballBd = ny b2BodyDef (); ballBd.linearDamping = .03; ballBd.allowSleep = false; ballBd.AddShape (ballSd); ballBd.position.Set (20,0); player.object = world.CreateBody (ballBd);
Så hvordan lager vi en kropp, trinnvis?
Box2DCircle
Som jeg nevnte tidligere, følger dette samme opprettelsesprosess med en boks, men nå må du sette noen nye parametere.
Box2DBody
- Flere eiendommerVi har allerede skapt vår verden; Du kan teste koden du har så langt. Du ser at spilleren faller over vestplattformen.
Nå, hvis du prøvde å kjøre demoen, bør du lure på hvorfor er siden så ufruktbar som hvitt papir?
Husk alltid: Box2D gjengir ikke; det beregner bare fysikk.
Deretter la oss gjengi box2DWorld.
Åpne din game.js
script, og legg til følgende kode:
funksjonstrinn () var stepping = false; var timeStep = 1,0 / 60; var iterasjon = 1; // 1 world.Step (timeStep, iterasjon); // 2 ctx.clearRect (0, 0, canvasWidth, canvasHeight); drawworld (verden, ctx); // 3 setTimeout ('step ()', 10);
skritt()
fungere igjen om ti millisekunder Med denne koden, jobber vi nå med fysikk og tegning. Du kan teste deg selv og se etter en fallende ball, som vist nedenfor:
drawWorld
i box2dutils.js
funksjon drawWorld (verden, kontekst) for (var j = world.m_jointList; j; j = j.m_next) drawJoint (j, kontekst); for (var b = world.m_bodyList; b; b = b.m_next) for (var s = b.GetShapeList (); s! = null; s = s.GetNext ()) drawShape (s, kontekst) ;
Hva vi har skrevet ovenfor, er en feilsøkingsfunksjon som trekker verden inn i lerretet, ved hjelp av grafikk-APIen som tilbys av HTML5s lærred API.
Den første sløyfen trekker alle leddene. Vi brukte ikke ledd i denne artikkelen. De er litt komplekse for en første demo, men likevel er de avgjørende for spillene dine. De lar deg lage veldig interessante kropper.
Den andre sløyfen trekker alle legemer, derfor er vi her!
funksjon drawShape (form, kontekst) context.strokeStyle = '# 000000'; context.beginPath (); bryter (shape.m_type) tilfelle b2Shape.e_circleShape: varcirkel = form; var pos = circle.m_position; var r = sirkel.m_radius; var segmenter = 16,0; var theta = 0,0; var dtheta = 2,0 * Math.PI / segmenter; // tegne sirkel context.moveTo (pos.x + r, pos.y); for (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();
Vi løper gjennom alle hjørner av objektet og tegner det med linjer (context.moveTo
og context.lineTo
). Nå er det nyttig å ha et eksempel? men ikke så nyttig i praksis. Når du bruker grafikk, trenger du bare å være oppmerksom på kroppens posisjonering. Du trenger ikke å løse hjørner, som denne demoen gjør.
Et spill uten interaktivitet er en film, og en film med interaktivitet er et spill.
La oss utvikle tastaturpilenes funksjonalitet for å hoppe og flytte ballen.
Legg til følgende kode i din game.js
fil:
funksjonshåndtakKeyDown (evt) keys [evt.keyCode] = true; funksjonshåndtakKeyUp (evt) keys [evt.keyCode] = false; // deaktiver vertikal rulling fra pilene :) document.onkeydown = function () return event.keyCode! = 38 && event.keyCode! = 40
Med handleKeyDown
og handleKeyUp
, vi setter opp en matrise
som sporer hver nøkkel brukeren skriver. Med document.onkeydown
, vi deaktiverer nettleserens opprinnelige vertikale rullefunksjon for opp- og nedpiler. Har du noen gang spilt et HTML5-spill, og når du hopper, går spilleren, fiender og gjenstander av skjermen? Det blir ikke et problem nå.
Legg til denne neste koden i begynnelsen av din skritt()
funksjon:
handleInteractions ();
Og utenfor, erklærer funksjonen:
funksjonshåndtakInteraksjoner () // opp pil // 1 var kollisjon = world.m_contactList; player.canJump = false; if (collision.GetShape1 (). GetUserData () == 'spiller' || collision.GetShape2 (). GetUserData () == 'spiller') if ((collision.GetShape1 () .GetUserData () == 'bakken' || collision.GetShape2 (). GetUserData () == 'bakken')) var playerObj = (collision.GetShape1 (). GetUserData () == 'spiller'? Kollisjon.GetShape1 () .GetPosition (): collision.GetShape2 (). GetPosition ()); var groundObj = (collision.GetShape1 (). GetUserData () == 'bakken'? Collision.GetShape1 (). GetPosition (): collision.GetShape2 (). GetPosition ()); hvis (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);
Den mest kompliserte delen av koden ovenfor er den første, der vi ser etter en kollisjon, og skriv noen forhold for å avgjøre om shape1
eller shape2
er spilleren. Hvis det er, bekrefter vi om shape1
eller shape2
er en bakke gjenstand
. Igjen, hvis ja, kolliderer spilleren med bakken. Deretter sjekker vi om spilleren er over bakken. Hvis det er tilfelle, kan spilleren hoppe.
På den andre kommenterte linjen (2) henter vi LinearVelocity
av spilleren.
Tredje og fjerde kommenterte regioner verifiserer om piler trykkes, og juster hastighetsvektoren, tilsvarende.
I den femte regionen installerer vi spilleren med den nye hastighetsvektoren.
Samspillet er nå gjort! Men det er ikke noe mål, vi hopper bare, hopper, hopper? og hopp!
Legg til koden nedenfor til begynnelsen av din LinearVelocity
funksjon:
hvis (player.object.GetCenterPosition (). y> canvasHeight) player.object.SetCenterPosition (ny b2Vec2 (20,0), 0) annet hvis (player.object.GetCenterPosition (). x> canvasWidth-50) showWin (); komme tilbake;
showWin ()
funksjon.funksjon showWin () ctx.fillStyle = '# 000'; ctx.font = '30px verdana'; ctx.textBaseline = 'top'; ctx.fillText ('Du! Du gjorde det!', 30, 0); ctx.fillText ('takk, andersonferminiano.com', 30, 30); ctx.fillText ('@ andferminiano', 30, 60);
Og det er det! Du har nettopp fullført ditt første enkle spill med HTML5 og Box2D. Gratulerer!
Hvis du trenger en enklere løsning, kan du sjekke ut valget av HTML5-spill på Envato Market, hvorav mange kommer med kildekoden for å undersøke og tilpasse for å passe dine behov.