Seguimos avanzando rápido! ¿Quien quiere armamento para disparar al aire? Va siendo hora de crear algunos enemigos xD. Veremos arrays/tablas y reglas de movimiento básico.

Creando enemigos.

En la última entrada vimos como generar números aleatorios, aquí veremos como aplicarlo en el juego.

Los atributos del enemigo son similares a los del player1, a fin de cuentas son objetos que se desplazan por pantalla, tienen armas, tendrán vida y daño…

Recordemos la declaración de player1:

player1 = {}
player1.image = love.graphics.newImage("recursos/PNG/playerShip1_blue.png")
player1.W = player1.image:getWidth() -- ancho de la nave
player1.H = player1.image:getHeight() -- alto de la nave
player1.x=(WINDOWW-player1.W)/2 -- posicion inicial x
player1.y=WINDOWH-player1.H-10 -- posicion inicial y
player1.v = 300 --velocidad de la nave
player1.ctrshoot = -1 -- control de disparos
player1.lasers={} 	-- tabla lasers

En el caso de los enemigos tenemos prácticamente lo mismo:

alien1 = {}
alien1.image = love.graphics.newImage("recursos/PNG/Enemies/enemyBlack1.png")
alien1.W = alien1.image:getWidth() -- ancho de la nave
alien1.H = alien1.image:getHeight() -- alto de la nave
alien1.x = math.random(1,WINDOWW-alien1.H) -- posicion inicial x
alien1.y = 6 + (fila*alien1.H) -- posicion inicial y
alien1.v = 100 + (5*math.random(10,40)) --velocidad de la nave variable, entre 150 y 300 a intervalos de 5
alien1.xdir = 1 -- afecta al sentido del movimiento en el eje X. 1derecha, -1izquierda
alien1.lasers={} -- tabla lasers
  • Hemos cambiado la imagen que los representa por enemyBlack1.png.
  • Si te fijas utilizamos un valor aleatorio para el eje x al definir las coordenadas de inicio.
  • La velocidad también será variable de una nave a otra dentro de unos valores acotados, entre 150 y 300.
  • Añadimos una nueva variable, xdir, para controlar hacia donde se desplaza la nave, derecha o izquierda.

Como vamos a crear más de un enemigo y queremos reutilizar el código, construimos una nueva función xnewalien().

function xnewalien(fila)
	alien1 = {}
	alien1.image = love.graphics.newImage("recursos/PNG/Enemies/enemyBlack1.png")
	alien1.W = alien1.image:getWidth() -- ancho de la nave
	alien1.H = alien1.image:getHeight() -- alto de la nave
	alien1.x = math.random(1,WINDOWW-alien1.H) -- posicion inicial x
	alien1.y = 6 + (fila*alien1.H) -- posicion inicial y
	alien1.v = 100 + (5*math.random(10,40)) --velocidad de la nave variable, entre 150 y 300 a intervalos de 5
	alien1.xdir = 1 -- afecta al sentido del movimiento en el eje X. 1derecha, -1izquierda
	-- tabla lasers
	alien1.lasers={}
	-- inserta en la tabla
	table.insert(aliens, alien1)
end

A la función le añadimos el parámetro fila, este definirá la posición inicial en el eje y.

Para gestionar de forma eficiente todos los enemigos los cargaremos en una Tabla, aliens. Como alien1 es a su vez una tabla tenemos que insertarla en la tabla aliens utilizamos table.insert()

Con la función definida podemos crear las naves enemigas. Lo haremos al inicio de la ejecución durante la carga. Abre la función xloadobjs() y añadimos las siguientes lineas:

-- tabla de aliens
aliens = {}
-- crea aliens por defecto
xnewalien(0)
xnewalien(1)		
xnewalien(2)

Recuerda que el parámetro de xnewalien() es la fila, estamos creando tres naves, una por fila.

Sin embargo, si ejecutas ahora no verás nada, tenemos que indicar al juego que pinte las naves.

Mostrar Enemigos

Vimos como recorrer una Tabla de elementos al pintar los lasers, el procedimiento es el mismo.

Añadimos a la función draw() lo siguiente:

