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.
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
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
.
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.
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
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
.
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 afficher
de 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
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
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
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
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
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
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..
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
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
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
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.