Game Maker: Cómo deformar un sprite

GreyShock

¡Hola amigos! ¿Alguno de vosotros conoce alguna manera de deformar un sprite? Lo que quiero conseguir es sesgar una imagen para crear una sombra rollo esto:

He llegado a esto:

draw_sprite_ext(parent.sprite_index,parent.image_index,parent.x,
parent.y+parent.footground*global.zoom*1.5,parent.image_xscale,
parent.image_yscale*-0.5,parent.image_angle,c_black,0.2);

Con lo que dibujo a los pies del personaje su mismo sprite, achatado, y de color negro con el alpha al 20%, peeero, no sé como conseguir darle perspectiva oblicua.

¿Alguien domina de deformaciones en Game Maker? :)

grivcon

#1 creo que buscas lo que se llama cavalier oblique projection

GreyShock

He descubierto que en inglés lo que quiero hacer se llama SKEW y me ha servido para encontrar esta función:

draw_sprite_pos(parent.sprite_index,
                            parent.image_index,
                            parent.x+parent.sprite_width,
                            parent.y+parent.sprite_height*2,
                            parent.x+parent.sprite_width*2,
                            parent.y+parent.sprite_height*2,
                            parent.x+parent.sprite_width,
                            parent.y+parent.sprite_height,
                            parent.x,
                            parent.y+parent.sprite_height,
                            0.2);

http://docs.yoyogames.com/source/dadiospice/002_reference/drawing/drawing%20sprites%20and%20backgrounds/draw_sprite_pos.html

He conseguido dibujar el sprite de forma oblicua y con el alpha al 20%... pero esta función no admite cambiar el color del sprite... así que ahora estoy buscando si existe una manera de cambiar el color de forma independiente Y__Y

1 1 respuesta
Potito

#3 no puedes hacerlo con image_blend ? No se si se puede teñir al negro total

1 respuesta
GreyShock

#4 He probado image_blend y también draw_set_color antes de utilizar draw_sprite_pos en el evento Draw del objeto... pero parece que nada afecta a esta función :(

1 respuesta
Potito

#5 He visto que muchos juegos usan sombras genericas para los personajes cuando son similares, a lo mejor usando un sprite especifico para la sombra de cualquiera...

GreyShock

OK, me ha costado toda la tarde pero lo he conseguido al fin.

            if(surface_exists(o_5_control.surf_shadow)){       
surface_set_target(o_5_control.surf_shadow); draw_clear_alpha(0, 0); draw_sprite_pos(parent.sprite_index, parent.image_index, parent.x+parent.sprite_width, parent.y+parent.sprite_height*2, parent.x+parent.sprite_width*2, parent.y+parent.sprite_height*2, parent.x+parent.sprite_width, parent.y+parent.sprite_height, parent.x, parent.y+parent.sprite_height, 1); surface_reset_target(); draw_surface_ext(o_5_control.surf_shadow, 0, 0, 1, 1, 0, c_black, 0.2); }else{ o_5_control.surf_shadow = surface_create(room_width,room_height); }

Utilizo una surface de Game Maker.

o_5_control es un objeto general desde el que gestiono la lógica del nivel, ahí creo una surface (o_5_control.surf_shadow) y en el evento draw del objeto sombra, cambio el destino de dibujo a la superficie surf_shadow, después devuelvo el draw a la aplicación y dibujo esta superficie en la que he dibujado el sprite deformado pero aplicando un blend negro y un alpha del 20%.

POR FIN.

Si alguien quiere saber más sobre las surfaces y sus utilidades, hay un hilo de Chevy Ray en TIGSource bien majo y detallado:

http://forums.tigsource.com/index.php?topic=7441.0

1
Crucialhunte

Gracias por poner lo que vas descubriendo, puede que a mas de uno nos estés salvando una tarde entera de investigación.

Una imagen del resultado no tendrás no :P ?

1 respuesta
GreyShock

#8 Una muy disimulada, ya que es un spoiler de Gods Will Be Watching xD pero algo pondré, sí :)

