Game-menu's en schermovergangen animeren in HTML5 een handleiding voor Flash-ontwikkelaars

HTML5- en Flash-ontwikkeling kunnen veel gemeen hebben, maar als een Flash-ontwikkelaar heb ik het nog steeds als een enorme opgave gevonden om mijn oude vaardigheden in HTML5 opnieuw te leren. In deze zelfstudie laat ik je zien hoe ik een geanimeerd menu en een schermovergang heb gemaakt voor een HTML5-shoot-'em-up-game.


Eindresultaat voorbeeld

Bekijk het resultaat waar we naartoe werken:


Klik om de demo te proberen

Let op de scrollende achtergrond, de schepen die verschijnen en draai aan elke kant van elk menu-item, en de manier waarop het scherm vervaagt naar zwart wanneer u een optie selecteert.


Invoering

HTML5 en JavaScript lijken op veel verschillende manieren op ActionScript; er is veel overlap in syntaxis, gebeurtenislisteners en methoden. Er zijn echter enkele zeer duidelijke verschillen die ik in deze tutorial zal behandelen:

  • Vormen tekenen
  • Afbeeldingen tekenen
  • Intervallen gebruiken
  • animeren
  • Muis evenementen
  • Ondersteuning toevoegen voor meerdere browsers

Iets om op te merken is dat deze tutorial voornamelijk afbeeldingen gebruikt die kunnen worden gedownload met de bron of u kunt uw eigen afbeeldingen gebruiken als u wilt (u moet de breedte en hoogte weten).


Stap 1: instellen

Het eerste dat we moeten doen is de element in de body van een HTML-bestand, dus maak er een aan ShootEmUp.html en voeg het volgende in:

    Schiet ze op    

Uw browser ondersteunt geen HTML5!

De gemarkeerde lijnen voegen het canvaselement toe, dat ons eigenlijke menu zal weergeven. Zie deze tutorial voor een handleiding voor canvas helemaal opnieuw.

Het is al bijna tijd om JavaScript te gaan coderen! We hebben twee opties waar de code naartoe kan gaan; Het kan binnen in de HTML worden geschreven

Onze volgende stap is om vier variabelen te maken om gemakkelijk naar het canvaselement te verwijzen.

 var canvas = document.getElementById ("myCanvas"); var context = canvas.getContext ("2d"); var width = canvas.getAttribute ('width'); var height = canvas.getAttribute ('height');

We hebben eerst verwezen naar de myCanvas variabele en stel deze zo in dat deze naar het HTML-canvaselement verwijst. Een andere variabele met de naam context is gemaakt om de canvas-dimensionaliteit (2D) te krijgen. Net als bij Flash maken we de laatste twee variabelen, breedte en hoogte, om het proces van toegang tot de eigenschappen width en height van het canvas te vereenvoudigen.


Stap 2: Afbeeldingen laden en tekenen

Net als in ActionScript gaan we exemplaren van onze afbeeldingen maken.

 var bgImage = new Image (); var logoImage = new Image (); var playImage = new Image (); var instructImage = new Image (); var settingsImage = new Image (); var creditsImage = new Image (); var shipImage = new Image ();

We missen een cruciaal stuk code voor elk exemplaar - het bronpad! Ik heb alle afbeeldingen in de map 'Afbeeldingen' opgeslagen in dezelfde map als het HTML-bestand, dus:

 shipImage.src = "Images / ship.png"; bgImage.src = "Images / Background.png"; logoImage.src = "Images / logo.png"; playImage.src = "Images / play.png"; instructImage.src = "Images / instructions.png"; settingsImage.src = "Images / settings.png"; creditsImage.src = "Images / credits.png";

Voordat we de afbeeldingen naar het canvas tekenen, maken we vier arrays om de posities en groottes van de knoppen vast te houden (playImage, instructImage, settingsImage, creditsImage). Deze arrays zullen later worden gebruikt om een ​​mouse over-functie te creëren.

 var-knop X = [192,110,149,160]; var-knopY = [100,140,180,220]; var buttonWidth = [96,260,182,160]; var buttonHeight = [40,40,40,40];

