Abril 01, 2014, 09:58:08 AM Ultima modificación: Abril 02, 2014, 02:35:10 AM por penumbra
Autor: penumbra
Descripción: Un ejemplo de cómo usar un sprite para bloquear parcialmente la vista durante una transición entre habitaciones.
Versión: Desarrollado en GM8.1. No lo he probado en GM:S, quizás funcione o quizás necesite pequeños cambios en el código.

Información preeliminar:
Para comprender cómo funciona el script, hay que enteder el método que GM nos ofrece para agregar nuevas transiciones a las ya disponibles, siempre y cuando nos ciñamos a ciertas directivas del propio sistema de transiciones. Me voy a extender un poco, pero considero que esto es preferible a dejar dudas que podrían suponer obstáculos si te decides a usar transiciones personalizadas. A partir de un solo script, es posible crear un nuevo efecto de transición que puede ser llamado como cualquiera de las otras transiciones incluídas por defecto en GM. Cuando llamamos a un efecto de transición, hacemos esto:

transition_kind = 10    //indice_de_la_transicion
room_goto_next();


El índice de la transición apunta a un script interno de GM el cual se encarga de realizar el efecto de transición. Algo fundamental que debemos saber del sistema de transiciones es que los argumentos con los que trabaja el script de transición ya están previamente definidos, son los mismos siempre, de hecho, al llamar al script, GM le provee automáticamente de los argumentos. Lo que a nosotros nos interesa es saber cuáles son esos parámetros, para poder hacer referencia a ellos y usarlos según nos convenga. Los argumentos son:

argument0: Surface con la imagen de la habitación anterior
argument1: Surface con la imagen de la siguiente habitacion
argument2: Ancho de la surface
argument3: Alto de la surface
argument4: Porcentaje de la transición (varía de 0 a 1)

Una vez que creamos un script, hay que registrarlo de manera que GM sepa que es un efecto de transición. Para esto usamos la función transition_define()
transition_define(100, "nombre_del_script")

El primer argumento es el índice del script, el cual puede ser cualquier número SIEMPRE Y CUANDO no sea un índice que ya se use en otro script de transición, incluidas las 21 transiciones por defecto de GM. Para evitar problemas, puedes usar índices para tus transiciones a partir de un número más o menos grande, por ejemplo 50 o 100.

El segundo argumento es el nombre del script, el cual debe especificarse en comillas.

Quizás el mejor lugar para registrar un script de transición sea el evento [GAME START] de algun objeto controlador, aunque se puede registrar en cualquier evento.


También podemos controlar el tiempo que dura la transición, mediante la variable transition_steps. El valor por defecto de esta variable es de 80 steps, aunque es probable que este número sea algo corto para la mayoría de transiciones.

Factores a considerar para que el script funcione de manera correcta:
Este script usa un sprite (una simple imagen) como máscara para la transición. La imagen tiene una zona transparente (alfa 0) en su centro y el área alrededor es opaca (alfa 1). La transición inicia con la imagen a tamaño normal, y a medida que se efectúa la transición, el tamaño de sprite aumenta, lo que produce que la zona central (transparente) sea cada vez mayor y revele más y más la vista del juego. Adjunto una imagen que deja más claro de lo que se trata.

spr_mask: LA ZONA CLARA ES EN REALIDAD TRANSPARENTE


Es necesario realizar ciertas preparaciones para que el script funciones de manera correcta, de lo contrario el efecto se hecha a perder (y realmente se ve mal)


  • El sprite que uses como máscara debe ser exactamente del tamaño de la vista (view).
  • La zona transparente del sprite debe ser con alfa = 0, la zona opaca que yo usé es de color negro, pero creo que cualquier color (alfa 1) funcionaría igual. Obviamente el formato recomendado de la imagen debe ser PNG-24
  • En GM, debes indicar el origen del sprite EN SU CENTRO (en las propiedades del sprite)
  • El sprite debe estar cargado en el árbol de recursos de GM, en el ejemplo el nombre del sprite es spr_mask, pero se puede usar otro nombre siempre y cuando se modifique el script.
  • Debes declarar una variable global (en cualquier objeto persistente) de nombre inc e iniciarla a 0 antes de llamar al script.

