Anuncios Google

Colisiones entre cajas

Tutoriales Avanzados Homebrewes

¡Hola de nuevo! he vuelto, para seguir con este, mi tutorial de LuaDEV :D. En esta ocasión traigo el cómo hacer colisiones entre cajas u objetos que asemejan ser cuadrados o rectangulares,  esto servirá para que nuestros homebrews sean mas interesantes y por supuesto más atractivos.

Ya vimos como desplazar nuestro personaje, y cómo limitar su área de movimiento. Ahora, veremos cómo hacer que nuestro personaje colisione contra objetos que impidan su movimiento, estos objetos no son más que cajas con su posición en pantalla, ancho y alto, ah, y un color para poder dibujarlas.

Pues bien, ya que en la anterior entrega hicimos el movimiento del personaje, tomaré ese mismo código con ligeras modificaciones para empezar:

link = {} -- tabla con todos los frames y propiedades de link
link["stay"]={} -- tabla con los frames cuando link está quieto
link["walk"]={} -- tabla con los sprites cuando link se mueve
 
link["stay"]["up"] = image.load("sprites/link_stay_up.png")
link["stay"]["down"] = image.load("sprites/link_stay_down.png")
link["stay"]["right"] = image.load("sprites/link_stay_right.png")
link["stay"]["left"] = image.load("sprites/link_stay_left.png")
 
link["walk"]["up"] = image.loadsprite("sprites/link_walk_up.png",22,27)
link["walk"]["down"] = image.loadsprite("sprites/link_walk_down.png",22,27)
link["walk"]["right"] = image.loadsprite("sprites/link_walk_right.png",22,27)
link["walk"]["left"] = image.loadsprite("sprites/link_walk_left.png",22,27)
 
link.status = "stay" -- al principio estará quieto, luego cuando se presione algo pasará a "walk" y caminará
link.direction = "down" -- que mire hacia abajo, asi "nos ve" xD, los otros serian "up", "left" y "right"
link.x = 10 -- posicion en X en la que se mostrará inicialmente
link.y = 10 -- posicion en Y en la que se mostrará inicialmente
link.w = 22 -- Ancho que ocupa link en pantalla
link.h = 27 -- Alto que ocupa link en pantalla
link.anim = 0 -- cuadro de la animación actual, cuenta desde 0, e irá hasta 10
 
rojo = color.new(255,0,0) -- color que usaremos para los objetos
 
while true do
	controls.read()
 
	-- código de movimiento de la animación
	if controls.up() or controls.down() or controls.left() or controls.right() then
		link.anim = link.anim + 0.2
		link.status = "walk"
		if math.floor(link.anim)>9 then
			link.anim = 0
		end
	else
		link.anim = 0
		link.status = "stay"
	end
 
	-- código de desplazamiento de nuestro héroe
	if controls.up() then
		link.y=link.y-1
		link.direction = "up"
	elseif controls.down() then
		link.y=link.y+1
		link.direction = "down"
	elseif controls.right() then
		link.x=link.x+1
		link.direction = "right"
	elseif controls.left() then
		link.x=link.x-1
		link.direction = "left"
	end
 
	if link.status=="walk" then -- si no está quieto
		link[link.status][link.direction]:setframe(link.anim) -- que pueda caminar
	end
 
	link.x = math.min(math.max(0,link.x), 480-link.w) -- límite en X dentro de la pantalla
	link.y = math.min(math.max(0,link.y), 272-link.h) -- límite en Y dentro de la pantalla
 
	link[link.status][link.direction]:blit(link.x,link.y) -- mostrar a link! (al fin xD)
 
	screen.flip() -- mostrar cambios en pantalla
	if controls.l() and controls.cross() then -- si presiono L y Cruz al mismo tiempo
		broke() -- error!
	end
end

Como podrán ver, he puesto los valores de animación, dirección, estado, etc... dentro de la tabla de link, para tener un poco más de orden por si ponemos más personajes en un futuro, además he creado el color rojo para pintar los objetos.

Entonces, básicamente cada objeto tendrá:

  • Posición en X
  • Posición en Y
  • Ancho
  • Alto
  • Color o una imagen que lo represente (como en el caso del personaje)

Con esa base, crearemos tres objetos para mostrarlos en pantalla:

