Ooit een platformgame willen maken, maar niet al te graag alle code helemaal opnieuw willen schrijven? De Citrus Engine elimineert code niet volledig, maar het maakt het veel eenvoudiger, met veel nuttige 2D-gamefuncties ingebouwd. In deze tutorial gebruiken we het om een eenvoudig platformspel te bouwen.
In deze tutorial gebruiken we een populaire Flash Game Engine, Citrus genaamd, en een reeks ActionScript-klassen om een platformgame te maken.
Open Flash en maak een 420x280px-document. Stel de beeldsnelheid in op 30 fps.
We gebruiken deze geweldige pixelafbeeldingen van Guillaume Moreau. Je kunt ze downloaden van opengameart.org.
Verander voor de achtergrond de kleur van het werkgebied naar # 99D9EA, of gebruik het gereedschap Rechthoek (R) om een rechthoek van die kleur te tekenen.
Een waarschuwing wordt getoond wanneer de speler het level voltooit of sterft; het toont een game over het bericht en de score. Gebruik de Rechthoekgereedschap om het te maken en de naam van het exemplaar in te stellen AlertView. Markeer de Exporteren voor ActionScript vak en geef het dezelfde klassenaam.
Er zijn veel andere objecten in het spel (bijvoorbeeld: een titelscherm, de verschillende symbolen voor elke sprite, het terrein). In plaats van uit te leggen hoe ik ze hier moet maken, raad ik aan de bronbestanden te downloaden en te kijken welke objecten zich in de FLA-bibliotheek bevinden. Je kunt dezelfde symbolen gebruiken in je eigen spel, of nieuwe maken!
We gebruiken een bitmap-lettertype in het spel; omdat we het lettertype dynamisch gaan gebruiken, moeten we het in de applicatie insluiten. Ik gebruik de lettertypen 04b11 en Arcade Classic.
Selecteer een dynamisch tekstveld met het lettertype van uw voorkeur en klik op de Insluiten ... knop in de Eigenschappen paneel.
Selecteer / voeg alle benodigde tekens toe en klik op OK.
We gebruiken Geluidseffecten om het spelgevoel te verbeteren. De geluiden die in dit voorbeeld worden gebruikt, zijn gegenereerd met as3sfxr en zijn opgenomen in de bronbestanden.
We gebruiken een andere tween-engine dan de standaard in Flash. Dit verhoogt de prestaties en is gemakkelijker te gebruiken.
Je kunt TweenNano downloaden van de officiële website.
We zullen de Citrus Engine gebruiken om onze game van stroom te voorzien.
Wat is de Citrus Engine? Meer informatie op haar website:
De Citrus Engine is een professionele, schaalbare Flash-game-engine die is gebouwd voor spellen van industriekwaliteit. Het is gebaseerd op moderne Flash-programmeermethoden, zodat u zich kunt concentreren op het geweldig maken van uw spel! Het wordt ingebouwd met een "platformer" starterskit, waarmee je gemakkelijk fantastische 2D sidescrolling-spellen kunt maken.
Ga naar de downloadpagina en ontvang de benodigde bestanden. Open Flash-voorkeuren, selecteer ActionScript uit de lijst aan de linkerkant en klik op ActionScript 3.0-instellingen ... , voeg vervolgens het pad naar de bronnen toe zoals in de bovenstaande afbeelding.
We zullen onze applicatie interactief maken door een externe klasse te gebruiken. Voeg de naam toe (Hoofd
) naar de Klasse veld in de Publiceren deel van de eigenschappen panel om de FLA te koppelen aan de hoofddocumentklasse.
Maak een nieuwe ActionScript 3.0-klasse (Cmd + N) en sla deze op als Main.as in je klasmap.
Maak uw standaard klassenstructuur om te beginnen met het schrijven van uw code.
package public class Main public function Main (): void // constructor code
Main.as
De Hoofd
klasse bereidt de Citrus Engine voor op het eerste niveau.
pakket import com.citrusengine.core.CitrusEngine; publieke slotklasse Main verlengt CitrusEngine public final function Main (): void super (); state = nieuw niveau ();
Deze klasse breidt de CitrusEngine-klasse uit en stelt de "status" van het spel in Niveau, dat is de naam van de klas die het gedrag van al onze spellen bevat.
Level.as
De klasse State is een van de kernklassen van Citrus Engine en u moet deze klasse uitbreiden om de spellogica van uw niveaus of staten te maken. In dit voorbeeld de Niveau klasse breidt zich uit Staat om het eerste niveau van het spel te creëren.
Maak een nieuwe ActionScript 3.0-klasse (Cmd + N) en sla deze op als Level.as in je klasmap.
Dit zijn de klassen die we moeten importeren voor onze Niveau
klasse om te werken. De importeren
richtlijn maakt extern gedefinieerde klassen en pakketten beschikbaar voor uw code.
import flash.display.MovieClip; import flash.display.Sprite; import flash.events.MouseEvent; import com.citrusengine.core.CitrusEngine; import com.citrusengine.core.State; import com.citrusengine.physics.Box2D; import com.citrusengine.objects.platformer. *; import com.citrusengine.objects. *; import com.citrusengine.math.MathVector; import flash.events.Event; import flash.geom.Rectangle; import flash.ui.Keyboard; import flash.events.KeyboardEvent; import flash.text.TextField; import flash.text.TextFormat; import com.greensock.TweenNano; import com.greensock.easing.Expo; import flash.net.navigateToURL; import flash.net.URLRequest; import flash.filters.GlowFilter; import flash.filters.BitmapFilter;
Dit zijn de variabelen die we zullen gebruiken; lees de opmerkingen in de code om meer over hen te weten. (Sommige van hun namen spreken voor zich, dus er is geen commentaar.)
privé var-niveauBeeld: LevelView = nieuwe LevelView (); // sprite uit de bibliotheek private var hero: Hero; private var hearts: Vector.= nieuwe Vector. (); private var tf: TextFormat = new TextFormat ('ArcadeClassic', 17, 0xFFFFFF, null, null, null, null, null, 'right'); private var scoreTF: TextField = new TextField (); private var gemSnd: GemSnd = new GemSnd (); // Snd = Geluid private var goalSnd: GoalSnd = new GoalSnd (); private var hitSnd: HitSnd = new HitSnd (); private var jumpSnd: JumpSnd = new JumpSnd (); private var loseSnd: LoseSnd = new LoseSnd (); private var baddySnd: BaddySnd = new BaddySnd ();
De constructor is een functie die wordt uitgevoerd wanneer een object wordt gemaakt op basis van een klasse, deze code is de eerste die wordt uitgevoerd wanneer u een exemplaar van een object maakt, wordt geladen zodra het spel start als onderdeel van de documentklasse.
Het roept de nodige functies op om het spel te starten. Controleer die functies in de volgende stappen.
public final function Level (): void // Code
We beginnen met het pauzeren van het spel; dit voorkomt dat de engine de grafische weergave toevoegt terwijl de levelview-sprite zich op het podium bevindt.
public final function Level (): void super (); // standaard setup-code CitrusEngine.getInstance (). spelen = false; // game eigenlijk pauzeren
Hiermee wordt de sprit voor niveauweergave aan het podium toegevoegd, evenals een muisluisteraar om het te verwijderen.
override public function initialize (): void / * Level Start View * / addChild (levelView); levelView.addEventListener (MouseEvent.MOUSE_UP, startLevel);
De volgende functie wordt uitgevoerd wanneer op de niveauweergave wordt geklikt en de logica wordt verwerkt om het spel te starten.
private finale functie startLevel (e: MouseEvent): void
Deze code vernietigt de instantie Level View.
levelView.removeEventListener (MouseEvent.MOUSE_UP, startLevel); removeChild (levelView); levelView = null;
Nu pauzeren we het spel en initialiseren we het level.
super.initialize (); CitrusEngine.getInstance (). Spelen = waar;
De volgende code start de Box2D-engine die de physics van Citrus Engine verwerkt.
var box2D: Box2D = nieuwe Box2D ('Box2d'); toe te voegen (Box2D); //box2D.visible = true; // uncomment om de foutopsporingsgrafiek van Box2D te zien
Deze regels zullen het volledige niveau creëren, lees de code door om het Citrus Engine-instantiatiestelsel te begrijpen (wat heel gemakkelijk is!).
(Allemaal uitzicht
eigenschappen zijn de klassenamen van symbolen uit de FLA-bibliotheek: bg
, TerrainPart1
, WaterX3
, enz.)
var leftWall: Platform = nieuw platform ('LeftWall', width: 1, height: 280, x: 0, y: 110); toe te voegen (leftWall); var rightWall: Platform = nieuw platform ('RightWall', width: 1, height: 280, x: 726, y: 100); toe te voegen (rightWall); var bg: CitrusSprite = nieuwe CitrusSprite ('Bg', view: Bg, x: 0, y: 20); toe te voegen (bg); var terrain1: Platform = nieuw platform ('Terrain1', width: 422, height: 32, x: 211, y: 264, view: TerrainPart1); toe te voegen (terrain1); var oneWay1: Platform = nieuw platform ('OneWay1', width: 92, height: 32, x: 184, y: 232, oneWay: true, view: OneWay1); toe te voegen (oneWay1); var gem: Coin = new Coin ('Gem', width: 11, height: 10, x: 186, y: 136, view: Gem); toe te voegen (gem); var water: Sensor = nieuwe sensor ('Water', breedte: 92, hoogte: 32, x: 468, y: 264, weergave: WaterX3); Voeg water toe); var terrain2: Platform = nieuw Platform ('Terrain2', width: 214, height: 32, x: 621, y: 264, view: TerrainPart2); toe te voegen (terrain2); var baddy: Baddy = nieuwe Baddy ('Baddy', x: 300, y: 200, leftBound: 250, rightBound: 350, view: Enemy); toe te voegen (Baddy); var movingPlatform: MovingPlatform = nieuw MovingPlatform ('MP', width: 32, height: 8, x: 436, y: 232, startX: 436, startY: 232, endX: 500, endY: 232, view: PlatformClip, speed : 0,9); toe te voegen (movingPlatform); var oneWay2: Platform = nieuw platform ('OneWay2', width: 127, height: 32, x: 663, y: 232, oneWay: true, view: OneWay2); toe te voegen (oneWay2); var oneWay3: Platform = nieuw platform ('OneWay3', width: 64, height: 32, x: 695, y: 200, oneWay: true, view: OneWay3); toe te voegen (oneWay3); var deur: Sensor = nieuwe sensor ('Deur', breedte: 20, hoogte: 28, x: 695, y: 202, weergave: Deur); toe te voegen (deur); hero = new Hero ('Hero', x: 30, y: 234, width: 19, height: 26, view: HeroClip, jumpHeight: 9, maxVelocity: 2, hurtVelocityX: 2); toe te voegen (held);
Zoals u kunt zien, maakt u in elk geval een instantie van het type object dat u wilt en gebruikt u de parameters om de positie, grootte, afbeelding of skin (dit is de uitzicht parameter) en andere nuttige elementen. Dan voegen we het toe aan de Citrusfase met behulp van de toevoegen()
methode.
Laten we hier stoppen om een snelle test uit te voeren en ervoor te zorgen dat onze spelcode werkt:
Vergeet niet dat de mijlpalen zijn opgenomen in de bronbestanden, dus als dit om een of andere reden niet in dit bestand voorkomt, kijk dan eens naar de bron om te zien wat dat kan veroorzaken. (Houd er rekening mee dat sommige regels moeten worden becommentarieerd omdat sommige functies nog niet zijn gemaakt.)
Citrus Engine gebruikt signalen om interactie met het gebeurtenistype aan te kunnen. Je kunt meer leren over signalen op deze Activetuts + tutorial.
gem.onBeginContact.addOnce (function (e: *) gemSnd.play (); scoreTF.text = String (int (scoreTF.text) + 50);); door.onBeginContact.addOnce (levelComplete); hero.onTakeDamage.add (hurtHero); hero.onGiveDamage.addOnce (killBaddy); hero.onJump.add (functie () jumpSnd.play ()); hero.onGiveDamage.addOnce (functie () baddySnd.play ());
Onze Hero MovieClip wordt standaard afgespeeld, tenzij we dit voorkomen. Deze code verwerkt dat en u leert ook hoe u toegang krijgt tot de MovieClip die dient als de kunst voor uw Citrus-object.
this.view.getArt (held) .content.stop (); //State(Level).SpriteView.SpriteArt.MovieClip.stop gameListeners (); addIndicators ();
Deze code voegt de luisteraars van het EnterFrame en het toetsenbord toe die in onze game zullen worden gebruikt. U kunt in de volgende stappen over de bijbehorende afhandelingsfuncties lezen.
private slotfunctie gameListeners (actie: String = 'add'): void if (action == 'add') stage.addEventListener (Event.ENTER_FRAME, gameLogic); stage.addEventListener (KeyboardEvent.KEY_DOWN, animateWalk); stage.addEventListener (KeyboardEvent.KEY_UP, stopWalk); else stage.removeEventListener (Event.ENTER_FRAME, gameLogic); stage.removeEventListener (KeyboardEvent.KEY_DOWN, animateWalk); stage.removeEventListener (KeyboardEvent.KEY_UP, stopWalk);
Harten vertegenwoordigen de gezondheid van onze held. De volgende code voegt drie harten toe aan het podium en slaat ze op in een Vector om ze later buiten deze functie te gebruiken.
private laatste functie addIndicators (): void / * Hearts * / for (var i: int = 0; i < 3; i++) var heart:Heart = new Heart(); heart.y = 5; heart.x = 5 + (i * heart.width); addChild(heart); hearts.push(heart);
Het Score TextField wordt gemaakt door deze code. We gebruiken filters om de zwarte streek rond de letters toe te voegen.
/ * Score * / scoreTF.x = 320; scoreTF.defaultTextFormat = tf; scoreTF.text = '0'; var-filter: BitmapFilter = new GlowFilter (0, 1, 2, 2); var filter2: BitmapFilter = new GlowFilter (0, 1, 1, 1); scoreTF.filters = [filter, filter2]; addChild (scoreTF);
Hier zetten we de camera op, die onze held zal volgen als zijn positie voorbij het midden X van het podium is.
privé-eindfunctie gameLogic (e: Event): void / * Camera verwerken * / if (hero.x> = stage.stageWidth * 0.5) view.setupCamera (hero, nieuwe MathVector (stage.stageWidth * 0.5, 234), nieuwe Rectangle (0, 0, 726, 228), null);
Deze code controleert of onze held in het water is gevallen en zo ja, speelt hij het verlossende geluid af en roept hij een waarschuwing.
/ * Controleer of de held viel * / if (hero.y> stage.stageHeight) loseSnd.play (); alert ( 'verliezen');
Onze heldenloopanimatie wordt gestart wanneer de linker- of rechterpijltoetsen worden ingedrukt.
private finale functie animateWalk (e: KeyboardEvent): void if (e.keyCode == 37 || e.keyCode == 39) this.view.getArt (hero) .content.play ();
Wanneer de toetsen worden losgelaten, stopt de animatie.
private finale functie stopWalk (e: KeyboardEvent): void if (e.keyCode == 37 || e.keyCode == 39) this.view.getArt (hero) .content.gotoAndStop (1);
Laten we hier stoppen om nog een test uit te voeren en controleren of onze spelcode werkt:
Houd er nogmaals rekening mee dat sommige regels zijn becommentarieerd omdat nog niet alle functies zijn gemaakt.
Vergeet niet dat de mijlpalen zijn opgenomen in de bronbestanden, dus als dit om een of andere reden niet in dit bestand wordt nagebootst, kijk dan eens naar de bron om te zien wat dat zou kunnen veroorzaken.
De held moet schade oplopen als de slechterik hem raakt; de volgende regels verwijderen één hart en spelen het gewonde geluid. Er wordt een melding gegeven wanneer de held zijn gezondheid verliest.
private finale functie hurtHero (): void removeChild (hearts [hearts.length-1]); hearts.splice (hearts.length-1, 1); hitSnd.play (); if (hearts.length <= 0) loseSnd.play(); alert('lose');
Je kunt een slechterik doden door erop te springen. Wanneer dit gebeurt, neemt de score toe.
private final-functie killBaddy (): void scoreTF.text = String (int (scoreTF.text) + 100);
Het level eindigt wanneer de held de deur bereikt. Er wordt een geluid afgespeeld en er wordt een melding gegeven; je kunt de waarschuwingscode zien in de volgende stap.
private final function levelComplete (e: *): void goalSnd.play (); alert ();
Deze functie stopt het spel en toont het game-overbericht en voegt ook een muisluisteraar toe om het spel opnieuw in te stellen wanneer erop wordt geklikt.
private laatste functie alert (gameState: String = 'win'): void gameListeners ('rmv'); CitrusEngine.getInstance (). Spelen = false; this.view.getArt (held) .content.gotoAndStop (1); var alert: AlertView = nieuwe AlertView (); alert.x = stage.stageWidth * 0.5; alert.y = stage.stageHeight * 0.5; alert.scoreTF.text = score TF.text; alert.addEventListener (MouseEvent.MOUSE_UP, restart); if (gameState == 'lose') alert.titleTF.text = 'Level Failed!'; addChild (waarschuwing); TweenNano.from (alert, 0.6, scaleX: 0.2, scaleY: 0.2, ease: Expo.easeOut);
Met deze code wordt de SWF opnieuw geladen wanneer op het bericht wordt geklikt, waarbij alle oorspronkelijke waarden worden hersteld en het oorspronkelijke scherm wordt weergegeven.
privé laatste functie opnieuw opstarten (e: MouseEvent): void navigateToURL (nieuwe URLRequest (stage.loaderInfo.url), '_level0');
We zijn nu klaar om een laatste test voor onze game uit te voeren en te controleren of alles werkt zoals verwacht.
Experimenteer met deze krachtige game-engine en maak je eigen games!
Ik hoop dat je deze tutorial leuk vond, bedankt voor het lezen!