Aquí va un análisis del problema.
Se me ocurren dos formas ligeramente diferentes para realizar el movimiento parabólico:

*La primera es usar el método que se ve frecuentemente en los tutoriales de GM, en el que se hace una aproximación del movimiento de un objeto real. Primero se definen las siguientes variables
[gml]
vx = //velocidad horizontal
vy = //velocidad vertical
g  = //gravedad
[/gml]
y el desplazamiento se realiza de esta forma (en el evento Step)
[gml]
vy += g; //efecto de la gravedad
x += vx; //desplazamiento
y += vy;
[/gml]
así se obtiene una trayectoria parabólica, no obstante, los significados de velocidad y aceleración son un poco diferentes a los de un objeto real.

*La segunda forma es definir la trayectoria del proyectil como se estudia en física clásica. Usaremos este método para no tener que pensar tanto, pues ya existen muchas fórmulas para calcular todas las características del lanzamiento, y hay mucha información en Internet (aunque prefiero los libros de texto para estudiar estos temas, por lo general la información de Internet no es muy clara).

Para un objeto con aceleración constante, la posición se define como una función del tiempo
r(t) = ri + vit + at2/2
la expresión anterior, en forma vectorial, puede definir el movimiento de un objeto en un espacio de cualquier número de dimensiones. En este caso el movimiento es en 2 dimensiones, y como la aceleración (gravedad) se aplica sólo en dirección vertical, se puede representar como la superposición de 2 movimientos independientes: uno en dirección horizontal con velocidad constante, y otro en dirección vertical que es afectado por la aceleración de la gravedad. Se modifica la expresión anterior para definir el movimiento en y
y(t) = yi + vyit + gt2/2
yi es la posición inicial (en pixeles)
vyi es la velocidad vertical inicial( en px/step)
g es la gravedad (en px/step2)
(la unidades sólo son para tener un planteamiento formal)

Al derivar la ecuación anterior se obtiene la expresión de la velocidad como función del tiempo
vy(t) = vyi + gt

Con esto ya podemos hacer que el objeto se mueva en una trayectoria parabólica, sin embargo, las expresiones anteriores se pueden simplificar si consideramos que la posición se actualiza en unidades de tiempo (steps) y hacemos que la posición inicial sea la del step anterior
y = y + vy + g/2
vy = vy + g
entonces el código quedaría así (en el evento Step)
[gml]
x += vx;
y += vy +g/2;
vy += g;
[/gml]

#16 Julio 25, 2015, 08:49:30 PM Ultima modificación: Julio 26, 2015, 04:56:05 PM por Clamud
Ahora viene la segunda parte; calcular el lanzamiento con precisión.

Propongo que el lanzamiento sea de 45 grados, así se simplifican algunos cálculos. Digamos que el alcance horizontal es de 20 espacios de 24 px (480 px en total) y lo representamos con la letra X mayúscula. Como el ángulo de lanzamiento es de 45 grados, se tiene la siguiente relación
X = vi2/g
vi es la magnitud de la velocidad inicial, considerando las 2 dimensiones del movimiento.

¿Cómo establecemos los valores que faltan?
Podemos proponer el tiempo requerido para completar el vuelo y de ahí calcular la velocidad de lanzamiento y la gravedad, también podemos proponer la velocidad de lanzamiento y calcular la gravedad. Yo elijo proponer la gravedad y calcular la velocidad de lanzamiento, y después hacer muchas pruebas.

Hay un ejemplo adjunto a este mensaje. En la primera room, el personaje tiene un alcance horizontal X = 480 px que no cambia. Lo que se puede cambiar es el valor de la gravedad; notarás que al aumentar el valor de g el tiempo de vuelo se reduce. Si quieres un lanzamiento super rápido (con g alta) el código del ejemplo puede tener errores (prueba con g = 4), para evitarlo sería necesario usar la ecuación larga de la posición como función del tiempo. En este ejemplo es preferible usar valores de g menores que 1.

Veamos las partes importantes de obPlayer0
En el evento Create se declaran las variables
[gml]
///Sin movimiento al principio

vx = 0; //velocidad horizontal
vy = 0; //velocidad vertical
g = 0.2; //gravedad

X = 20*24; //alcance horizontal maximo (20 bloques * 24 px)
vi = sqrt( X*g ); //velocidad inicial (de lanzamiento)
[/gml]
vi se calcula despejando la ecuación anterior.
Al presionar el dígito 2 se inicia el lanzamiento
[gml]
///Iniciar lanzamiento

