¡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á:
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:
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:
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!
Comentarios
Tamaño de un sprite
Hola queria saber cuanto es el tamaño maximo de un sprite aceptado para luaDev...
Gracias...
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.
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.
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).
Ya lo intente
pero me da el mismo error, puse el sprite en una dimension mas pequeña menor que 512, pero no da.
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.
Deberias poner otros
Deberias poner otros mas..porfavor
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!.
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.
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.
interesante n.n
interesante n.n
Muy bueno
Muy wueno chime sigue asi
Gran tuto y a la espera de
Gran tuto y a la espera de más =)