GreyShock

POR FIN! Tras siete horas de trabajo, las malditas sombras están listas y optimizadas

///draw shadows
//manage surface
if(surface_exists(surf_shadow)){
    surface_set_target(surf_shadow);
    draw_clear_alpha(0, 0);
}else{
    surf_shadow = surface_create(room_width,room_height);
    surface_set_target(surf_shadow);
}

//handle every shadow in the room
with(o_5_char_shadow){
    if(parent>-1){
        if(instance_exists(parent)){
            if(parent.visible){
                //transformation points
                var px = parent.x;
                var py = parent.y;
                var w = sprite_get_width(parent.sprite_index)*global.zoom;
                var h = parent.footground*global.zoom;
                var wd = 50; //horizontal iclination
                var hd = h/1.5; //vertical inclination
                var xoff = (sprite_get_xoffset(parent.sprite_index)+1)*global.zoom;
                var yoff = parent.sprite_height-(parent.footground+1)*global.zoom; 
                //check if there's the necessity of duplicating a new sprite
                if(parent.sprite_index!=last_sprite){
                    //delete previous duplicated sprite
                    if(sp!=-1) sprite_delete(sp);
                    //create new duplicated sprite
                    sp = sprite_duplicate(parent.sprite_index);
                    sprite_collision_mask(sp,false, 1, 0, 0, 0, 0, 1, 0);
                    last_sprite = parent.sprite_index;
                }
                sprite_index = sp;
                //draw skewed sprite
                draw_sprite_pos(sprite_index,
                                parent.image_index,
                                px+wd-xoff,
                                py+h+hd,
                                px+w+wd-xoff,
                                py+h+hd,
                                px+w-xoff,
                                py+h-yoff,
                                px-xoff,
                                py+h-yoff,
                                1);
            }
        }else{
            instance_destroy();
        }
    }
}

//reset drawing target
surface_reset_target();
//draw the modified shadow sprites with black blending color and 20% alpha
draw_surface_ext(surf_shadow, 0, 0, 1, 1, 0, c_black, 0.1);

leer mejor en Pastebin: http://pastebin.com/yFFtpPjv

Cuando no esté tan reventao arreglaré un poco todo y haré algún mini tutorial o algo, que he sudado sangre con lo que parecía una tontería...

1
javifugitivo

Muy muy interesante, me lo guardo para el futuro por si puede ser útil. Yo también he estado varias semanas liado buscando un sistema de iluminación que me convenciera. El principal problema que hay con game maker actualmente es que las luces que proyectan sombras dinámicas consumen mucho rendimiento así que tienes que optimizar mucho.

Tu sistema es genial ya que imagino que provoca sombras en movimiento de todos los sprites e incluso podrías cambiar la perspectiva. ¡Buen trabajo!

itoaragon

GreyShock, a mi se me ocurrió dibujar la sombra como un primitivo con textura, e ir modificando los cuatro vértices conforme a la distancia desde el origen de la luz.

Al menos en mi juego lo he hecho así y funciona sin problemas:

1.- En el create event inicializamos y asignamos el objeto que se convertira en objetivo que queremos que arroje una sombra

// Initialize
shadow_alpha = 0
target = instance_nearest(x,y,obj_hibari)

2.- En el step event vamos actualizando las coordenadas de los vértices que determinan la textura. Yo aprovecho para calcular la opacidad de la sombra (que será menor conforme más lejos esté el punto luminoso).

// Update shadow vertex coordinates

xdif = (target).x - x
ydif = (target).y - y

// Vertex 1
ax = ((target).x  - ((target).sprite_width/2))+ xdif 
ay = (target).y + ydif
// Vertex 2
bx = ((target).x  + ((target).sprite_width/2))+ xdif  
by = ay // Vertex 3 cx = (target).x - ((target).sprite_width/2) cy = (target).y // Vertex 4 dx = (target).x + ((target).sprite_width/2) dy = (target).y // Update shadow alpha value // The further the light source is, the lower this value becomes xdif2 = (target).x - x xdif2 /= 600 if xdif2 < 0 {xdif2 *= -1} shadow_alpha = 0.7 - xdif2