Nu kunnen we de afbeeldingen naar het canvas tekenen; dit kan binnen een onload functie voor elke afbeelding, maar een onload-functie hoeft niet te worden opgenomen - we kunnen gewoon gebruiken drawImage ().

 bgImage.onload = function () context.drawImage (bg Image, 0, 0); ; logoImage.onload = function () context.drawImage (logoImage, 50, -10);  playImage.onload = function () context.drawImage (playImage, buttonX [0], button Y [0]);  instructImage.onload = function () context.drawImage (instructImage, knop X [1], knop Y [1]);  settingsImage.onload = function () context.drawImage (settingsImage, buttonX [2], buttonY [2]);  creditsImage.onload = function () context.drawImage (creditsImage, buttonX [3], buttonY [3]); 

Als het nu wordt getest, zou je een statisch beeld moeten zien van een menu dat we binnenkort zullen inademen. Het schip is niet bij de rest van de afbeeldingen betrokken omdat we het later in een muisgebeurtenis zullen tekenen. Trouwens, als je dit tot nu toe niet hebt gedaan, houd je variabelen bovenaan gegroepeerd en doe je hetzelfde met functies.


Stap 3: Animeren door intervallen

JavaScript mist een onEnterFrame () equivalent, maar we kunnen gemakkelijk onze eigen creëren door het gebruik van een interval (timer).

 var-frames = 30; var timerId = 0; timerId = setInterval (update, 1000 / frames);

U kunt in de war raken over hoe het interval werkt, dus ik zal het in het kort uitleggen. Het interval roept de functie op bijwerken() elke (1000 /frames) milliseconden om een ​​vloeiende verversingssnelheid te creëren. De waarde van frames bestuurt de fps; als frames is 25, dan probeert de browser te bellen bijwerken() elke (1000/25 =) 40 milliseconden.

Onze volgende voor de hand liggende stap is om de functie te maken bijwerken()

 functie-update () wissen (); bewegen (); trek(); 

Er werden nog drie functies genoemd. duidelijk() wordt gebruikt om het canvas te wissen, omdat het canvas in tegenstelling tot flash werkt als stickers op een bord plaatsen; de afbeeldingen kunnen niet worden verplaatst nadat ze zijn geplaatst. De volgende functie, bewegen (), wordt gebruikt voor het wijzigen van de variabelewaarden die worden gebruikt met de afbeeldingen. Tenslotte trek() is geroepen om die "stickers" te plaatsen.

 function clear () context.clearRect (0, 0, width, height); 

Simpel gezegd wist deze code alles binnen de rechthoek die de grootte van het canvas is en wordt getrokken uit (0,0), de linkerbovenhoek. Dat betekent dat het het volledige zichtbare canvas opruimt.

Voordat we naar de volgende functie gaan, moeten twee variabelen worden geïntroduceerd. backgroundY is de variabele voor de y-positie van de achtergrondafbeelding en snelheid zal worden gebruikt om van af te trekken backgroundY elke updatecyclus.

 var backgroundY = 0; var snelheid = 1;

Het effect dat we gaan produceren is een continu scrollende achtergrond. Het beeld bestaat uit twee identieke starfield-afbeeldingen, de een boven de ander, in een grotere afbeelding (de afbeelding is tweemaal de hoogte van het canvas). We zullen het beeld langzaam omhoog verplaatsen tot de tweede helft volledig in beeld is en dan zullen we de positie van het beeld terugzetten naar de eerste helft.

 functie verplaatsen () backgroundY - = snelheid; if (backgroundY == -1 * height) backgroundY = 0; 

Eindelijk hebben we de trek() functie. Alle afbeeldingen worden opnieuw getekend, maar een verandering om op te merken is dat de bgImageDe y-waarde is vervangen door de variabele backgroundY.

 context.drawImage (bgImage, 0, backgroundY); context.drawImage (logoImage, 50, -10); context.drawImage (playImage, buttonX [0], buttonY [0]); context.drawImage (instructImage, knop X [1], knop Y [1]); context.drawImage (settingsImage, buttonX [2], buttonY [2]); context.drawImage (creditsImage, buttonX [3], buttonY [3]);

Test nu en bewonder de soepele scrollende achtergrond.


