Dans ce tutoriel, je vais expliquer les principales étapes et le flux de travail pour la création d'un jeu de survie dans l'espace simple, basé sur le mécanisme de la gravité expliqué dans un précédent tutoriel. Ce jeu est écrit en AS3 avec FlashDevelop.
Utilisez les touches fléchées gauche et droite pour manœuvrer votre vaisseau, les touches fléchées haut et bas pour augmenter ou réduire le champ magnétique généré, et la barre d'espace pour inverser la polarité. Récupérez les cristaux blancs pour augmenter votre réserve de carburant - mais évitez les rouges, car ils l’utilisent. Ne pas frapper un rocher, ou c'est game over!
Dans ce tutoriel, nous ne créerons pas réellement le jeu complet affiché ci-dessus; nous allons juste commencer, en créant une version très simple avec des graphismes primitifs et un seul type d'objet. Cependant, à la fin, vous devriez avoir appris suffisamment pour pouvoir ajouter vous-même les autres fonctionnalités.!
Le jeu lui-même est très simple dans son état actuel - jetez un œil à cette critique pour obtenir des conseils sur la manière de passer d'une simple démo à un jeu complet.!
Configurer un nouveau projet AS3 dans FlashDevelop et définir ses dimensions à 550x600px.
package [SWF (width = "550", height = "600")] classe publique Main étend Sprite
Il y a six objets dans la particule que vous pouvez identifier en jouant au jeu ci-dessus:
Bien sûr, vous pouvez ajouter n'importe quel autre objet pour rendre le jeu plus interactif ou ajouter une nouvelle fonctionnalité. Pour ce tutoriel, nous allons simplement faire
Énergie
ClasseParmi les objets que nous avons identifiés, quatre d’entre eux fonctionnent exactement de la même manière: en tombant de haut en bas.
Elles sont:
Dans ce tutoriel, nous allons uniquement créer les objets "fourniture d'énergie", sur les quatre précédents. Commençons donc par créer ces objets et en les faisant tomber, avec une position et une vitesse de génération aléatoires..
Commencez par créer un Énergie
classe:
package import flash.display.MovieClip; import flash.events.Event; public class Energy s'étend sur MovieClip private var rSpeed: Number = 0; fonction publique Energy (speed: Number) graphics.beginFill (0x321312); graphics.drawCircle (0, 0, 8); rSpeed = speed; // nous appellerons cela chaque fonction publique function move (): void this.y + = rSpeed; // la vitesse de rotation est liée à la vitesse de déplacement this.rotation + = rSpeed / 8;
GameScreen
ClasseCette classe finira par contrôler la plupart des aspects de notre jeu, y compris le mouvement du joueur et la boucle du jeu..
Créez la classe:
package classe publique GameScreen étend MovieClip fonction publique GameScreen ()
C'est tout ce dont nous avons besoin pour l'instant.
Nous allons maintenant créer une instance de GameScreen
dans Principale
:
package import flash.display.Sprite; import flash.events.Event; [SWF (width = "550", height = "600")] La classe publique Main étend Sprite private var game: GameScreen; fonction publique Main (): void // ne pas afficher de rectangle jaune à l'écran au démarrage. stageFocusRect = false; game = new GameScreen (); addChild (jeu); // donne le focus clavier à l'écran de jeu immédiatement stage.focus = game;
Pourquoi s'embêter? Eh bien, de cette façon, il sera plus facile d'ajouter des écrans supplémentaires ultérieurement si nous le souhaitons (comme un préchargement, un écran de titre, un jeu sur écran…).
Pour éviter le GameScreen
la classe devenant trop désordonnée, nous utiliserons des classes séparées pour gérer chaque objet.
Chaque classe de gestionnaire contiendra toutes les fonctions qui se rapportent à un objet particulier et qui interagissent avec lui. Ici se trouve le EnergyManager
classe:
package import flash.display.MovieClip; public class EnergyManager // ce vecteur stockera toutes les instances de la classe énergétique private var energyList: Vector.var privéScreenScreen: GameScreen; fonction publique EnergyManager (gs: GameScreen) gameScreen = gs; energyList = nouveau vecteur. ;
Notez que nous avons besoin qu'une référence à GameScreen soit transmise au constructeur et nous stockons cette référence dans une variable privée. Nous avons également mis en place un vecteur pour stocker des références à tous les objets d'énergie.
Jusqu'à présent, la classe ne contient aucune autre fonction. nous les ajouterons plus tard.
Ajoutez la fonction ci-dessous pour créer de l’énergie, c’est juste une fonction; nous appellerons la fonction plus tard de GameScreen
Classe:
fonction publique createEnergy (number: int): void var energy: Energy; pour (var i: int = 0; i < number; i++) energy = new Energy(4); gameScreen.addEnergyToScreen(energy); energyList.push(energy); energy.x = Calculation.generateRandomValue(30, 520); energy.y = Calculation.generateRandomValue( -150, -20);
Nous créons une nouvelle source d’énergie avec une vitesse de 4, nous l’ajoutons à la liste d’affichage (via GameScreen), au vecteur de tous les objets d’énergie que nous venons de créer et définissons sa position à un point aléatoire dans certaines limites..
le Calculation.generateRandomValue (#, #)
est une fonction statique que nous n'avons pas encore écrite, faisons-le maintenant. Créez une nouvelle classe appelée Calcul
et ajoutez cette fonction:
Fonction statique publique generateRandomValue (min: Number, max: Number): Number var randomValue: Number = min + (Math.random () * (max - min)); return randomValue;
Cette fonction générera un nombre aléatoire entre les deux valeurs qui lui sont transmises. Pour plus d'informations sur son fonctionnement, consultez cette astuce. Comme il s’agit d’une fonction statique, il n’est pas nécessaire de créer une instance de Calcul
pour l'appeler.
Maintenant, qu'est-ce que c'est addEnergyToScreen ()
une fonction? Nous n'avons pas encore défini cela, alors faisons-le maintenant. Ajouter ceci à GameScreen
:
fonction publique addEnergyToScreen (énergie: énergie): void addChild (énergie);
Il ajoute simplement l'instance d'énergie passée à la liste d'affichage. Faisons également une fonction correspondante pour supprimer un objet d'énergie donné de l'écran:
fonction publique removeEnergyFromScreen (energy: Energy): void if (energy.parent == this) removeChild (énergie);
Définissons une minuterie qui définit l’intervalle pour chaque ponte. Ce code va dans GameScreen
Fonction constructeur de:
energyM = new EnergyManager (this); // n'oubliez pas de passer une référence à l'écran du jeu var spawnTimer: Timer = new Timer (3000, 0); spawnTimer.addEventListener (TimerEvent.TIMER, spawnEnergy); spawnTimer.start ();
Ainsi, toutes les trois secondes, la minuterie appellera spawnEnergy ()
. Écrivons cette fonction maintenant:
fonction privée spawnEnergy (e: TimerEvent): void energyM.createEnergy (4); // crée 4 énergies
Utilisons un autre cercle plus grand pour représenter le joueur. N'hésitez pas à importer une image à utiliser à la place:
fonction publique Player () graphics.beginFill (0x7ebff1); graphics.drawCircle (0, 0, 20);
Ajouter ce code à GameScreen
pour ajouter le joueur à l'écran:
// dans les définitions de variable public var player: Player;
// dans la fonction constructeur player = new Player; addChild (joueur); player.x = 275; player.y = 450;
Jusqu’à présent, nous devrions avoir quelques réserves d’énergie chutant quelques secondes, et le lecteur apparaît au milieu de l’écran:
Il y a fondamentalement deux manières d'appliquer le mouvement:
vrai
. Dans chaque mise à jour du cadre, "déplacer à droite" est vrai
, on augmente la valeur x de l'objet. Utilisation de la mise à jour directe de chaque image
- lorsque l'on appuie sur la touche fléchée droite, il est dit à un objet de se déplacer immédiatement à droite, en augmentant sa valeur x. La deuxième méthode ne permet pas un mouvement fluide lorsque la touche est enfoncée de manière continue, contrairement à la première méthode. Nous allons donc utiliser la première méthode..
Pour ce faire, vous devez suivre trois étapes simples:
private var moveRight: Boolean = false; private var moveLeft: Boolean = false;
addEventListener (Event.ENTER_FRAME, mise à jour); addEventListener (KeyboardEvent.KEY_DOWN, KeyDownHandler); addEventListener (KeyboardEvent.KEY_UP, KeyUpHandler); fonction privée KeyDownHandler (e: KeyboardEvent): void if (e.KeyCode == Keyboard.RIGHT) moveRight = true; if (e.keyCode == Keyboard.LEFT) moveLeft = true; if (e.keyCode == Keyboard.SPACE) if (isGravityPushing == true) isGravityPushing = false; else isGravityPushing = true; fonction privée KeyUpHandler (e: KeyboardEvent): void if (e.keyCode == Keyboard.RIGHT) moveRight = false; if (e.keyCode == Keyboard.LEFT) moveLeft = false;
N'oubliez pas de créer d'abord une fonction listen à partir de l'événement enter frame, "update":
// appelle cette fonction chaque mise à jour de la fonction privée du cadre (e: Event): void if (moveRight == true) player.x + = 6; if (moveLeft == true) player.x - = 6;
Gardez le joueur dans les limites de l'écran:
if (player.x> = 525) moveRight = false; if (player.x <= 20) moveLeft = false;
Voici à quoi ça ressemble, en place:
package import flash.display.MovieClip; import flash.events.Event; import flash.events.TimerEvent; importer flash.ui.Keyboard; import flash.utils.Timer; import flash.events.KeyboardEvent; classe publique GameScreen public var player: Player; private var energyM: EnergyManager; private var moveRight: Boolean = false; private var moveLeft: Boolean = false; private var isGravityPushing: Boolean = true; variable privée retournéePower: int = 0; private var scoreText: Texte; var privé totalScore: int = 0; score var privé: Texte; fonction publique GameScreen () scoreText = nouveau Texte ("Score:"); addChild (scoreText); energyM = new EnergyManager; var spawnTimer: Timer = new Timer (3000, 0); spawnTimer.addEventListener (TimerEvent.TIMER, spawnEnergy); spawnTimer.start (); joueur = nouveau joueur; addChild (joueur); player.x = 275; player.y = 450; addEventListener (Event.ENTER_FRAME, mise à jour); addEventListener (KeyboardEvent.KEY_DOWN, KeyDownHandler); addEventListener (KeyboardEvent.KEY_UP, KeyUpHandler); fonction privée KeyDownHandler (e: KeyboardEvent): void if (e.KeyCode == Keyboard.RIGHT) moveRight = true; if (e.keyCode == Keyboard.LEFT) moveLeft = true; if (e.keyCode == Keyboard.SPACE) if (isGravityPushing == true) isGravityPushing = false; else if (isGravityPushing == false) isGravityPushing = true; fonction privée KeyUpHandler (e: KeyboardEvent): void if (e.keyCode == Keyboard.RIGHT) moveRight = false; if (e.keyCode == Keyboard.LEFT) moveLeft = false; mise à jour de fonction privée (e: Event): void if (player.x> = 525) moveRight = false; if (player.x <= 20) moveLeft = false; if (moveRight == true) player.x += 6; if (moveLeft == true) player.x -= 6;
Pour le moment, les réserves d'énergie sont en train de se reproduire mais ne bougent pas. Nous allons utiliser le GameScreen.update ()
fonction pour les faire bouger, car il exécute chaque image.
Ajouter ce code à GameScreen.update ()
:
energyM.moveAll (); // fera bouger chaque objet énergétique
Maintenant, bien sûr, nous devons faire le EnergyManager.moveAll ()
fonction, alors ajoutez ceci à EnergyManager.as
:
fonction publique moveAll (): void for (var i: int = 0; i < energyList.length; i++) var energyS:Energy = energyList[i]; energyS.move();
Nous devrons vérifier les collisions entre chaque objet d’énergie et le joueur. (Si vous développez davantage le jeu, vous devrez vérifier cela pour les astéroïdes et les consommateurs d'énergie, mais pas pour les étoiles.)
Le meilleur endroit pour gérer ces contrôles est à l’intérieur du EnergyManager
, déclenché chaque image par le GameScreen
.
Une chose à considérer: les contrôles de collision se feront entre deux cercles, donc hitTestObject ()
n'est pas idéal. Au lieu de cela, nous utiliserons la méthode décrite dans ce tutoriel..
Nous pouvons écrire la fonction comme ci-dessous:
fonction publique checkCollision (p: Player): int // énergie transférée en raison d'une collision var energyTransfer: int = 0; pour (var i: int = 0; i < energyList.length; i++) var energyS:Energy = energyList[i]; var newX:Number = p.x - energyS.x; var newY:Number = p.y - energyS.y; var distance:Number = Math.sqrt(newX * newX + newY * newY); if (distance <= 28) gameScreen.removeEnergyFromScreen(energyS); energyList.splice(i, 1); // for this simple game, we'll always transfer 1 unit // but you could alter this based on speed of collision // or any other factor energyTransfer = 1; return energyTransfer;
Energie
est l'abréviation de Energy Supply.Vous pouvez modifier la ligne 51 en energyTransfer + = 1
, pour permettre au joueur d'absorber plus d'un objet d'énergie à la fois. C'est à vous de l'essayer et voir comment cela affecte le jeu..
Nous devons vérifier les collisions à chaque image, nous devrions donc appeler la fonction que nous venons d'écrire GameScreen.update ()
.
Tout d'abord, nous devons créer une variable entière pour stocker la valeur de transfert d'énergie à partir de la fonction de détection de collision. Nous utiliserons cette valeur pour augmenter l'énergie du vaisseau et augmenter le score du joueur..
variable privée retournéePower: int = 0;
returnPower = energyM.checkCollision (lecteur);
Avant de commencer à créer le mécanisme de jeu pour les fonctions "Push" et "Pull" du navire, je voudrais présenter le concept de physique sur lequel repose le mécanisme..
L'idée est d'attirer l'objet vers le joueur à l'aide d'un Obliger. La loi de la gravitation universelle de Newton nous donne une grande (et simple) formule mathématique que nous pouvons utiliser pour cela, où la force est bien sûr la force gravitationnelle:
G n’est qu’un nombre et nous pouvons le régler comme bon nous semble. De même, nous pouvons définir les masses de chaque objet du jeu avec les valeurs que nous aimons. La gravité se produit sur des distances infinies, mais dans notre jeu, nous aurons un point de coupure (indiqué par le cercle blanc dans la démonstration depuis le début du didacticiel)..
Les deux choses les plus importantes à noter à propos de cette formule sont:
Avant de commencer à coder les mécanismes de jeu pour les fonctions 'Push' et 'Pull', clarifions ce que nous voulons qu'il fasse:
Nous voulons essentiellement que A (le joueur) exerce une certaine force sur B (un cristal) et déplace B vers A en fonction de cette force..
Nous devrions revoir quelques concepts:
Math.atan2 (B.y - A.y, B.x - A.x)
.B.x + = (Force * Math.cos (angle));
B.y + = (Force * Math.sin (angle));
Pour plus d'informations, consultez les didacticiels Gravity in Action et Trigonométrie pour les développeurs de jeux Flash..
Sur la base de l'explication précédente, nous pouvons élaborer un plan pour notre code qui attire chaque cristal sur le navire:
Exemple de code:
fonction publique gravityPull (p: Player): void pour (var i: int = 0; i < energyList.length; i++) var energyS:Energy = energyList[i]; var nX:Number = (p.x - energyS.x); var nY:Number = (p.y - energyS.y); var angle:Number = Math.atan2(nY, nX); var r:Number = Math.sqrt(nX * nX + nY * nY); if (r <= 250) var f:Number = (4 * 50 * 10) / (r * r); energyS.x += f * Math.cos(angle); energyS.y += f * Math.sin(angle);
Voici un timelapse montrant à quoi cela ressemble:
Notez que l’énergie se déplace plus rapidement à mesure qu’on se rapproche du navire, grâce au terme r-carré.
Nous pouvons implémenter la fonction de poussée simplement en rendant la force négative:
fonction publique gravityPull (p: Player): void pour (var i: int = 0; i < energyList.length; i++) var energyS:Energy = energyList[i]; var nX:Number = (p.x - energyS.x); var nY:Number = (p.y - energyS.y); var angle:Number = Math.atan2(nY, nX); var r:Number = Math.sqrt(nX * nX + nY * nY); if (r <= 250) var f:Number = (4 * 50 * 10) / (r * r); energyS.x -= f * Math.cos(angle); energyS.y -= f * Math.sin(angle);
Ici, l’objet se déplace plus lentement à mesure qu’il s’éloigne du joueur, car la force s’affaiblit..
Bien sûr, vous aurez besoin de cette fonction pour exécuter chaque image par GameScreen
- mais avant cela, nous devrons utiliser une fonction booléenne pour basculer entre les deux fonctions:
private var isGravityPushing: Boolean = true; // frapper l'espace le fait basculer
Nous allons utiliser true pour 'Push' et false pour 'Pull'.
À l'intérieur KeyDownHandler ()
:
if (e.keyCode == Keyboard.SPACE) if (isGravityPushing == true) isGravityPushing = false; else if (isGravityPushing == false) isGravityPushing = true;
Ensuite, vous devrez vérifier la valeur booléenne de chaque image. Ajouter ceci à mettre à jour()
:
if (isGravityPushing == true) energyM.gravityPull (player); if (isGravityPushing == false) energyM.gravityPush (joueur);
Vous trouverez peut-être que le mouvement n'a pas l'air si beau. Cela pourrait être dû au fait que la force n’est pas tout à fait idéale ou au terme r-carré.
Je voudrais changer la formule comme suit:
var f: nombre = (0,8 * 50 * 10) / r;
Comme vous pouvez le constater, j'ai réduit la valeur de "G" à 0,8 et modifié la force pour qu'elle dépende simplement de la distance entre les objets, plutôt que de la distance au carré..
Essayez-le et voyez si vous aimez le changement. Vous pouvez toujours le modifier comme bon vous semble.
Nous devrons afficher du texte à l'écran pour indiquer le score et la puissance restante du navire..
Pour cela, nous allons construire une nouvelle classe, Texte
:
package import flash.display.MovieClip; import flash.text.TextField; import flash.events.Event; import flash.text.TextFormat; import flash.text.TextFormatAlign; public class Text étend MovieClip public var _scoreText: TextField = new TextField (); fonction publique Text (string: String) var myScoreFormat: TextFormat = new TextFormat (); // Format modifiable myScoreFormat.size = 24; myScoreFormat.align = TextFormatAlign.LEFT; myScoreFormat.color = (0x131313); _scoreText.defaultTextFormat = myScoreFormat; _scoreText.text = string; addChild (_scoreText); fonction publique updateText (string: String) _scoreText.text = string;
C'est très simple; c'est essentiellement un MovieClip avec un champ de texte à l'intérieur.
Pour relever le défi, nous allons utiliser la puissance du vaisseau lentement, de sorte que le joueur doit collecter des objets énergétiques pour se recharger..
Pour que la puissance du navire apparaisse sur le navire lui-même, nous pouvons simplement ajouter un exemple de Texte
à la liste d'affichage de l'objet navire.
Déclarez ces variables dans le Navire
classe:
public var totalPower: Number = 100; // navire commence avec cette quantité d'énergie privée var powerText: Text;
Nous devrons maintenir la quantité d’énergie (stockée et affichée) mise à jour chaque image, ajoutez donc cette nouvelle fonction à Joueur
:
Tout d'abord, dans le constructeur:
// ajoute un nouvel objet texte s'il n'existe pas déjà si (! powerText) powerText = new Text (String (int (totalPower))); addChild (powerText); powerText.x - = 20; // Ajuster la position powerText.y - = 16;
Et alors…
public function updatePower (): void // fps = 24, la puissance diminue donc de 1 / sec totalPower - = 1/24; powerText.updateText (String (int (totalPower)));
La puissance diminuera chaque image de 1/24 de unité, ce qui signifie qu’elle diminuera d’une unité complète toutes les secondes..
Nous devons faire cette course chaque image, alors ajoutez cette ligne à GameScreen.update ()
:
player.updatePower ();
Lorsque le navire entre en collision avec un objet énergétique, nous voulons qu'il augmente sa puissance.
Dans GameScreen.update ()
, ajoutez la ligne en surbrillance:
returnPower = energyM.checkCollision (lecteur); player.totalPower + = returnPower;
N'oubliez pas que vous pouvez modifier la quantité d'énergie renvoyée dans le EnergyManager.checkCollision ()
une fonction.
Encore une fois, nous aurons besoin de la classe de texte. Cette fois, nous allons afficher "Score", puis la valeur.
Ici, nous aurons besoin de trois autres variables:
Déclarez-les dans GameScreen
classe:
private var scoreText: Texte; var privé totalScore: int = 0; score var privé: Texte;
Dans le constructeur, ajoutez ce code:
scoreText = nouveau texte ("Score:"); addChild (scoreText); score = nouveau texte (String (totalScore)); addChild (score); score.x = scoreText.x + 100; // Le positionner à côté du texte "Score:". score.y + = 2;
Maintenant, dans le mettre à jour()
fonction, ajoutez ceci:
score.updateText (String (totalScore));
Ça y est - nous avons créé une version de base du jeu ci-dessus!
Jetez un oeil (vous devrez peut-être recharger la page):
Peut-être aimeriez-vous aussi un fond avec une image incorporée et des étoiles. Ajoutez ceci à votre Principale
classe:
[Incorporer (source = "/… /lib/SpaceBackground.jpg")] // incorporer une variable privée backgroundImage: Class; // Cette ligne doit venir immédiatement après l'intégration de la variable privée bgImage: Bitmap = new backgroundImage (); private var numOfStars: int = 70;
Maintenant, créez le Étoile
classe:
actifs du package import flash.display.MovieClip; import flash.events.Event; Classe publique Star étend MovieClip private var speed: Number; fonction publique Star (alpha: Number, size: Number, speed1: Number) graphics.beginFill (0xCCCCCC); graphics.drawCircle (0, 0, taille); vitesse = vitesse1; // assurez-vous d'appeler cette fonction privée de chaque cadre moveDown (): void this.y + = speed; si (this.y> = 600) this.y = 0;
dans le Principale()
constructeur, ajoutez ceci pour créer les étoiles:
pour (var i: int = 0; i < numOfStars; i++) createStars();
Voici le réel createStars ()
une fonction:
fonction privée createStars (): void var étoile: étoile = nouvelle étoile (Math.random (), Calculations.getRandomValue (1, 2), Calculations.getRandomValue (2, 5)); // alpha aléatoire, taille et vitesse addChild (star); star.x = Calculations.getRandomValue (0, 550); star.y = Calculations.getRandomValue (0, 600);
Avec un alpha, une taille, une position et une vitesse aléatoires, un arrière-plan pseudo-3D peut être généré..
Un cercle d'indicateur de distance peut être créé simplement en créant un autre cercle et en l'ajoutant à la liste d'affichage du navire, exactement comme vous avez ajouté le texte du témoin de puissance. Assurez-vous que le cercle est centré sur le navire et que son rayon est égal à la portée du navire..
Ajoutez de la transparence (valeur alpha) au cercle avec le code ci-dessous:
graphics.beginFill (0xCCCCCC, 0.1);
Essayez d’ajouter des commandes supplémentaires qui augmentent ou diminuent la portée lorsque vous appuyez sur les touches fléchées haut et bas..
J'espère que vous avez apprécié ce tutoriel! S'il vous plaît laissez vos commentaires.
Suivant: Lisez cette critique pour un guide sur la transformation de Flux d’une simple démo en jeu complet.!