objetos = {} -- tabla que tendrá los objetos, éstos no serán mas que rectángulos de color rojo
function generar_objetos() -- una función para generar los objetos cada que queramos
	for i=1,3 do
		objetos[i] = {} -- cada objeto, es una tabla con ciertas propiedades:
		objetos[i].w = math.random(20,30) -- haremos que cada objeto, tenga de ancho de 20 a 30
		objetos[i].h = math.random(20,30) -- lo mismo con el alto
		objetos[i].x = math.random(0,480-objetos[i].w) -- ahora, cada objeto tiene una posicion en pantalla, en X, va de 0 a 480, pero! el objeto tiene ancho, entonces, para que no se salga de pantalla el límite será 480 - el ancho del objeto (objetos[i].w)
		objetos[i].y = math.random(0,272-objetos[i].h) -- lo mismo que arriba, en Y el límite sería 272, pero el objeto tiene alto (objetos[i].h)
	end
end

Sintaxis de math.random: En este caso, math.random trabaja con dos parámetros que sirven de límites, esta función devuelve un número entero aleatorio entre el número mínimo (en este caso 20) y el número máximo (en este caso 30) que se le de.

He puesto el código en una función para facilitar la creación de objetos, pero atención, que no hemos ejecutado la función, por lo tanto, los objetos aun no existen.

Listo, ya tenemos a nuestro personaje, y tres objetos que serán creados, ahora, como hacemos que colisione?, para esto, primero debemos saber en qué consiste una colisión.

Una colisión se da únicamente, cuando un borde de un objeto toca o intenta atravesar el borde de otro, es decir, que sólo hay cuatro colisiones posibles:

  • Borde derecho de un objeto con el borde izquierdo del otro
  • Borde izquierdo de un objeto con el borde derecho del otro
  • Borde inferior de un objeto con el borde superior del otro
  • Borde superior de un objeto con el borde inferior del otro

Ok, con esto, podemos hacer una función que nos facilite la comprobación entre dos objetos, para saber si colisionan o no:

function colision(obj1, obj2) -- esta función, verifica si hay colisión o no entre dos objetos, notar que, DENTRO de la función se usan los parámetros que recibe, más adelante, veremos como se usa
	if obj1.x+obj1.w>obj2.x -- borde derecho obj1 > borde izquierdo obj2
	and obj1.x<obj2.x+obj2.w -- borde izquierdo obj1 < borde derecho obj2
	and obj1.y+obj1.h>obj2.y -- borde inferior obj1 > borde superior obj2
	and obj1.y<obj2.y+obj2.h then -- borde superior obj1 < borde inferior obj2
		return true -- retorna verdadero si hay colisión
	end
return false -- si el if no se cumple, viene a esta línea y retorna false, es decir, no hay colisión
end

Recordar que, un borde es la coordenada, y el otro, es la coordenada mas el valor de ancho (en el caso de x) o de alto (en el caso de y), ya que prácticamente cada objeto es una caja.

Nota: Toda declaración de funciones, debe ir fuera del bucle principal, ya que ponerla dentro, no es más que pérdida de tiempo.

Con esto, estamos listos, solo falta una cosa, crear los objetos!, para esto usaremos la función que creamos arriba:

generar_objetos() -- generamos objetos al comienzo

Esto, justo antes de entrar al while.

Ahora veamos, toda colisión consta de tres tiempos:

  • Justo antes de la colisión: Nuestro personaje estará borde con borde con un objeto
  • Durante la colisión: Nuestro personaje se habrá pasado por un píxel al objeto, y la colisión sera verdadera
  • Después de la colisión: Nuestro personaje, al mostrarlo, deberá estar en la posición justo antes de la colisión, debemos buscar la forma de contrarrestar el movimiento para que no quede encima del objeto

Entonces, justo antes de la colisión, será justo antes de que se mueva, es decir, antes del código de desplazamiento de nuestro héroe.

Durante la colisión, justo después de ese código, donde puede que se haya movido un píxel, por lo tanto, allí debe ir nuestro código para verificar la colisión, y hacer la corrección para que no atraviese el objeto:

