Comunidad Game Maker

Ayuda => Preguntas y respuestas => Mensaje iniciado por: uziel en Marzo 16, 2013, 10:57:02 AM

Título: Caminar conforme al grid
Publicado por: uziel en Marzo 16, 2013, 10:57:02 AM
Hola amigos, primero que nada me presento, soy Uziel y estudio ingeniería en sistemas computacionales, me encantan los videojuegos y me acabo de unir a esta gran comunidad.

Tengo un par de días echándole un ojo a lo que es Game Maker, he ojeado un poco la documentación por lo que conozco mas bien poco. Actualmente estoy queriendo hacer que mi personaje principal se mueve por mi mapa conforme al grid, osea que cuando quiera ir abajo se mueva a la celda que está justo debajo suyo. Lo que pasa es que el movimiento lo hace en el momento, y quisiera que hiciera el cambio de celda en un lapso de por ejemplo, un segundo, además de que no deseo el efecto de desaparecer de la celda y aparecer en la nueva posición como si mi personaje se teletransportara. Esto lo había pensando solucionar con un delay, de tal forma que mi personaje se moviera por ejemplo de 8 en 8 píxeles hacia abajo, hasta completar los 64 que son de cada celda y por último utilizar el move_snap(64,64) pero no encuentro la manera de usar un delay, he visto un poco las alarm pero tampoco es que lo vea muy elegante.

¿Alguien conoce la manera en la que pueda llevar a cabo esto?

Muchas gracias por su atención, y espero que nos podamos apoyar mutuamente.

Saludos
Título: Re:Caminar conforme al grid
Publicado por: elviskelley en Marzo 17, 2013, 01:21:15 AM
place_snapped(hsnap,vsnap) Devuelve si la instancia está alineada con los valores de snap hsnap y vsnap.
if  not place_snapped(32,32)
{
move_snap(32,32) Alinea la instancia, como la acción correspondiente.

}
Título: Re:Caminar conforme al grid
Publicado por: AndreiiCx en Marzo 17, 2013, 05:14:28 AM
Otra forma es, creando por medio de variables tu propio sistema de grid, que es prácticamente lo que planteaste solo que mas individual (me explico?  :-[)

Te eh dejado un ejemplo con esto, espero haber explicado bien el código pero si hay algo que no entiendas me avisas ;)
Título: Re:Caminar conforme al grid
Publicado por: uziel en Marzo 17, 2013, 09:48:02 PM
Primero que nada, muchas gracias a los dos.

Cita de: elviskelley en Marzo 17, 2013, 01:21:15 AM
place_snapped(hsnap,vsnap) Devuelve si la instancia está alineada con los valores de snap hsnap y vsnap.
if  not place_snapped(32,32)
{
move_snap(32,32) Alinea la instancia, como la acción correspondiente.

}

Gracias por mostrarme el move_snap y el place_snapped, me están sirviendo de mucha ayuda.

Cita de: AndreiiCx en Marzo 17, 2013, 05:14:28 AM
Otra forma es, creando por medio de variables tu propio sistema de grid, que es prácticamente lo que planteaste solo que mas individual (me explico?  :-[)

Te eh dejado un ejemplo con esto, espero haber explicado bien el código pero si hay algo que no entiendas me avisas ;)

Hola, le echaré un ojo que nunca viene mal una nueva forma de hacer las cosas.
Título: Re:Caminar conforme al grid
Publicado por: uziel en Marzo 20, 2013, 04:17:11 AM
Bueno, les cuento que ya he solucionado mi problema y les cuento un poco de como lo he hecho por si a alguien se le ofrece mas adelante, aunque quizás halla formas mas sencillas de hacerlo, pero pues apenas llevaré una semana usando el game maker y no domino aún el lenguaje.

Primero que nada les cuento que es lo que quería.

