Error al Implementar Gravedad Y Salto Con Delta Time

Publicado por BoondDark, Julio 18, 2022, 01:16:04 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

BoondDark

Hola a todo mundo, espero que se encuentren muy bien, resulta que luego de comparar mi juego en diferentes ordenadores, resulta que algunas cosas con físicas o movimientos con aceleración varían respecto el ordenador. así que recurrí al Delta Time, lo que hice fue lo siguiente:

//Create
delta=(delta_time/1000000)*60;
g=0;
dir=0;

//Step
if(place_free(x,y+1)) {
    g+=0.4*delta;
}
    repeat(g*dir) {
        if(place_free(x,y+sign(g))) {
            y = y + sign(g);
        } else {
            g=0;
            break;
        }
    }
    if(g>0){dir=1;}else{dir=-1;}
if(keyboard_check_pressed(vk_space)){g-=12 *delta;}

//Begin Step
delta=(delta_time/1000000)*60;

El principal problema es que debería funcionar ya que con la función repeat esta tomando el valor de g que es lo que varia con los frames, resulta que cuando renderizo a 60 fps va bien, pero cuando lo pruebo a 30 fps salta muchísimo mas alto, ayuda por favor, por mas que intendo cosas no logro solucionar el problema, muchas gracias amigos, y espero que este sistema de salto de colisión precisa pueda servirle a quien lo necesite también

Clamud

Hola. Hice un script para calcular la posición y la velocidad  final de un objeto que se mueve con aceleración contante. Puede servir para resolver este problema.

[spoiler]
[gml]
/// array = acelerar( xi, vi, a, t, vm );
// Devuelve un array con posicion final y velocidad final

var xi = argument0; //posicion inicial
var vi = argument1; //velocidad inicial
var a = argument2; //aceleracion (debe ser positiva)
var t = argument3; //tiempo transcurrido (debe ser positivo)
var vm = argument4; //velocidad meta, es la velocidad a la que se debe acercar
var d; //desplazamiento
var v; //velocidad final
var r; //resultado
//var x; //posicion final

a *= sign(vm - vi); //signo de la aceleracion
//si v meta es mayor a v inicial, a es positiva
//si v meta es menor a v inicial, a es negativa
//si v meta es igual a v inicial, a es cero

v = vi + (a * t); //velocidad final

// si la velocidad rebasa la meta
if (abs(v - vi) > abs(vm - vi)) {
   var t1 = (vm - vi) / a; //tiempo en el que alcanza el limite
   var t2 = t - t1; //tiempo restante
   var d1 = (vi * t1) + (a * t1 * t1 / 2); //desplazamiento en el primer perido
   var d2 = vm * t2; //desplazamiento en el segundo periodo
   d = d1 + d2; //desplazamiento total
   v = vm; //velocidad final = velocidad meta
}
// si v no rebasa la meta
else d = (vi * t) + (a * t * t / 2); //desplazamiento

r[0] = xi + d; //posicion final
r[1] = v; //velocidad final
return r; //devolver resultado
[/gml]
[/spoiler]
Referencias:
https://es.wikipedia.org/wiki/Movimiento_parabólico
http://hyperphysics.phy-astr.gsu.edu/hbasees/acons.html

El script requiere 5 parámetros
xi: Posición inicial (donde inicial el movimiento)
vi: Velocidad inicial (la velocidad que lleva el objeto)
a: Aceleración (en este caso el valor de la gravedad)
t: Tiempo transcurrido (en este caso delta)
vm: Velocidad meta (para limitar la velocidad)

El script podría funcionar solo con los 4 primeros parámetros, pero en los plataformeros es necesario limitar la velocidad vertical, de lo contrario la velocidad incrementaría demasiado a causa de la gravedad. Si se mueve muy rápido podrá atravesar el piso.
La velocidad se limita dentro del script para asegurar que el desplazamiento nunca se calcule con velocidades mayores al límite.

Tu código podría quedar de esta manera (Es probable que debas modificar algunas cosas)
[gml]
//Create
delta = 0; //declarar delta, el valor se calcula en Step o Begin Step
g = 0; //gravedad, se activa cuando no hay piso
vv = 0; //velocidad vertical
vvl = 8; //velocidad vertical limite
d = 0; //desplazamiento
//dir = 0;

//Step
if(place_free(x,y+1)) { //si no hay piso
    g = 0.4; //activar la gravedad
}
else {
    g = 0; //desactivar gravedad
}
//calcular desplazamiento y velocidad provocadas por la gravedad
r = acelerar(y, vv, g, delta, vvl);
d = r[0] - y; //desplazmiento total
vv = r[1];

//mover pixel por pixel hasta colisionar
repeat (abs(d)) {
    if(place_free(x, y + sign(vv))) {
        y = y + sign(vv);
    } else {
        vv = 0;
        break;
    }
}

// saltar
if (keyboard_check_pressed(vk_space)) vv = -12;

//Begin Step
delta = (delta_time / 1000000) * 60; //calcular delta
[/gml]

Aquí puedes ver un ejemplo de funcionamiento del script. Presiona espacio para cambiar los fps. A veces debes hacer clic en Reload para que funcione correctamente.

BoondDark

Hola amigo!!!, muy buen script, esta genial la manera en que calculas ese desplazamiento, lo intente mi hermano, pero desafortunadamente cuando bajan los fps salta mas alto el jugador, no se la verdad porque sucede esto, pero técnicamente no hay ningún error por parte de tu lógica, tal vez el problema sea game maker con el calculo del delta time, ya que son valores muy volátiles la verdad, de todas formas muchas gracias por ayudar! <3

Jeffrey Faper

#3
EDITADO:
Olvide lo que dije, ya implemente delta en mis juegos y funciono correctamente
y es una maravilla,si ,pero tambien es un dolor de culo, este codigo fue el que me dio menos errores es de un usuario de esta comunidad asi que gracias a 0m@R.

//Begin Step 
var _cdelta=min(0.1, delta_time * 0.000001); //lo guardamos en una varible local

//delta time
if(!paused){
    delta=_cdelta; //current delta time
}else{
    //si el juego es pausado reseteamos delta para que no pasen cosas raras
    delta=0;
}
/*
puede crear una macros para acceder a delta, 
en lugar de escribir objControl.delta o global.delta que es muy largo y tedioso
por ejemplo crear macro ( name=dtm, value=objControl.delta)
y la aplicaria a su velocidad final asi y+=sign(hspd)*dtm; 
*/


286 Visitantes, 0 Usuarios