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.
Bekijk het resultaat waar we naartoe werken:
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.
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:
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).
Het eerste dat we moeten doen is de
Schiet ze op
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.
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.
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 bgImage
De 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.
Eén ding is de HTML5
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.
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!