Créer un jeu de combat aérien dans Corona plus de jeu

Ce que vous allez créer

introduction

Dans le tutoriel précédent de cette série, nous avions commencé à implémenter le gameplay du jeu et avions déjà réussi à faire bouger l'avion à l'écran. Dans ce tutoriel, nous allons continuer à implémenter le gameplay. Let's plonger directement dans le startTimers une fonction.

1. startTimers

Comme son nom l'indique, le startTimers fonction démarre les minuteries. Ajoutez le code suivant à gamelevel.lua.

fonction startTimers () end

Invoquer cette fonction dans le enterScene méthode comme indiqué ci-dessous.

scène de fonction: enterScene (événement) local planeSound = audio.loadStream ("planesound.mp3") planeSoundChannel = audio.play (planeSound, boucles = -1) Durée d'exécution: addEventListener ("enterFrame", gameLoop) startTimers () end

2. firePlayerBullet

le firePlayerBullet fonction crée une balle pour le joueur.

fonction firePlayerBullet () tempBullet local = display.newImage ("bullet.png", (player.x + playerWidth / 2) - bulletWidth, player.y-bulletHeight) table.insert (playerBullets, tempBullet); planeGroup: insert (tempBullet) end 

Ici nous utilisons l'objet Display Nouvelle image méthode pour créer la balle. Nous le positionnons de manière à ce qu'il se trouve au centre du plan sur l'axe des x et tout en haut du plan sur l'axe des y. La balle est ensuite insérée dans le playerBullets tableau pour référence ultérieure et aussi dans le planeGroup.

3. appeler firePlayerBullet

Nous devons appeler le firePlayerBullet fonctionner périodiquement pour s'assurer que l'avion du joueur tire automatiquement des balles. Ajoutez l'extrait de code suivant dans le startTimers une fonction.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) fin

Comme son nom l'indique, le minuteur performWithDelay méthode appelle une fonction spécifiée après une période donnée. Le temps est en millisecondes, alors nous appelons le firePlayerBullet fonctionner toutes les deux secondes. En passant -1 comme troisième argument, la minuterie se répètera pour toujours.

Si vous testez le jeu maintenant, vous devriez voir toutes les deux secondes une balle apparaître. Cependant, ils ne bougent pas encore. Nous nous en occuperons dans les prochaines étapes.

4. movePlayerBullets

Dans movePlayerBullets, nous parcourons le playerBullets table et changer le y coordonnée de chaque balle. Nous vérifions d’abord pour nous assurer que le playerBullets la table contient des balles. le # avant playerBullets est appelé le longueur opérateur et renvoie la longueur de l'objet sur lequel il est appelé. Il est utile de savoir que le # opérateur travaille également sur des chaînes.