Stap 4: De muispositie controleren

Eén ding is de HTML5 ontbreekt, is ondersteuning voor luisteraars voor beeldgebeurtenissen, wat betekent dat we niet zomaar kunnen schrijven playImage.mouseover = function () . In plaats daarvan moeten we de positie van de muis ten opzichte van het canvas bepalen en uitzoeken of het zich boven een object bevindt.

 var mouseX; var muis; canvas.addEventListener ("mousemove", checkPos);

De twee geïntroduceerde variabelen zullen worden gebruikt om de huidige positie van de muis te krijgen. We hebben een gebeurtenislistener toegevoegd, zoals in ActionScript, die de functie aanroept checkPos () elke keer dat de muis beweegt.

 function checkPos (mouseEvent) mouseX = mouseEvent.pageX - this.offsetLeft; mouseY = mouseEvent.pageY - this.offsetTop; 

Als u de waarden van hebt gewaarschuwd mouseX en mouseY elke keer dat u de muis verplaatst, krijgt u de juiste positie. Maar er is één probleem: niet alle moderne desktopbrowsers ondersteunen deze methode. Om dit probleem te verhelpen, kunnen we de kleine hack gebruiken:

 if (mouseEvent.pageX || mouseEvent.pageY == 0) mouseX = mouseEvent.pageX - this.offsetLeft; mouseY = mouseEvent.pageY - this.offsetTop;  else if (mouseEvent.offsetX || mouseEvent.offsetY == 0) mouseX = mouseEvent.offsetX; mouseY = mouseEvent.offsetY; 

Hiermee wordt gecontroleerd of de browser de eigenschappen 'pagina' of 'offset' gebruikt om de positie van de muis te retourneren en de waarden aan te passen (indien nodig) om de positie van de muis ten opzichte van het canvas te bepalen.

Herinner je je dat schip dat we hebben geopend, maar niet getekend? We gaan dat statische beeld nemen, het draaien en het laten verschijnen telkens wanneer we met de muis over de knoppen gaan!

 var shipX = [0,0]; var shipY = [0,0]; var shipWidth = 35; var shipHeight = 40; var shipVisible = false; var shipSize = shipWidth; var shipRotate = 0;

De eerste vier variabelen zijn hetzelfde als voorheen (we hebben twee posities omdat er twee schepen zullen zijn). De shipVisible variabele zal worden ingesteld als de muis zich boven een knop bevindt. Wat betreft shipSize en shipRotate, ze zullen worden gebruikt om het schip verticaal te schalen en het te herpositioneren om de illusie te geven dat het draait. Houd er rekening mee dat afbeeldingen van rechts naar links worden geschaald.

 voor (i = 0; i < buttonX.length; i++) if(mouseX > buttonX [i] && mouseX < buttonX[i] + buttonWidth[i]) if(mouseY > buttonY [i] && mouseY < buttonY[i] + buttonHeight[i])  else  

Voeg de code toe in de checkPos () functie. Eerst fietsen we door de knoppen die er zijn (ik heb de waarde bepaald met behulp van buttonX.length). Vervolgens vergelijken we het mouseX om te zien of het groter is dan de huidige knoppen buttonX en minder dan zijn knop X + knop Breedte - d.w.z. binnen de horizontale grenzen van de knop. Vervolgens herhalen we het proces in een andere if-instructie voor de Y-waarden. Als dit allemaal waar is, moet de muis zich boven een knop bevinden, dus instellen shipVisible naar waar:

 shipVisible = true;

En binnen het lege anders statement ingesteld vals; het wordt dan elke keer dat je de muis uit een knop haalt opgeroepen:

 shipVisible = false;

Onder shipVisible = true we zullen de beginwaarden voor de instellen shipX en shipY, en voer alle schaalvergroting uit binnen de verplaatsings- en tekenfuncties.

 shipX [0] = buttonX [i] - (shipWidth / 2) - 2; SHIPY [0] = knop Y [i] + 2; shipX [1] = buttonX [i] + buttonWidth [i] + (shipWidth / 2); shipY [1] = button Y [i] + 2;

