Se puede revisar pixel por pixel, como dice Niu, pero el proceso sería muy pesado y no sería recomendable que se ejecute en cada Step.
Una forma de optimizar sería realizar la comprobación en pasos más grande y al encontrar colisión ir refinando poco a poco el cálculo de la distancia. Por ejemplo, para detectar la distancia horizontal a la derecha, se comprobaría con place_free en pasos iguales a la anchura del player, después al detectar colisión, se comprobaría la posición libre en sentido contrario haciendo pasos de un pixel. Sería más óptimo si los pasos se reducen a la mitad en cada evento de detección de colisión o detección de espacio libre.
Si todos los objetos son rectángulos, creo que sería mejor usar un método que compruebe la distancia de "intervalos".
Usemos este script:
[gml]
///interA( a,b, c,d );
//Dados dos intervalos ABIERTOS (a,b) y (c,d)
//devuelve true si hay interseccion
return argument0 < argument3 and argument1 > argument2;
[/gml]
Sea (x1,y1) la posición de la esquina superior izquierda de un rectángulo y (x2,y2) la esquina contraria.
La distancia a la derecha se podría calcular así (en el objeto player):
[gml]
d = "Inf"; //distancia infinita
var t;
with( obBlock )
{
if interA( other.y1,other.y2, y1,y2 ) //si los rectangulos se "ven" en direccion horizontal
{
t = x1 - other.x2; //distancia a la derecha
if( t > 0 ) //si el bloque esfectivamente esta a la derecha
if( t < d //y la distancia es menor a otra encontrada
or d == "Inf" ){ //o no se ha encontrado otra distancia valida
d = t; //la menor distancia es igual a t
}
else if( t == 0 ){ //si t es cero
d = 0; //la distancia es cero
break; //no es necesario seguir buscando
}
}
}
//d contiene el resultado
[/gml]
Una forma de optimizar sería realizar la comprobación en pasos más grande y al encontrar colisión ir refinando poco a poco el cálculo de la distancia. Por ejemplo, para detectar la distancia horizontal a la derecha, se comprobaría con place_free en pasos iguales a la anchura del player, después al detectar colisión, se comprobaría la posición libre en sentido contrario haciendo pasos de un pixel. Sería más óptimo si los pasos se reducen a la mitad en cada evento de detección de colisión o detección de espacio libre.
Si todos los objetos son rectángulos, creo que sería mejor usar un método que compruebe la distancia de "intervalos".
Usemos este script:
[gml]
///interA( a,b, c,d );
//Dados dos intervalos ABIERTOS (a,b) y (c,d)
//devuelve true si hay interseccion
return argument0 < argument3 and argument1 > argument2;
[/gml]
Sea (x1,y1) la posición de la esquina superior izquierda de un rectángulo y (x2,y2) la esquina contraria.
La distancia a la derecha se podría calcular así (en el objeto player):
[gml]
d = "Inf"; //distancia infinita
var t;
with( obBlock )
{
if interA( other.y1,other.y2, y1,y2 ) //si los rectangulos se "ven" en direccion horizontal
{
t = x1 - other.x2; //distancia a la derecha
if( t > 0 ) //si el bloque esfectivamente esta a la derecha
if( t < d //y la distancia es menor a otra encontrada
or d == "Inf" ){ //o no se ha encontrado otra distancia valida
d = t; //la menor distancia es igual a t
}
else if( t == 0 ){ //si t es cero
d = 0; //la distancia es cero
break; //no es necesario seguir buscando
}
}
}
//d contiene el resultado
[/gml]