-- Draw enemies
for _,a in pairs(aliens) do
	love.graphics.draw(a.image, a.x, a.y)
end

Ahora si!, escuadrón enemigo en pantalla, de momento está inmóvil porque no saben como moverse, y digo «saben» porque el movimiento será cosa suya. Es el momento de crear la lógica para que se desplacen por pantalla.

Algoritmo de movimiento autónomo

Creo que una de las partes más interesantes y divertidas de la programación de videojuegos es la capacidad de crear seres/objetos autónomos, que interactuen con otros elementos en función de reglas básicas.

En este caso vamos a definir un comportamiento sencillo, desplazamiento horizontal de lado a lado cambiando el sentido al tocar el borde de la ventana

Para mantener el código ordenado creamos una función que contenga las reglas de movimiento de naves enemigas

-- Move Aliens
function xmovealiens(dt)
	for _,a in pairs(aliens) do				
		a.x = a.x + (a.v * dt * a.xdir)
		-- si llega al borde de la ventana cambia el sentido
		if a.x > WINDOWW-a.W then
			a.x = WINDOWW-a.W
			a.xdir = -1
		elseif a.x<0 then
			a.x = 0
			a.xdir = 1
		end		
	end
end

¿Que hace la función?

  1. Iniciamos un bucle que recorra la Tabla aliens
  2. Modificamos la coordenada x de la nave:
    • El desplazamiento es: Velocidad * DeltaTime * SentidoNave
    • Tenemos velocidad = a.v, DeltaTime=dt y SentidoNave=xdir
    • A dicho desplazamiento hay que añadirle la posición actual x para tener la posición absoluta.
    • Todo ello queda: a.x = a.x + (a.v * dt * a.xdir)
  3. Por último, para que la nave no se pierda fuera de la zona visible añadimos la condición:
    • Si la posición sobrepasa el borde derecho -> if a.x>WINDOWW
      • posiciona nave al mismo borde
      • cambia el sentido a negativo a.xdir=-1
    • Si la posición sobrepasa el borde izquierdo –> if a.x<0
      • posiciona la nave al borde, x=0
      • cambia el sentido a positivo a.xdir=1

Recuerda que el valor de coordenadas del eje x es de incremental de izquierda a derecha, siendo la posición más a la izquierda de la ventana el valor 0 y la de la derecha el mismo ancho de la ventana, que lo cargamos en la variable WINDOWW durante el load().

Deltatime o ds contiene el tiempo en milisegundos desde la última vez que se ejecuto update(). Es necesario aplicar este valor porque el desplazamiento es relativo al tiempo transcurrido.

Teniendo la función solo nos queda llamarla desde update() pasando ds como parámetro, añade esta linea al final de love.update():

xmovealiens(dt)

Y ejecuta!! ya tenemos escuadrón enemigo en movimiento.

El código queda así.

function xInit()
	print("altaruru intro a love2d")
	print("ESCAPE TO QUIT")	
  -- recupera dimensiones de la ventana
	WINDOWH = love.graphics.getHeight()
	WINDOWW = love.graphics.getWidth()
	-- inicia aleatorios:
	math.randomseed(os.time()) -- random initialize
end

function xloadobjs()
	background = {}
	background.image = love.graphics.newImage('recursos/Backgrounds/clouds.png')
	background.W = background.image:getWidth()
	background.H = background.image:getHeight()
	background.sound=love.audio.newSource("recursos/musica/space1.mp3")

	laserblue01 = {}
	laserblue01.image = love.graphics.newImage("recursos/PNG/Lasers/laserBlue01.png")
	laserblue01.W = laserblue01.image:getWidth()
	laserblue01.H = laserblue01.image:getHeight()
	laserblue01.sound=love.audio.newSource("recursos/Bonus/sfx_laser1.ogg", "static")

	player1 = {}
	player1.image = love.graphics.newImage("recursos/PNG/playerShip1_blue.png")
	player1.W = player1.image:getWidth() -- ancho de la nave
	player1.H = player1.image:getHeight() -- alto de la nave
	player1.x=(WINDOWW-player1.W)/2 -- posicion inicial x
	player1.y=WINDOWH-player1.H-10 -- posicion inicial y
	player1.v = 300 --velocidad de la nave
	player1.ctrshoot = -1 -- control de disparos
	player1.lasers={} 	-- tabla lasers

	-- tabla de aliens
	aliens = {}
	-- crea aliens por defecto
	xnewalien(0)
	xnewalien(1)		
	xnewalien(2)