Voor het eerst shipX, die we net links van de knop willen plaatsen, stellen we de waarde in op (de huidige knop is X - de helft van de scheepsbreedte) en ik heb deze over 2 pixels naar links verplaatst om deze er beter uit te laten zien. Een soortgelijk proces wordt voor de eerste herhaald shipY. Voor de tweede shipX we positioneren op de (huidige knop is X + de breedte van die knop + de helft van de scheepsbreedte), en dan stellen we de Y als eerder in.

Het lastige gedeelte komt nu. We moeten het schip schalen en verplaatsen om de schaal te compenseren. Binnen de bewegen () functie schrijf dit als uitspraak.

 if (shipSize == shipWidth) shipRotate = -1;  if (shipSize == 0) shipRotate = 1;  shipSize + = shipRotate;

De code begint met het aftrekken van de waarde van shipSize, die zal worden gebruikt om het beeld te schalen wanneer we het tekenen; zodra het nul bereikt, keert het proces terug totdat het weer op volle schaal is.

Nu kunnen we naar de trek() functie. Onder alle andere tekenmethoden voegt u het volgende if-statement toe.

 if (shipVisible == true) context.drawImage (shipImage, shipX [0] - (shipSize / 2), shipY [0], shipSize, shipHeight); context.drawImage (shipImage, shipX [1] - (shipSize / 2), shipY [1], shipSize, shipHeight); 

De schepen worden normaal getekend, met uitzondering van de X-posities die worden gecompenseerd door de helft van de huidige schaal af te trekken.


Stap 5: Controleren op muisklikken

Voeg nog een gebeurtenislistener toe voor mouseup en maak een nieuwe variabele aan voor een tweede interval dat we zullen maken.

 var fadeId = 0; canvas.addEventListener ("mouseup", checkClick);

Maak de functie checkClick ().

 functie checkClick (mouseEvent) for (i = 0; i < buttonX.length; i++) if(mouseX > buttonX [i] && mouseX < buttonX[i] + buttonWidth[i]) if(mouseY > buttonY [i] && mouseY < buttonY[i] + buttonHeight[i])    

Zoals eerder, controleren we of de positie van de muis correct is. Nu moeten we het nieuwe interval maken en de andere interval- en gebeurtenislisteners stoppen.

 fadeId = setInterval ("fadeOut ()", 1000 / frames); clearInterval (timerID); canvas.removeEventListener ("mousemove", checkPos); canvas.removeEventListener ("mouseup", checkClick);

Niets nieuws hier, behalve dat we een functie moeten maken genaamd Fadeout (). We moeten ook een andere variabele maken die wordt genoemd tijd.

 var time = 0,0;
 function fadeOut () context.fillStyle = "rgba (0,0,0, 0,2)"; context.fillRect (0, 0, width, height); tijd + = 0,1; if (tijd> = 2) clearInterval (fadeId); tijd = 0; timerId = setInterval ("update ()", 1000 / frames); canvas.addEventListener ("mousemove", checkPos); canvas.addEventListener ("mouseup", checkClick); 

Het heeft een aantal nieuwe methoden, maar het is vrij eenvoudig. Omdat we alle luisteraars van het evenement en het andere interval hebben gestopt, is ons menu volledig statisch. Dus we trekken herhaaldelijk een transparante zwarte rechthoek boven op het menu - zonder deze op te ruimen - om de illusie te geven dat het langzaam verdwijnt.

De variabele tijd wordt verhoogd telkens wanneer de functie wordt aangeroepen en zodra deze een bepaalde waarde bereikt (als er 20 "frames" zijn gepasseerd, in dit geval), wissen we het huidige interval. Hier reset ik het menu, maar hier zou je een nieuw gedeelte van het menu tekenen.

Een laatste ding om op te merken is dat wanneer je vormen tekent op het canvas de fillStyle is ingesteld met een rgb (rood, groen, blauw) waarde. Als je transparante vormen wilt tekenen, gebruik je rgba (rood, groen, blauw, alpha).

Ik hoop dat het een beetje van het leerproces voor het overstappen van eenvoudige AS3-programmering naar eenvoudige canvas-programmering is gedemystificeerd. Plaats een opmerking als je vragen hebt!