Buenas! Saqué código del siguiente vídeo:
https://www.youtube.com/watch?v=dYbCfhX3Hu4
el problema es que TODA LA PANTALLA se pone oscura, y las luces lo iluminan. Quiero hacer que el fondo no se vea afectado, es decir, que el fondo siempre tenga iluminación máxima, y que la luz (todo oscuro y se ilumine con la linterna) sólo afecte a las tiles y objetos, pero NO al background. Tengo un objeto con depth 10000 que hace draw_background, pues quiero que ese draw no se vea afectado por la luz, que se vea al 100% claro.
Os pego el código del vídeo, está en el objecto controlador, -1000 depth
CREATE
light = surface_create(view_wview, view_hview);
STEP
surface_set_target(light);
draw_set_color(make_color_rgb(200, 200, 200));
draw_rectangle(0, 0, view_wview, view_hview, false);
surface_reset_target();
DRAW
draw_set_blend_mode(bm_subtract);
draw_surface(light, view_xview, view_yview);
draw_set_blend_mode(bm_normal);
Hecho eso, en cualquier lugar, por ejemplo el objeto linterna:
DRAW
draw_set_blend_mode(bm_subtract);
surface_set_target(objCtrl.light);
// Dibujar la luz: un sprite cuyos píxeles blancos iluminarán el entorno
surface_reset_target();
draw_set_blend_mode(bm_normal);
Puedes usar una segunda surface donde dibujes los sprites y tiles, que luego podrás utilizar como mascara para eliminar las áreas de la surface con el efecto donde solo hay background.
Usa el objeto donde dibujas el background como objeto controlador.
Crea una nueva surface, en esta surface se dibujará todo lo que no sea background o luz.
Pasa el draw_background del evento Draw al evento Draw Begin.
Justo después del draw_background agrega un surface_set_target y ponle la nueva surface, esto hará que todo lo que no se especifique para otra surface sea dibujado en la nueva.
En el evento Draw End pon draw_reset_target. Esto hará que ya no se dibuje nada más en la surface nueva.
Ahora, aún en el evento Draw End coloca este código:
surface_set_target(light);
draw_set_blend_mode_ext(0,5);
draw_surface(Nueva_surface,0,0);
draw_set_blend_mode(bm_normal);
surface_reset_target();
Eso eliminará los espacios "en blanco" de la surface con el efecto de luz.
Dibuja la nueva surface para que todo aparezca en pantalla como si se dibujara normalmente.
Dibuja la surface de luz con el código que ya tenías.
Como dije, todo esto desde el objeto donde dibujas el background.
Una pregunta: a la hora de dibujar los objetos en la surface nueva, eso se hace automático: toda tile y objeto, al dibujarse, lo hará en la nueva. PERO, la nueva surface, que tiene tamaño igual a la view... tiene coordenadas iniciando en 0. Mientras que los objetos se dibujarán con las coordenadas de la room, o sea, FUERA DE LA SURFACE, que va de 0 a view_wview.
Una opción sería, por ejemplo, que los objetos se dibujen en x-view_xview e y-view_yview, o sea, se dibujan dentro de la surface, después la surface la dibujo en view_xview y view_yview. En cuanto a dibujo funciona, he hecho una mini prueba, y no me molesta poner en todos los objetos un evento draw de esa forma PEEERO... aparece un efecto window-from-windows. Al mover un objeto deja un rastro de sí mismo atrás, donde estaba antes. O sea, como si la pantalla no se limpiara, en cada step se dibuja y ese dibujado se mantiene, dejando una estela. A demás, esto no sé si puedo hacerlo con tiles... podría recorrer tile tras tile y.. o no.. la cuestión sería como hacer que las tiles se dibujen entre 0 y view_wview para que también funcione. O alguna otra solución más sencilla? Porque me preocupa, aún dibujandolo todo entre 0-W, el efecto este de dejar rastro
PD: vaya, no sabía que había draws begin y end, mola, y tiene buena pinta, a ver si solucionamos esto :D
Lo del rastro que dejan los sprites al moverse se puede solucionar limpiando la surface con un draw_clear_alpha(0,0) en el Draw Begin justo cuando se pone la surface nueva, pero no habia considerado el movimiento de la view y como afectaria comandos de dibujo con coordenadas definitivas.
Es ciertamente posible mover las capas de tiles por completo, sin tener que mover uno por uno cada tile, pero haciendo la prueba con este método en particular, da más dolores de cabeza que los que resuelve.
Mover al mismo tiempo la view y los tiles hace que algunos de los tiles que deberían dibujarse en pantalla queden "fuera de la view" según los cálculos del GM, y por lo tanto el GM no los dibuja, resultando en una imagen incompleta.
La única forma de resolver esto sería no mover la view para nada, en su lugar tener variables que hagan de cámara que le digan a los objetos y tiles donde deben dibujarse. Como dije, un dolor de cabeza.
Desde un principio fueron los tiles los que complicaban este efecto, como no poseen ninguna función para dibujarlos a pedido, hay que agarrarlos cuando se están dibujando normalmente.
Sobre una solución más simple... bueno, no sé si será más simple pero tratando de improvisar, me parece recordar que el GM tiene una función para pasar el contenido de una view a una surface, quizás esto podría utilizarse para adquirir la máscara para eliminar las áreas del background de la surface de luz sin tener que afectar la view principal del juego, pero sería algo que tendría que ponerme a probar cuando tenga el GM a la mano.
Ok, Me tomo un poco más de tanteo del que me gustaría admitir, pero ya encontré la forma, o al menos una forma.
Configura la view 1 igual a la view 0, las views deben comportarse igual.
Si no lo has hecho, desactiva el dibujo de color de fondo en la room.
Cambia los valores de todas las luces para que le resten las coordenadas de la view al dibujarse.
En el objeto controlador/background, en Draw Begin, borra el código que tenías, en su lugar necesitamos asignar la view 0 a la superficie nueva, y comprobar si la view activa es la 0 para limpiar la pantalla con un draw_clear_alpha, si la activa es la 1 dibujar el background. Debería quedarte algo así:
view_surface_id[0] = Images;
if view_current = 0{
draw_clear_alpha(0,0);
}
else {
draw_background(background1,0,0);
}
Usamos la view 0 para dibujar en la superficie porque es la primera en dibujarse.
En el evento Draw End elimina el draw_reset_target, ya no es necesario. Coloca el resto del código en Draw End en un if que compruebe que la view activa es la 1.
Dejo un ejemplo.
Arceus bendito! Llevo una buena media hora, o ha sido más? Pero lo he logrado! Varias cosas distintas, como que mi background es menor al tamaño de la room y lo dibujo en view_xyview, y que en la room lo tengo asignado, visible y tileado para que sea fácil editarla, y tengo que desactivarlo por código... pero lo he logrado, MIL GRACIAS!
-No sabía que con /// añades un comentario que también te comenta el icono del código... genial para identificar rápido las cosas. En ciertos objetos tengo como 3-10 iconos de piezas de código seguidos en un mismo evento, esto es genial, cómo nunca lo supe?
-Te has currado el ejemplo, o ya tenías parte hecho? Porque es super extenso, con la tilesheet, las luciérnagas, las antorchas animadas...
De nuevo gracias por el esfuerzo, lo bien explicado y la buena solución, si esque aún flipo T_T *DarkK coloca galletas y bollos en círculo y reza* eres mi nuevo dios, toma dos galletas