function movePlayerBullets () if (#playerBullets> 0), puis pour i = 1, # playerBullets utilise playerBullets [i]. y = playerBullets [i] .y - 7 end end end

Nous devons invoquer movePlayerBullets dans le gameLoop fonctionne comme indiqué ci-dessous.

fonction gameLoop () --SNIP-- numberOfTicks = numberOfTicks + 1 movePlayer () movePlayerBullets () end

5. checkPlayerBulletsOutOfBounds

Quand une balle sort de l'écran, cela n'a plus d'importance pour le jeu. Cependant, ils font toujours partie de la playerBullets table et continuer à se déplacer comme toute autre balle dans la table. C'est un gaspillage de ressources et, si le jeu devait durer très longtemps, il en résulterait des centaines ou des milliers d'objets inutilisés..

Pour résoudre ce problème, nous surveillons les balles et, une fois celles-ci sorties de l'écran, nous les retirons de l'écran. playerBullets table ainsi que de l'affichage. Jetez un coup d’œil à la mise en œuvre de checkPlayerBulletsOutOfBounds.

function checkPlayerBulletsOutOfBounds () if (#playerBullets> 0), puis pour i = # playerBullets, 1, -1 à faire si (playerBullets [i] .y < -18) then playerBullets[i]:removeSelf() playerBullets[i] = nil table.remove(playerBullets,i) end end end end

Il est important de noter que nous parcourons le playerBullets table à l'envers. Si nous parcourons la table en boucle, lorsque nous supprimons une des puces, l’index de la boucle est renvoyé et provoque une erreur. En boucle sur la table dans l'ordre inverse, la dernière puce est déjà traitée. le se supprimer méthode supprime l'objet d'affichage et libère sa mémoire. Il est recommandé de définir tous les objets sur néant après avoir appelé se supprimer.

Nous invoquons cette fonction dans le gameLoop une fonction.

fonction gameLoop () --SNIP-- movePlayer () movePlayerBullets () checkPlayerBulletsOutOfBounds () end

Si vous voulez voir si cette fonction fonctionne correctement, vous pouvez insérer temporairement un print ("Suppression d'une balle") déclaration immédiatement après le paramétrage de l'objet d'affichage néant.

6. générerIsland

Pour rendre le jeu plus intéressant, nous générons une île de temps en temps et la déplaçons vers le bas de l'écran pour donner l'apparence de l'avion survolant les îles. Ajoutez l'extrait de code suivant pour le générerIsland une fonction.

function generateIsland () local tempIsland = display.newImage ("island1.png", math.random (0, display.contentWidth - islandWidth), - islandHeight) table.insert (îles, tempIsland) islandGroup: insert (tempIsland) end

Nous utilisons le Nouvelle image méthode une fois de plus et positionner l'île en définissant une valeur négative pour la îleHauteur. Pour le X position, nous utilisons le math.random méthode pour générer un nombre entre 0 et le afficherde contentWidth moins le islandWidth. La raison pour laquelle nous soustrayons la largeur de l'île est de nous assurer que l'île est complètement à l'écran. Si nous ne soustrayions pas la largeur de l'île, il y aurait une chance qu'une partie de l'île ne soit pas affichée à l'écran.

Nous devons démarrer une minuterie pour générer une île de temps en temps. Ajoutez l'extrait suivant au startTimers fonction que nous avons créée plus tôt. Comme vous pouvez le constater, nous générons une île tous lescinq secondes. Dans l'étape suivante, nous ferons bouger les îles.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) generateIslandTimer = timer.performWithDelay (5000, generateIsland, -1) fin

7. moveIslands

L'implémentation de moveIslands est presque identique à la movePlayerBullets une fonction. Nous vérifions si le îles table contient toutes les îles et, si tel est le cas, nous les parcourons en boucle et déplaçons chaque île un peu.

function moveIslands () if (#islands> 0) alors pour i = 1, #islands ne îles [i] .y = îles [i] .y + 3 fin fin fin

8. checkIslandsOutOfBounds

Tout comme nous vérifions si les balles du joueur sont sorties de l'écran, nous vérifions si l'une des îles était passée à l'écran. L'implémentation de checkIslandsOutOfBounds devrait donc vous paraître familier. Nous vérifions si les îles y la position est supérieure à display.contentHeight et si c'est le cas, nous savons que l'île est sortie de l'écran et peut donc être supprimée..

function checkIslandsOutOfBounds () if (#islands> 0) alors pour i = # îles, 1, -1 faire si (îles [i] .y> display.contentHeight) puis îles [i]: removeSelf () îles [i] = nil table.remove (islands, i) fin fin fin fin

9. générerFreeLife

De temps en temps, le joueur a une chance d'avoir une vie gratuite. Nous générons d'abord une image de vie gratuite et si le joueur entre en collision avec l'image, il a une vie supplémentaire. Le joueur peut avoir un maximum de six vies.

function generateFreeLife () if (numberOfLives> = 6), puis retourne fin local freeLife = display.newImage ("newlife.png", math.random (0, display.contentWidth - 40), 0); table.insert (freeLifes, freeLife) planeGroup: insert (freeLife) end 

Si le joueur a déjà six vies, nous ne faisons rien en revenant plus tôt que prévu. Sinon, nous créons une nouvelle image de la vie et l'ajoutons à l'écran. Semblable à la façon dont nous avons positionné les îles plus tôt, nous définissons l'image à un négatif y positionner et générer une valeur aléatoire pour l'image X position. Nous l'insérons ensuite dans le freeLifes tableau pour pouvoir le référencer plus tard.

Nous devons appeler cette fonction de temps en temps. Ajoutez l'extrait suivant au startTimers une fonction.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) generateIslandTimer = timer.performWithDelay (5000, generateIsland, -1) generateFreeLifeTimer = timer.performWithDelay (7000, generateFreeLife, - 1) fin

dix. moveFreeLives

L'implémentation de moveFreeLifes devrait sembler familier. Nous parcourons le freeLifes table et déplace chaque image.

function moveFreeLifes () if (#freeLifes> 0) alors pour i = 1, # freeLifes est gratuit, que ce soit freeLifes [i] .y = freeLifes [i] .y +5 end end end

Il suffit d'appeler moveFreeLifes dans le gameLoop une fonction.

fonction gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () end

11. checkFreeLifesOutOfBounds

L'extrait de code suivant devrait également vous paraître familier maintenant. Nous vérifions si l’une des images dans le freeLifes table se sont déplacés hors de l'écran et retirez ceux qui ont.

function checkFreeLifesOutOfBounds () if (#freeLifes> 0), puis pour i = # freeLifes, 1, -1 faire si (freeLifes [i] .y> display.contentHeight) alors freeLifes [i]: removeSelf () freeLifes [i] = nil table.remove (freeLifes, i) fin fin fin fin 

Nous appelons cette fonction dans le gameLoop une fonction.

fonction gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () checkFreeLifesOutOfBounds () end

12. hasCollided

Nous devons être en mesure de savoir quand les objets du jeu entrent en collision, tels que l'avion du joueur et les images de la vie libre, les balles et les avions, etc. Corona offre un moteur physique très robuste capable de gérer facilement les collisions entre les objets d'affichage. pour nous, cela ajoute un peu de surcharge aux calculs que le moteur doit faire à chaque image.

Pour les besoins de ce jeu, nous utiliserons un système simple de détection de collision par cadre de sélection. Cette fonction permet de s’assurer que les rectangles ou les cadres de sélection entourant deux objets ne se chevauchent pas. S'ils le font, les objets entrent en collision. Cette logique est implémentée dans le hasCollided une fonction.

function hasCollided (obj1, obj2) if (obj1 == nil), puis retourne false fin si (obj2 == nil), puis retourne false fin local gauche = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin droit local = obj1.contentBounds.xMin> = obj2.contentBounds.xMin et obj1.contentBounds.xMin <= obj2.contentBounds.xMax local up = obj1.contentBounds.yMin <= obj2.contentBounds.yMin and obj1.contentBounds.yMax >= obj2.contentBounds.yMin local bas = obj1.contentBounds.yMin> = obj2.contentBounds.yMin et obj1.contentBounds.yMin <= obj2.contentBounds.yMax return (left or right) and (up or down) end

J'ai trouvé cet extrait de code sur le site Web CoronaLabs. Cela fonctionne vraiment bien, parce que les objets du jeu dans notre jeu sont rectangulaires. Si vous travaillez avec des objets qui ne sont pas rectangulaires, vous feriez mieux de tirer parti du moteur physique de Corona car sa détection de collision est très bien optimisée pour cela..

13. checkPlayerCollidesWithFreeLife

Nous voulons vérifier si l'avion du joueur est entré en collision avec un objet de la vie libre. Si tel est le cas, nous accordons au joueur une vie gratuite..

function checkPlayerCollidesWithFreeLife () if (#freeLifes> 0) puis pour i = # freeLifes, 1, -1 do if (hasCollided (freeLifes [i], lecteur)), puis freeLifes [i]: removeSelf () freeLifes [i] = nil table.remove (freeLifes, i) numberOfLives = numberOfLives + 1 hideLives () showLives () end end end end

dans le checkPlayerCollidesWithFreeLife fonction, nous parcourons le freeLives table à l'envers pour la même raison que j'ai décrite plus tôt. Nous appelons le hasCollided fonction et passer dans l'image en cours et le plan du joueur. Si les deux objets entrent en collision, on enlève l'image de la vie libre, on incrémente la nombre de vies variable et appelez le hideLives et showLives une fonction.

Nous invoquons cette fonction dans le gameLoop une fonction.

fonction gameLoop () --SNIP-- moveFreeLifes () checkFreeLifesOutOfBounds () checkPlayerCollidesWithFreeLife () end

14. hideLives

le hideLives fonction en boucle à travers le livesImages table et définit le est visible propriété de chaque image de la vie à faux.

function hideLives () pour i = 1, 6 ne vit livesImages [i] .isVisible = faux fin fin 

15. showLives

le showLives fonction en boucle à travers le livesImages table et définit chaque image est visible propriété à vrai.

function showLives () pour i = 1, numberOfLives ne vit livesImages [i] .isVisible = true; fin fin

Conclusion

Ceci met fin à la troisième partie de cette série. Dans la prochaine et dernière tranche de cette série, nous allons créer des avions ennemis et finaliser le gameplay du jeu. Merci de m'avoir lu et à bientôt.