Lo que buscaba era hacer que mi personaje solo se moviera con respecto a las celdas, tal cual juego de pokemon, de hecho, el movimiento es igual. Si el botón se presionaba un momento mi personaje solo voltearía a ver en la dirección, si se mantenía presionado mas tiempo, el personaje caminara hacia la dirección según la tecla presionada.

Uno de los problemas con los que me topé, es que los eventos del teclado tienen una especie de prioridad, esto es, que si dos teclas se mantenían presionadas, mi personaje caminaría hacia la dirección que indicara la tecla con mas prioridad, algo indeseable en mi caso, ya que yo quería que mi personaje caminara en dirección a la última tecla presionada. Para solucionar esto, hice una lista donde iba almacenando las teclas presionadas y el último elemento de esta lista era el que me indicaría hacia donde mi personaje se tenía que dirigir, aquí el código donde agrego a la lista cada tecla presionada:

ds_list_add(numeroLista,vk_left);

Esto lo he hecho para cada tecla direccional y en el evento key press el cual es esencial ya que una tecla es imposible presionarla dos veces sin antes soltarla una vez, por lo que cada tecla estará en la lista solo una vez.

Cuando suelto una tecla agrego las siguientes lineas de códigos:

posicion = ds_list_find_index(numeroLista,vk_left);
ds_list_delete(numeroLista,posicion);


Con esto, ya puedo obtener siempre la última tecla que ha presionado el usuario, lo cual es justamente lo que deseaba.

Como he dicho antes, quería que si un botón era presionado solo un instante mi personaje solo volteara, y si se mantenía presionado mi personaje empezara a caminar, por lo que le he agregado líneas al evento keypress, el cual pasó a ser de esto:

ds_list_add(numeroLista,vk_left);

A esto:

teclasPulsadas = ds_list_size(numeroLista);

if(teclasPulsadas == 0 && orientacionActual != 180)
    soloVoltear = true;

ds_list_add(numeroLista,vk_left);


Esto quiere decir que si mi personaje está volteando para un lado que no sea la dirección de la tecla que estoy pulsando y que si es la primera tecla pulsada solo quiero que mi personaje voltee a ver en la dirección, mas no que empiece a caminar.

La variable orientaciónActual me dice en qué dirección está mi personaje volteando actualmente, si es 0 mi personaje mira hacia la derecha, si es 90 mi personaje mira hacia arriba, si es 180 mi personaje mira hacia la izquierda y por último, si es 270 es por que mi personaje mira hacia abajo.

Como tengo que dar tiempo a que mi personaje espere x tiempo para saber si solo tengo que hacer que mi personaje mire en otra dirección o que mi personaje camine hacia otra dirección he llamado a mi script de movimiento en el evento step y queda de la siguiente manera:

scr_moverPersonaje();

Ahora si viene lo bueno, todo el código anterior fue para agregar teclas a la lista y para saber si mi personaje tiene que voltear o caminar, pero la verdadera magia viene en el siguiente script el cual copio y pego y lo explico un poco con comentarios ya que es un poco grande:

//Aquí obtengo el número de teclas presionadas actualmente
numeroTeclas = ds_list_size(numeroLista);

