Crea un juego de combate de aviones en Corona más jugabilidad

Lo que vas a crear

Introducción

En el tutorial anterior de esta serie, comenzamos a implementar el juego del juego y ya conseguimos que el avión se moviera por la pantalla. En este tutorial, continuaremos implementando el juego. Vamos a sumergirnos en el startTimers función.

1. startTimers

Como su nombre lo indica, el startTimers La función inicia los temporizadores. Agregue el siguiente código a gamelevel.lua.

función startTimers () end

Invoca esta función en el enterScene método como se muestra a continuación.

escena de la función: enterScene (evento) local planeSound = audio.loadStream ("planesound.mp3") planeSoundChannel = audio.play (planeSound, loops = -1) Runtime: addEventListener ("enterFrame", gameLoop) startTimers () end

2. firePlayerBullet

los firePlayerBullet La función crea una bala para el jugador..

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

Aquí utilizamos el objeto Display. nueva imagen Método para crear la bala. Lo colocamos de tal manera que esté en el centro del plano en el eje x y en la parte superior del plano en el eje y. La bala se inserta en el jugadorBullets mesa para referencia posterior y también en el grupo de aviones.

3. Llamando firePlayerBullet

Necesitamos llamar al firePlayerBullet funciona periódicamente para asegurarte de que el avión del jugador dispara balas automáticamente. Agregue el siguiente fragmento de código en el startTimers función.

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

Como su nombre lo indica, el temporizador realizar con demora El método llama a una función específica después de un período de tiempo. El tiempo es en milisegundos, así que aquí estamos llamando al firePlayerBullet Funciona cada dos segundos. Pasando -1 Como tercer argumento, el temporizador se repetirá para siempre..

Si prueba el juego ahora, debería ver que cada dos segundos aparece una bala. Sin embargo, todavía no se están moviendo. Nos encargaremos de eso en los próximos pasos..

4. movePlayerBullets

En movePlayerBullets, recorremos el jugadorBullets tabla y cambiar la y coordenada de cada bala. Primero revisamos para asegurarnos de que el jugadorBullets La mesa tiene balas en ella. los # antes de jugadorBullets se llama el longitud operador y devuelve la longitud del objeto al que se llama. Es útil saber que el # operador también trabaja en cadenas.