for i=1,3 do -- for para mostrar los objetos en pantalla
	draw.fillrect(objetos[i].x, objetos[i].y, objetos[i].w, objetos[i].h, rojo) -- mostramos el objeto relleno de color rojo
	if colision(link, objetos[i]) and link.status=="walk" then -- si ha colisionado, y link estaba caminando en el momento de la colisión, hay que contrarrestar el movimiento
		if link.direction=="right" then link.x=link.x-1 -- por derecha
		elseif link.direction=="left" then link.x=link.x+1 -- por izquierda
		elseif link.direction=="up" then link.y=link.y+1 -- por arriba
		elseif link.direction=="down" then link.y=link.y-1 end -- por abajo
		-- básicamente lo que hemos hecho es que avance en la dirección contraria
	end
end

colision entre link y objetos[i]... espera, no eran obj1 y obj2??, si si, pero cuando usas funciones, estos valores se reemplazan por los que les pasas.

Es decir, que al hacer colision(link, objetos[i]), Lua se va a la línea donde se declaró la función y dice: ok, link está justo donde va obj1, entonces obj1 = link, y luego objetos[i] está justo donde va obj2, entonces obj2 = objetos[i], esto, dentro de toda la función, y listo! ya puede operar entre los objetos que queremos.

Con eso ya tenemos a nuestro personaje caminando por la pantalla, con pequeños bloques que impiden su paso, y por cierto, no pusimos nada para que los bloques no terminen encima de nuestro personaje al generarlos, por eso, sería bueno poner en cualquier parte del código, pero dentro del bucle, esto:

if controls.press("cross") then -- si presionamos X
	generar_objetos() -- generamos de nuevo los objetos
end

Con eso al presionar X los objetos se generarán nuevamente.

Bueno, eso es todo por hoy, Saludos!

4.213335
Tu voto: Ninguno Votos totales: 4.2 (75 votos)

Anuncios Google

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de DmaKill_18

Tamaño de un sprite

Hola queria saber cuanto es el tamaño maximo de un sprite aceptado para luaDev...

 

Gracias...

Imagen de Andres_Ne

Tamaño?,pues el que no exeda

Tamaño?,pues el que no exeda la pantalla por cuestio de visibilidad xD,pero no hay ningun limite establecido.

Imagen de DmaKill_18

Tengo un Sprite de 2400x100

Tengo un Sprite de 2400x100 pero al momento de pasar a la siguiente animacion osea la siguiente imagen, se deforma la imagen este es el srpite.

 

Sprite


Editado: El límite del ancho de las imágenes es de 500 pixeles, sobrepasar este límite puede descolocar la web e incumple las Normas de la Comunidad, antes de volver a postear por favor revíselas.| Rober Galarga

De hecho si hay un límite, es

De hecho si hay un límite, es el mismo para todas las imágenes: 512x512pix (en realidad es algo menor, creo, cosa de probar).

Imagen de DmaKill_18

Ya lo intente

pero me da el mismo error, puse el sprite en una dimension mas pequeña menor que 512, pero no da.

Imagen de Jepte

pues algo deves estar

pues algo deves estar haciendo mal, intenta hacerlo de forma manual, a que te refieres cuade dices que pusite el sprite en una dimencion mas pequeña, los 512 son pixeles no dimenciones xd.

Imagen de Andres_Ne

Deberias poner otros

Deberias poner otros mas..porfavor 

Imagen de barney77

Duda.

Pero... ¿Y si úsaramos el >=(mayor o igual que) y el =<(menor o igual que) en la colision ya no se pasaría por un pixel, no?. Es decir si indicamos en la condicion que al ser mayor o igual que( o menor o igual que, dependiendo del caso), al ser igual no se pasaría por un pixel o sí?.

Bueno esa es mi duda, un saludo chime!.

Imagen de Chimecho

Inténtalo

Creo que se verá como si tuviera un recuadro de un píxel de ancho de más por el que Link no podrá pasar.

Imagen de barney77

Precisamente

Tal y como lo haz dicho, se ve como si tuviera un pixel del más por el cual link no puede pasar!.

Muchas gracias chime.

Imagen de klozz

interesante n.n

interesante n.n

Imagen de m.rr

Muy bueno

Muy wueno chime sigue asi

 

Imagen de sisinio

Gran tuto y a la espera de

Gran tuto y a la espera de más =)

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.