Después de tanto rollo, el script:

/*
Descripcion: Script para usar un sprite como máscara en una transición entre habitaciones
Autor: penumbra
*/
var surfaces, ancho, alto, fraction;
surfaces[0] = argument0; // surface con la imagen de la habitación anterior.
surfaces[1] = argument1; // surface con la imagen de la habitación siguiente.
ancho = argument2; // ancho de la surface
alto = argument3; // alto de la surface
fraction = argument4; // porcentaje de la transición (entre 0 y 1)
draw_clear(c_black);

var mascara, f, w, esc;                                    //surface de mascara, factor normalizador, ancho del sprite máscara, factor de escala.

mascara = surface_create(ancho, alto)
surface_copy(mascara, 0, 0, surfaces[1])                        // copiar la superficie de la habitación siguiente en la superficie de máscara
surface_set_target(mascara)
draw_set_blend_mode(bm_subtract)
draw_set_color(c_black)

inc += 0.01 // incremento del escalado
w = sprite_get_width(spr_mask)
//hacer que el factor f sea tal que f*x_scale y f*y_scale sea 1 para el sprite máscara. fraction * w nunca será mayor al ancho del sprite.
if (fraction * w < ancho)
{
    f = fraction * ( ancho/(0.01 + fraction * w) )            //0.01 es para evitar error de división por 0, al inicio de la transición.
    esc = f + f*inc
}
else { esc = 8 }

draw_sprite_ext(spr_mask, 0, view_xview + view_wview/2 , view_yview + view_hview/2, esc, esc, 0, c_white, 1)
draw_set_blend_mode(bm_normal)
surface_reset_target()
draw_surface(surfaces[0], 0, 0)
draw_surface(mascara, 0, 0)
surface_free(mascara)


Para usar esta transición, en el evento [STEP] del obj_jugador harías algo similar a esto:
if place_meeting(x,y,obj_portal)
{
     transition_kind = 100;                 //Yo registré el script con el índice 100, especifica el número de índice que tu hayas registrado
     transition_steps = 300;       
     visible = false
     room_goto_next();
}


¿Por qué uso visible = false? Es por el modo en que GM se comporta cuando se usan las funciones de cambio de habitación. Si no hago invisible el sprite del personaje, el sprite aparece en la superficie especificada por argument0 durante la transición, y eso hecha a perder el efecto, tal vez esto sea confuso, pero es cuestión de que pruebes a mantener el sprite visible y verás que durante la transición el sprite del personaje se puede ver repetido en dos lugares distintos. Es por esto que hay que hacer invisible el sprite. Ahora, para volver a hacerlo visible, usamos el evento ROOM START. En mi caso, luce así:

Objeto jugador, evento [ROOM_START]
if (room == room1)     //Este IF se puede modificar para que sea verdadero en todas las habitaciones excepto la primera
{
  x = 1;                       //El jugador es un objeto persistente, por lo que debemos posicionarlo al comienzo de la nueva habitación
  visible = true              //Hacemos visible de nuevo al jugador
}


Bueno, eso es todo, si hay alguna duda o algo no se entiende, escribe un mensaje. Ah, casi se me olvida. El efecto de máscara luce algo así.

#1 Abril 01, 2014, 08:18:34 PM Ultima modificación: Abril 01, 2014, 08:37:55 PM por vampy09
Me parece excelente el script el que has posteado.
Permite una "customizacion" mas sencilla de la transición, por que es mil veces mas sencilo crear una imagen.

Lamentablemente no funciona en GM:S. La funciones de transicion son obsoletas.

Seria grandioso poder lograr un script como este en GM:S.

Saludos!
The next best thing to knowing something,
is knowing where to find it.


Cita de: vampy09 en Abril 01, 2014, 08:18:34 PM
Lamentablemente no funciona en GM:S. La funciones de transicion son obsoletas.

Uh. no lo sabía. Creo que aun es posible hacer algo similar en GM:S, pero sería muy enredoso de hacer  :-X

Cita de: abramelin en Abril 01, 2014, 09:37:50 PM
gracias por compartir, eres un autentico resource-man

Gracias, en realidad es el primer script que comparto.