//Si es mayor que 0 hago que mi personaje camine o voltee hacia la dirección indicada por la última tecla presionada, si es igual a 0, hago que mi personaje se detenga.
if(numeroTeclas > 0)
{
    //Si mi personaje está colocado en una celda de forma correcta hago el movimiento correspondiente
    if(place_snapped(64,64))
    {
        //Obtenemos la última tecla presionada
        ultimaTecla = ds_list_find_value(numeroLista,numeroTeclas - 1); 
   
        //Hacemos la acción correspondiente según la última tecla presionada
        switch(ultimaTecla)
        {
            //Aquí solo explicaré lo que se hace cuando la última tecla presionada es la que hace que nuestro personaje vaya a la derecha, pero se hace lo mismo para cada tecla, solo se cambian sprites y direcciones
           
            //Si la ultima tecla presionada fue la de dirección derecha
            case vk_right:
                //Si solo quiero voltear o la siguiente celda es un obstáculo, cambio el sprite actual y hago que mi personaje se detenga,
                if(soloVoltear || !place_free(x+64,y))
                {
                    sprite_index = Spr_Ash_MirarDerecha;
                    motion_set(0,0);
                }
                //Si no se cumple la condición anterior es por que debemos de caminar, así que ponemos el sprite correspondiente y hacemos que camine hacia la dirección y con la velocidad deseada
                else
                {
                    sprite_index = Spr_Ash_CaminarDerecha;
                    motion_set(0,4);
                }
                //Sin importar si volteamos o caminamos cambiamos la dirección actual
                orientacionActual = 0;
                break;
            case vk_up:
                if(soloVoltear || !place_free(x,y-64))
                {
                    sprite_index = Spr_Ash_MirarArriba;
                    motion_set(0,0);
                }
                else
                {
                    sprite_index = Spr_Ash_CaminarArriba;
                    motion_set(90,4);
                }
                orientacionActual = 90;
                break;
            case vk_left:
                if(soloVoltear || !place_free(x-64,y))
                {
                    sprite_index = Spr_Ash_MirarIzquierda;
                    motion_set(0,0);
                }
                else
                {
                    sprite_index = Spr_Ash_CaminarIzquierda;
                    motion_set(180,4);
                }
                orientacionActual = 180;
                break;
            case vk_down:
                if(soloVoltear || !place_free(x,y+64))
                {
                    sprite_index = Spr_Ash_MirarAbajo;
                    motion_set(0,0);
                }
                else
                {
                    sprite_index = Spr_Ash_CaminarAbajo;
                    motion_set(270,4);
                }
                orientacionActual = 270;
                break;
        }
    }
}
//Si no hay teclas presionadas hacemos lo siguiente
else
{
    //Si mi personaje está colocado en la celda correctamente podemos detener nuestro personaje
    if(place_snapped(64,64))
    {
        //Dependiendo de la orientación actual es el sprite que usaremos, ya que queremos pasar de una animacion caminando a una que solo este parado el personaje mirando hacia la dirección correspondiente
        switch(orientacionActual)
        {
             //Si volteamos hacia la derecha
            case 0:
                sprite_index = Spr_Ash_MirarDerecha;
                break;
            //Si volteamos hacia arriba
            case 90:
                sprite_index = Spr_Ash_MirarArriba;
                break;
             //Si volteamos hacia la izquierda
            case 180:
                sprite_index = Spr_Ash_MirarIzquierda;
                break;
             //Si volteamos hacia abajo
            case 270:
                sprite_index = Spr_Ash_MirarAbajo;
                break;
        }
        //Detenemos nuestro personaje
        motion_set(0,0);
    }
}

//Esto es para controlar el delay de voltear, ya que si no lo hacemos nuestro personaje volteará, pero empezará a caminar casi al instante, cosa indeseable

//Si queremos solo voltear nuestro personaje
if(soloVoltear)
{
     //Si se cumple el tiempo que le damos a nuestro personaje para que voltee y no empiece a caminar en el momento
    if(delayVoltear == 0)
    {
        soloVoltear = false;
        delayVoltear = 3;   
    }
    delayVoltear--;
}


Y con esto logramos un movimiento idéntico al que se lleva a cabo en los juegos de pokemon, quizás como dije antes, se puede hacer mucho mas fácil, pero es algo que ahora mismo desconozco y es a la solución a la que he podido llegar, lo he puesto por que no me gustan los temas inconclusos, y le puede ser suficiente a mas de uno.

Si les parece un poco lento el movimiento, solo hay que cambiar la velocidad a la que se mueve el personaje.

Para cualquier duda o sugerencia me comentan.

Saludos
Título: Re:Caminar conforme al grid
Publicado por: AndreiiCx en Marzo 24, 2013, 12:36:18 AM
eso de voltearte antes de caminar no lo habias aclarado /: haha! me alegra que hayas solucionado todo tu solo(: éxitos en tus proyectos!