3.- Finalmente en el draw event dibujamos la textura con los datos de coordenadas calculados en el step event.

// Draw shadow as a primitive with texture

draw_set_color(c_black);
draw_set_alpha(shadow_alpha)
texture = sprite_get_texture((target).sprite_index, (target).image_index)
texture_set_interpolation = true
draw_primitive_begin_texture(pr_trianglestrip,texture);
draw_vertex_texture(ax,ay,0,0);
draw_vertex_texture(bx,by,1,0);
draw_vertex_texture(cx,cy,0,1);
draw_vertex_texture(dx,dy,1,1);
draw_primitive_end();

El resultado:

Lo dejo ahí por si le sirve a alguien.

Saludos

4 1 respuesta
GreyShock

#12 OH! Disculpa la tardanza en contestar, se me había pasado por alto este hilo.

Tiene muy buena pinta tu manera de realizarlo, intentaré aplicarla a Gods Will Be Watching si saco algo de tiempo entre la beta y la entrega final :'(

Lo que más me gusta de tu forma de hacerlo es que no usa surfaces, y eso es bueno, ya que en testing con ordenadores antiguos la surface tira de gráfica y hace que vaya como el culete, así que tuve que meterle un detector de fps y en caso de que se fueran al garete, eliminar las sombras para las máquinas menos... aventajadas xD

///draw shadows
if(!slow_performance){//switch off shadows if the performance is low
    //manage surface
    if(surface_exists(surf_shadow)){
        surface_set_target(surf_shadow);
        draw_clear_alpha(0, 0);
    }else{
        surf_shadow = surface_create(room_width,room_height);
        surface_set_target(surf_shadow);
    }
    
//handle every shadow in the room if(instance_exists(o_5_char_shadow)){ with(o_5_char_shadow){ if(parent>-1){ if(instance_exists(parent)){ if(parent.visible){ //transformation points var px = parent.x; var py = parent.y; var w = sprite_get_width(parent.sprite_index)*global.zoom; var h = parent.footground*global.zoom; var wd = 50; //horizontal iclination var hd = h/1.5; //vertical inclination var xoff = (sprite_get_xoffset(parent.sprite_index)+1)*global.zoom; var yoff = parent.sprite_height-(parent.footground+1)*global.zoom; //check if there's the necessity of duplicating a new sprite if(parent.sprite_index!=last_sprite){ //delete previous duplicated sprite if(sp!=-1) sprite_delete(sp); //create new duplicated sprite if(parent.sprite_index!=-1){ sp = sprite_duplicate(parent.sprite_index); sprite_collision_mask(sp,false, 1, 0, 0, 0, 0, 1, 0); }else{ sp = -1; } last_sprite = parent.sprite_index; } //draw skewed sprite if(sp!=-1){ //only if it has a valid sprite_index draw_sprite_pos(sp, parent.image_index, px+wd-xoff, py+h+hd, px+w+wd-xoff, py+h+hd, px+w-xoff, py+h-yoff, px-xoff, py+h-yoff, 1 ); } } }else{ instance_destroy(); } } } } //reset drawing target surface_reset_target(); //draw the modified shadow sprites with black blending color and 20% alpha draw_surface_ext(surf_shadow, 0, 0, 1, 1, 0, c_black, 0.1); } //calculate performance if(fps_real<room_speed and !slow_performance){ slow_meter++; if(slow_meter>57) slow_performance = true; }else{ slow_meter--; slow_meter = clamp(slow_meter,0,200); }

Así es como se ve el código con el limitador de FPS.

Pero a cualquiera que lea este hilo, le recomiendo que use el método de itoaragon sin duda.

Pongo el resultado de mis sombras en un gif super recortado para evitar spoilers del juego xD

2
1 comentario moderado

Usuarios habituales