x = xstart; //pos. inicial
y = ystart;
vx = vi/sqrt(2); //= vi*sen(45 grados); vel. horizontal
vy = -vx; //velocidad vertical (magnitud igual a vx)
[/gml]
vx y vy tienen la misma magnitud porque el ángulo de despegue es de 45 grados.
En el evento Step se realiza el movimiento
[gml]
///Desplazamiento

x += vx;
y += vy + g/2;
vy += g;

//aterrizaje
if( y >= ystart )
{
    vx = 0;
    vy = 0;
    move_snap( 24, 24 );
}
[/gml]
La primera parte es igual a la que puse en el mensaje anterior, el aterrizaje ocurre al cruzar la línea horizontal que pasa por el punto de despegue y la función move_snap asegura la alineación.

Presiona el dígito 3 para cambiar de room. En la segunda habitación el lanzamiento depende de la barra de distancia. Aquí el cambio significativo es el código de lanzamiento
[gml]
///Iniciar lanzamiento

x = xstart; //pos. inicial
y = ystart;

X = round(20*barra/100)*24; //alcance horizontal
vi = sqrt( X*g );

vx = vi/sqrt(2); //= vi*sen(45 grados); vel. horizontal
vy = -vx; //velocidad vertical (magnitud igual a vx)
[/gml]
el alcance X se determina con el valor de la barra (con la función round se obtiene un número entero de bloques, que se multiplica por 24 px).

Toma en cuenta que los puntos de lanzamiento y de aterrizaje están a la misma altura, si quieres que la resortera (punto de lanzamiento) esté sobre el piso hay que agregar otros códigos para tener un aterrizaje exacto.

MUCHAS GRACIAS CLAMUD!!!  :D
No entendí mucho...  XD pero si capté la esencia  :-[
GRACIAS POR TU ESFUERZO...
La segunda parte es que termine en snap 24,24 ?? no
Pero estaba pensando que el player al chocar el piso PLANO siga avanzando(0° grados(derecha)) y vaya bajando la velocidad hasta que al pasar por un 24,24 quede ahí...
BUENO, es solo una idea... espero tu respuesta  :D  :D  :D
- Empty -

#18 Julio 26, 2015, 07:23:21 PM Ultima modificación: Julio 26, 2015, 07:31:04 PM por Yoo
GRACIAS, lo he probado y funciona correctamente!!!  :D  :D  :D  :D
PERO... al intentar hacer unas graditas como estas... eso(el movimiento queda horizontal  XD)
GRACIAS por todo, ya pensare en algo...

MOD: Ya lo solucioné!!!(eso creo) solo crpee un obj_solid y cambie una parte del code STEP del player , osea esto:

//aterrizaje
if(!place_free(x,y+1))
{
    vx = 0;
    vy = 0;
    move_snap( 24, 24 );
}


NOTA: yo tambn estaba intentando hacer algo, asi que les dejo algo que hice...(me falta el aterrizaje   :-[)
- Empty -

YA LO MEJORE UN POKITO(eso creo)
Le agregué aterrizaje con inercia y en pisos bajos... (no esta al cien pero es algo  :D )
GRACIAS CLAMUDDD...  :D  :D  :D
Te debo todas  XD
- Empty -

Para hacer lanzamientos con diferente ángulo tenemos 2 alternativas:

* Si el ángulo es constante y el aterrizaje debe ser exacto, primero se define el alcance horizontal (X), se define el ángulo (angulo) y se calcula la velocidad inicial (vi)
[gml]
vi = sqrt( X*g / sin(degtorad(2*angulo)) );
[/gml]
se debe poner degtorad si el ángulo está en grados.
Después se calculan las componentes de la gravedad
[gml]
vx = lengthdir_x( vi, angulo );
vx = lengthdir_y( vi, angulo );
[/gml]

* Si el ángulo es variable, no conviene definir primero el alcance horizontal, en este caso la variable X no se utiliza porque el aterrizaje no es exacto (se deberá utilizar el deslizamiento). Primero se define la velocidad inicial y el ángulo, y las componentes se calculan directamente
[gml]
vx = lengthdir_x( vi, angulo );
vx = lengthdir_y( vi, angulo );
[/gml]
el código es igual al anterior.
Es importante notar que la velocidad inicial no es linealmente proporcional al alcance horizontal, la relación es cuadrática, entonces existen más probabilidades de hacer un lanzamiento largo que uno corto.