En la parte anterior de esta serie, conseguimos que la nave del jugador se moviera, movimos a los invasores y detectamos cuando una bala de jugador había golpeado a un invasor. En esta parte final de la serie, conseguiremos que los invasores ataquen al jugador, manejen los niveles y añadan la capacidad para que el jugador muera..
De vez en cuando uno de los invasores dispara una bala. Vamos a utilizar un temporizador para lograr esto. Agregue el siguiente código a gamelevel.lua.
function fireInvaderBullet () if (#invadersWhoCanFire> 0) y luego randomIndex local = math.random (#invadersWhoCanFire) local randomInvader = invadersWhoCanFire [randomIndex]. invaderSize / 2) tempInvaderBullet.name = "invaderBullet" scene.view: inserte (tempInvaderBullet) physics.addBody (tempInvaderBullet, "dynamic") table.insert (invaderBullets, tempInvaderBullet) else levelComplete () end end end
En esta función, primero verificamos si el InvadersWhoCanFire
La tabla tiene al menos un elemento en ella. Si ese es el caso, entonces ejecutamos el código en la sentencia if. De lo contrario, significa que el nivel ha terminado e invocamos el Nivel completado
función.
Siempre habrá al menos un invasor que puede disparar una bala hasta que mates al último invasor, en cuyo punto el InvadersWhoCanFire
la mesa estará vacía.
Dentro de la sentencia if, generamos un número aleatorio. randomIndex
dependiendo de cuantos elementos hay en el InvadersWhoCanFire
mesa. Entonces elegimos ese artículo, randomInvader
, desde el InvadersWhoCanFire
mesa.
Creamos una imagen de bala, le damos una nombre
propiedad para poder identificarla más adelante, insertarla en la escena y establecer las mismas propiedades que hicimos en la bala del jugador. Finalmente, insertamos la bala en el invaderBullets
mesa para que podamos consultarla más tarde.
Ahora tenemos que configurar el temporizador. Agregue lo siguiente a la escena: show
método.
escena de la función: show (evento) if (phase == "did") entonces --SNIP-- Runtime: addEventListener ("collision", onCollision) invaderFireTimer = timer.performWithDelay (1500, fireInvaderBullet, -1) end end
Cada 1500 milisegundos fireInvaderBullet
se invoca Tenga en cuenta que el último parámetro que pasamos es -1
, lo que significa que el temporizador se repite para siempre. Siempre que cree un temporizador que se repita para siempre, debe cancelarlo. Hacemos esto en elescena: ocultar
funciona como se muestra a continuación.
escena de la función: ocultar (evento) si (fase == "será") entonces --SNIP-- Tiempo de ejecución: eliminarEventListener ("colisión", onCollision) timer.cancel (invaderFireTimer) end end
Al igual que las balas del jugador, las balas de los invasores se moverán fuera de la pantalla y se mantendrán en movimiento, ocupando valiosa memoria. Para remediar esto, los eliminamos tal como lo hicimos con las balas del jugador..
function checkInvaderBulletsOutOfBounds () if (#invaderBullets> 0) luego para i = # invaderBullets, 1, -1 do if (invaderBullets [i] .y> display.contentHeight) luego invaderBullets [i]: removeSelf () invaderBullets [i] = nil table.remove (invaderBullets, i) end end end end end
Este código es muy similar a verificar si las balas del jugador están fuera de límites, por lo que no discutiré su implementación en detalle.
El siguiente paso es detectar si la bala de un invasor ha golpeado al jugador. Agregue el siguiente código a la onCollision
función.
función onCollision (evento) si (evento.fase == "comenzó") luego --SNIP-- si (evento.objeto1.nombre == "jugador" y evento.objeto.nombre == "invaderBullet") entonces tabla.remove (invaderBullets, table.indexOf (invaderBullets, event.object2)) event.object2: removeSelf () event.object2 = nil if (playerIsInvincible == false) luego killPlayer () end devuelve end if if (event.object1.name == " invaderBullet "y event.object2.name ==" player ") luego table.remove (invaderBullets, table.indexOf (invaderBullets, event.object1)) event.object1: removeSelf () event.object1 = nil if (playerIsInvincible == false ) entonces killPlayer () end return end end end end end
Como antes, no sabemos qué objeto. event.object1
y event.object2
Será así que usaremos dos declaraciones if para comprobar ambas situaciones. Quitamos la bala del invasor de la invaderBullets
mesa, sáquela de la pantalla y ajústela a nulo
. Si el jugador no es invencible, lo matamos..
Cuando matamos al jugador, le damos un corto tiempo de invencibilidad. Esto le da al usuario tiempo para recuperar el enfoque en el juego. Si el número de vidas
variable es igual a 0
, Sabemos que el juego ha terminado y la transición a la comienzo Escena donde el usuario puede comenzar un nuevo juego..
function killPlayer () numberOfLives = numberOfLives- 1; if (numberOfLives) <= 0) then gameData.invaderNum = 1 composer.gotoScene("start") else playerIsInvincible = true spawnNewPlayer() end end
los spawnNewPlayer
La función hace que el reproductor aparezca y desaparezca durante unos segundos. Es un buen efecto para que el usuario sepa que el barco es invencible temporalmente.
function spawnNewPlayer () número localOfTimesToFadePlayer = 5 número localOfTimesPlayerHasFaded = 0 función local fadePlayer () player.alpha = 0; transition.to (jugador, tiempo = 400, alfa = 1,) numberOfTimesPlayerHasFaded = número de puntos de juego, juego de cartas, juego de cartas, juego de cartas, y más (más)
Utilizamos una función local., fadePlayer
, que utiliza la biblioteca de transición para modificar el alfa
valor de la jugador
. Hacemos un seguimiento de cuántas veces el jugador
se ha desvanecido dentro y fuera, y establece la invencibilidad del jugador en falso
una vez que alcancemos el numberOfTimesToFadePlayer
. Usamos un temporizador para llamar al fadePlayer
Funciona para sin embargo muchas veces numberOfTimesToFadePlayer
es igual a.
Ejecutar el juego para probar esto. los jugador
Debería morir cuando la bala de un invasor golpea la nave. Si tres balas golpean el barco, deberías ser llevado a la comienzo Escena donde puedes comenzar un nuevo juego..
Para hacer esto más fácil de probar, comente la llamada a mover los invasores
en el gameLoop
funciona como se muestra a continuación.
function gameLoop () checkPlayerBulletsOutOfBounds () --moveInvaders () checkInvaderBulletsOutOfBounds () end
Si has logrado matar a todos los invasores, el juego habría llamado Nivel completado
Función, que aún no existe. Vamos a arreglar eso. Agregue el siguiente bloque de código.
function levelComplete () gameData.invaderNum = gameData.invaderNum + 1 if (gameData.invaderNum <= gameData.maxLevels) then composer.gotoScene("gameover") else gameData.invaderNum = 1 composer.gotoScene("start") end end
Nosotros incrementamos gameData.invaderNum
y, si es menor que gameData.maxLevels
, hacemos la transición al juego terminado escena. De lo contrario, el jugador ha completado todos los niveles y reiniciamos. gameData.invaderNum
a 1. Hacemos la transición al comienzo Escena donde el jugador puede comenzar un nuevo juego..
Una forma fácil de probar esto es comentando la llamada a mover los invasores
en el gameLoop
Funciona y usa los botones para mover la nave. Si eso sigue siendo demasiado difícil, también puede comentar las dos llamadas a killPlayer
en el onCollision
método.
Agregue el siguiente código a gameover.lua para implementar el juego sobre escena.
local composer = require ("composer") local scene = composer.newScene () local starFieldGenerator = require ("starfieldgenerator") local pulsatingText = require ("pulsatingtext") local nextLevelButton local starGenerator function scene: create (event) local group = self .view starGenerator = starFieldGenerator.new (200, group, 5) local invadersText = pulsatingText.new ("LEVEL COMPLETE", display.contentCenterX, display.contentCenterY-200, "Conquest", 20, group) invadersText: setColor (1, 1, 1) invadersText: pulsate () nextLevelButton = display.newImage ("next_level_btn.png", display.contentCenterX, display.contentCenterY) grupo: inserte (nextLevelButton) grupo de función: show (evento) local phase = event.phase composer .removeScene ("gamelevel") if (phase == "did") y luego nextLevelButton: addEventListener ("tap", startNewGame) Runtime: addEventListener ("enterFrame", starGenerator) final End escena escena: ocultar (evento) local fase fase = evento .phase if (phase == "will") luego Runtime: removeEventListener ("enterF rame ", starGenerator) nextLevelButton: removeEventListener (" tap ", startNewGame) end end end function startNewGame () composer.gotoScene (" gamelevel ") end scene: addEventListener (" create ", scene) scene: addEventListener (" show ", scene) scene: addEventListener ("hide", scene) return scene
Este código es muy similar al comienzo escena por lo que debe estar familiarizado con ella por ahora.
La última verificación de colisión que debemos realizar es una colisión entre el jugador y uno de los invasores. Agregue el siguiente bloque de código a la onCollision
método que vimos antes.
función onCollision (evento) --SNIP-- si (evento.fase == "comenzó") entonces --SNIP-- si (evento.objeto1.nombre == "jugador" y evento.objeto2.nombre == "invasor" ) entonces numberOfLives = 0 killPlayer () finaliza si (event.object1.name == "invader" y event.object2.name == "player") entonces numberOfLives = 0 killPlayer () end end end
Como de costumbre, necesitamos revisar ambas situaciones de colisión. Establecemos el número de vidas
a 0 y llama killPlayer
. Configurando número de vidas
a 0 e invocando killPlayer
, El juego ha terminado y el juego pasa a la comienzo escena.
Esto completa nuestro juego, pero te sugiero que intentes expandir el juego con algunas características adicionales. Por ejemplo, podría mostrar la vida del jugador en un HUD.
También he incluido un gráfico OVNI en los archivos de origen. Puedes intentar que aparezca un OVNI al azar y si el jugador lo golpea con una bala, dale una vida extra.
Si necesita ayuda con estos conceptos, consulte mi serie de juegos de combate de aviones en Tuts+.
Si has seguido esta serie, entonces deberías tener un juego completamente funcional similar al Space Invaders original. Expande y hazlo tuyo. Espero que hayas encontrado este tutorial útil y hayas aprendido algunas técnicas nuevas. Gracias por leer.