end

function xnewalien(fila)
	alien1 = {}
	alien1.image = love.graphics.newImage("recursos/PNG/Enemies/enemyBlack1.png")
	alien1.W = alien1.image:getWidth() -- ancho de la nave
	alien1.H = alien1.image:getHeight() -- alto de la nave
	alien1.x = math.random(1,WINDOWW-alien1.H) -- posicion inicial x
	alien1.y = 6 + (fila*alien1.H) -- posicion inicial y
	alien1.v = 100 + (5*math.random(10,40)) --velocidad de la nave variable, entre 150 y 300 a intervalos de 5
	alien1.xdir = 1 -- afecta al sentido del movimiento en el eje X. 1derecha, -1izquierda
	-- tabla lasers
	alien1.lasers={}
	-- inserta en la tabla
	table.insert(aliens, alien1)
end

function love.load()
	xInit()
	xloadobjs()
	background.sound:setVolume(0.3) -- 30% del volumen general
	background.sound:setLooping(true)
	background.sound:play()
end

function love.draw()
	-- Draw background  
  love.graphics.setColor(255, 255, 255)
  love.graphics.draw(background.image, 0, 0, 0, WINDOWW/background.W, WINDOWH/background.H)
	-- Draw player
  love.graphics.draw(player1.image, player1.x, player1.y)
	-- Draw enemies
	for _,a in pairs(aliens) do
		love.graphics.draw(a.image, a.x, a.y)
	end
	-- Draw lasers
	for _,l in pairs(player1.lasers) do
		love.graphics.draw(laserblue01.image, l.x, l.y)
	end
end

function xmoveplayer(x, y, dt)
	player1.x = player1.x + (x * player1.v * dt)
end	

-- Move Aliens
function xmovealiens(dt)
	for _,a in pairs(aliens) do				
		a.x = a.x + (a.v * dt * a.xdir)
		-- si llega a los bordes de la ventana cambia la dirección
		if a.x > WINDOWW-a.W then
			a.x = WINDOWW-a.W
			a.xdir = -1
		elseif a.x<0 then
			a.x = 0
			a.xdir = 1
		end		
	end
end	

function xmovelasers(dt)
	for ldel, laser in ipairs(player1.lasers) do
		if laser.y > -5 then
			laser.y= laser.y - 500 * dt
		else
			-- si llega a la parte superior de la ventana se elimina
			table.remove(player1.lasers, ldel)
			player1.ctrshoot=-1 -- temporal
		end
	end
	if player1.ctrshoot>0 then
		player1.ctrshoot = player1.ctrshoot - 1000 * dt
	end
end

function xplayershoot()
	if player1.ctrshoot < 0 then
		player1.ctrshoot=200
		laser={}
		laser.x= player1.x + (player1.W/2) - (laserblue01.W/2)
		laser.y= player1.y - laserblue01.H
		table.insert(player1.lasers, laser)
		-- reproduce sonido laser
		laserblue01.sound:stop()
		laserblue01.sound:play()
	end
end

function love.update(dt)
	if left_down then
		xmoveplayer(-1,0,dt)
	end
	if right_down then
		xmoveplayer(1,0,dt)
	end
	xmovelasers(dt)
	xmovealiens(dt)
end

function love.keypressed(key)
  if key == 'left' then
		left_down = true
	elseif key == 'right' then
    	right_down = true
 	end
	if key == " " then
		xplayershoot()
	end
	if key == "escape" then
		love.event.quit()
	end
end

function love.keyreleased(key, unicode)
 	if key == 'left' then
		left_down = false
	elseif key == 'right' then
   	right_down = false
	elseif key == " " then
		space_down = false
 	end
end

function love.quit()
  print("¡Hasta pronto!")
end

Nos vemos en la siguiente entrega, detección de colisiones.

Saludos y feliz código!!


Deja tu comentario