función movePlayerBullets () si (#playerBullets> 0) entonces para i = 1, # playerBullets do playerBullets [i]. y = playerBullets [i] .y - 7 end end end end

Necesitamos invocar movePlayerBullets en el gameLoop funciona como se muestra a continuación.

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

5. checkPlayerBulletsOutOfBounds

Cuando una bala sale de la pantalla, ya no es relevante para el juego. Sin embargo, todavía son parte de la jugadorBullets Tabla y continúe moviéndose como cualquier otra bala en la tabla. Esto es un desperdicio de recursos y, si el juego continuara por mucho tiempo, resultaría en cientos o miles de objetos no utilizados..

Para superar esto, monitoreamos las balas y, una vez que se mueven fuera de la pantalla, las eliminamos del jugadorBullets mesa, así como a partir de la pantalla. Eche un vistazo a la implementación de checkPlayerBulletsOutOfBounds.

function checkPlayerBulletsOutOfBounds () if (#playerBullets> 0) luego para i = # playerBullets, 1, -1 do if (playerBullets [i] .y < -18) then playerBullets[i]:removeSelf() playerBullets[i] = nil table.remove(playerBullets,i) end end end end

Es importante tener en cuenta que estamos recorriendo el jugadorBullets Mesa al revés. Si recorramos la tabla hacia adelante, entonces, cuando eliminamos una de las viñetas, el índice de bucle se desactivará y se producirá un error. Al pasar por encima de la tabla en orden inverso, la última viñeta ya está procesada. los quitarse El método elimina el objeto de visualización y libera su memoria. Como práctica recomendada, debe establecer cualquier objeto nulo después de llamar quitarse.

Invocamos esta función en el gameLoop función.

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

Si desea ver si esta función funciona correctamente, puede insertar temporalmente un imprimir ("Eliminación de viñetas") declaración inmediatamente después de configurar el objeto de visualización para nulo.

6. generarIsla

Para hacer que el juego sea más interesante, generamos una isla de vez en cuando y la movemos hacia abajo en la pantalla para dar la apariencia del avión que vuela sobre las islas. Agregue el siguiente fragmento de código para el generarIsla función.

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

Hacemos uso de la nueva imagen Método una vez más y posicionar la isla mediante el establecimiento de un valor negativo para el isla altura. Para el X posición, usamos el math.random método para generar un número entre 0 y el monitores contenido ancho menos el Isla Ancho. La razón por la que restamos el ancho de la isla es para asegurarnos de que esté completamente en la pantalla. Si no restáramos el ancho de la isla, habría una posibilidad de que parte de la isla no estuviera en la pantalla..

Necesitamos iniciar un temporizador para generar una isla de vez en cuando. Agregue el siguiente fragmento de código al startTimers función que creamos anteriormente. Como puedes ver, estamos generando una isla cadacinco segundos. En el siguiente paso, haremos que las islas se muevan..

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

7. moverIslas

La implementación de moverIslas es casi idéntica a la movePlayerBullets función. Verificamos si el islas La tabla contiene cualquier isla y, si lo hace, la recorremos y movemos cada isla un poco..

función moveIslands () si (#islands> 0) entonces para i = 1, #islands do islands [i] .y = islands [i] .y + 3 end end end end

8. checkIslandsOutOfBounds

Al igual que verificamos si las balas del jugador se han movido fuera de la pantalla, verificamos si alguna de las islas se ha movido fuera de la pantalla. La implementación de checkIslandsOutOfBounds Por lo tanto, debe ser familiar para usted. Verificamos si las islas. y la posición es mayor que display.contentHeight y si es así, sabemos que la isla se ha movido fuera de la pantalla y, por lo tanto, se puede eliminar.

función checkIslandsOutOfBounds () if (#islands> 0) luego para i = # islands, 1, -1 do if (islands [i] .y> display.contentHeight) luego islands [i]: removeSelf () islands [i] = nil table.remove (islands, i) end end end end end

9. generar vida gratuita

De vez en cuando, el jugador tiene la oportunidad de obtener una vida libre. Primero generamos una imagen de vida libre y si el jugador choca con la imagen, obtiene una vida extra. El jugador puede tener un máximo de seis vidas..

la función genereFreeLife () si (numberOfLives> = 6) y luego devuelve el final local freeLife = display.newImage ("newlife.png", math.random (0, display.contentWidth - 40), 0); table.insert (freeLifes, freeLife) planeGroup: insert (freeLife) end 

Si el jugador ya tiene seis vidas, no hacemos nada al regresar temprano de la función. Si no, creamos una nueva imagen de vida y la agregamos a la pantalla. De manera similar a como posicionamos las islas antes, establecemos la imagen en un negativo y Posición y generar un valor aleatorio para la imagen. X posición. Luego lo insertamos en el freeLifes Mesa para poder referenciarla más tarde..

Necesitamos llamar a esta función de vez en cuando. Agregue el siguiente fragmento de código al startTimers función.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) generateIslandTimer = timer.performWithDelay (5000, generateIsland, -1) genera FreeLifeTimer = timer.performWithDelay (7000, generateFslive, 1)

10. mover vidas libres

La implementación de moveFreeLifes debe parecer familiar. Estamos recorriendo el freeLifes Mesa y mueve cada imagen en ella..

función moveFreeLifes () if (#freeLifes> 0) entonces para i = 1, # freeLifes do freeLifes [i] .y = freeLifes [i] .y +5 end end end

Todo lo que necesitamos hacer es llamar moveFreeLifes en el gameLoop función.

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

11. checkFreeLifesOutOfBounds

El siguiente fragmento de código también debería parecerte familiar a estas alturas. Verificamos si alguna de las imágenes en el freeLifes mesa se han movido fuera de la pantalla y eliminar los que tienen.

Función checkFreeLifesOutOfBounds () if (#freeLifes> 0) luego para i = # freeLifes, 1, -1 do if (freeLifes [i] .y> display.contentHeight) luego freeLifes [i]: removeSelf () freeLifes [i] = nil table.remove (freeLifes, i) end end end end end 

Llamamos a esta función en el gameLoop función.

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

12. hasColido

Debemos poder saber cuándo los objetos del juego chocan entre sí, como el plano del jugador y las imágenes de vida libre, las balas y los planos, etc. Mientras Corona ofrece un motor de física muy robusto que puede manejar fácilmente las colisiones entre objetos de visualización Para nosotros, hacerlo agrega un poco de sobrecarga con los cálculos que el motor tiene que hacer en cada cuadro..

Para los fines de este juego, utilizaremos un sistema simple de detección de colisión de caja de delimitación. Lo que hace esta función es asegurarse de que los rectángulos o cuadros delimitadores alrededor de dos objetos no se superpongan. Si lo hacen, los objetos están chocando. Esta lógica se implementa en el hasColido función.

La función hasCollided (obj1, obj2) if (obj1 == nil) devuelve el final falso if (obj2 == nil) luego devuelve el final falso local left = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin derecho local = obj1.contentBounds.xMin> = obj2.contentBounds.xMin y obj1.contentBounds.xMin <= obj2.contentBounds.xMax local up = obj1.contentBounds.yMin <= obj2.contentBounds.yMin and obj1.contentBounds.yMax >= obj2.contentBounds.yMin local down = obj1.contentBounds.yMin> = obj2.contentBounds.yMin y obj1.contentBounds.yMin <= obj2.contentBounds.yMax return (left or right) and (up or down) end

Encontré este fragmento de código en el sitio web de CoronaLabs. Funciona realmente bien, porque los objetos del juego en nuestro juego son rectangulares. Si está trabajando con un objeto que no es rectangular, es mejor que aproveche el motor de física de Corona, ya que su detección de colisión está muy bien optimizada para esto..

13. checkPlayerCollidesWithFreeLife

Queremos comprobar si el avión del jugador ha colisionado con un objeto de vida libre. Si es así, le otorgamos al jugador una vida libre..

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

En el checkPlayerCollidesWithFreeLife función, pasamos por el vidas libres Tabla al revés por la misma razón que describí anteriormente. Llamamos al hasColido Funciona y pasa en la imagen actual y en el plano del jugador. Si los dos objetos chocan, eliminamos la imagen de vida libre, incrementamos la número de vidas variable, y llamar al ocultar vidas y show Lives función.

Invocamos esta función en el gameLoop función.

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

14. ocultar vidas

los ocultar vidas la función pasa por el vidasImágenes mesa y establece el es visible propiedad de cada imagen de vida a falso.

La función hideLives () para i = 1, 6 do livesImages [i] .isVisible = false end end 

15. show Lives

los show Lives la función pasa por el vidasImágenes tabla y establece cada imagen de es visible propiedad a cierto.

función showLives () para i = 1, numberOfLives do livesImages [i] .isVisible = true; final fin

Conclusión

Esto cierra la tercera parte de esta serie. En la próxima y última entrega de esta serie, crearemos aviones enemigos y finalizaremos el juego del juego. Gracias por leer y nos vemos allí..