Leyes de Newton
Para calcular el comportamiento real de nuestros objetos en el mundo 3D, basta con que nos busquemos algo lo mas sencillo posible y que no sea muy "caro" de calcular. Todos sabemos que en el mundo real existen miles de fuerzas, constantes, factores, etc... que constituyen la fisica real que rige nuestro mundo. Pero cuando programamos un juego debemos olvidarnos de todo aquello que no afecte directamente y en gran medida al movimiento de nuestro objeto.
Las Leyes de Newton son una leyes sencillas y eficaces, suficientes para la mayoria de los comportamientos que queremos representar en nuestros juegos.
1. Todo objeto tiende a mantener su estado de movimiento uniforme a no ser que se le apliquen fuerzas externas.
2. La relacion entre la masa de objeto (m), la aceleracion (a), y la fuerza aplicada (F) es la siguiente: F=m·a
3. Para cada accion existe una reaccion opuesta y de misma magnitud.
En otras palabras mas utiles: Una fuerza cambia la velocidad de un objeto, y la velocidad del objeto cambia su posicion. En los juegos no estamos calculando fisicas todo el rato, se trata de una operacion discreta, lo que quiere decir que el calculo tiene que modificar el estado del objeto durante un corto periodo de tiempo. Vamos a llamar dt a este tiempo (diferencia de frames) y la usaremos en nuestros calculos.
Otras notaciones que necesitaremos por el estado del objeo son:
- T. La matriz de transformcion de nuestra matrix, indicando su posicion y orientacion
- v. La velocidad del objeto (un vector 3D)
- m. La masa del objeto
Vamos a comenzar con un ejemplo sencillo: La caida libre de un objeto.... La fuerza aplicada al objeto es la fuerza de la gravedad (nos olvidamos de la resistencia del viento y tonterias por el momento). La fuerza de la gravedad es unu vector que tiene una direccion en el eje y negativo (hacia abajo) y una magnitud que depende del juego (si es en la tierra, en la luna, etc...) pero que en cualquier caso es propocional a la masa del objeto. Usaremos por el momento la constante g que estara definida en nuestro juego con el valor que queramos. Tenemos pues que el vector de la gravedad es (0, -m·g, 0)
Los calculos van a ser los siguientes:
- Calcular la aceleracion, a , que es la fuerza dividida por la masa del objeto (segun la segunda ley de Newton)
a = (1/m) * (0, -m·g, 0) = (0, -g, 0)
- La velocidada cambia de acuerdo a la aceleracion y la diferencia de tiempo
v = v + a * dt = v + (0, -dt·g, 0)
- La posicion (que son los 3 primeros elementos de la cuarta columna de la matriz transformacion) se modifican de acuerdo a la velocidad y la diferencia de tiempo. Por el momento para no liarnos vamos a llamar a la posicion P
P += v * dt
Si no hay fuerza, la aceleracion es 0 y la velocidad se mantiene constante (segun la primera ley de Newton)
Con una aceleracion constante, resultado de una fuerza constante (la gravedad en caida libre), obtenemos el resultado de que el objeto cae mas y mas rapido todo el tiempo, que es lo que esperamos de una caida libre.
Para un caso mas general, la fuerza aplicada a un objeto en cada frame es el resultado de todas las fuerzas que afectan al objeto en ese periodo de tiempo. Por ejemplo, si de repente llega Superman e intenta detener nuestro objeto que cae libre, la fuerza que aplicaremos al fin y al cabo sobre el objeto sera la de la gravedad menos la de Superman.
Esto que parece sencillo no lo es tanto, sobretodo mas cuando queramos unir esto a nuestra deteccion de colisiones... porque, el objeto cae ibre, muy bien, pero que pasa cuando choca contra algo? hay que detectarr esa colision, calcular los vectores de "rebote" y las velocidades, etc... Para entonces usaremos algo que se llama "momento". Por el momento :) vamos a decir que el "momento " es simplemente su velocidad por la masa ( m·v )
Veamos como hacemos para meter todo esto dentro de una clase:
class FisicasObjeto
{
public:
void Avanzar(float dt)
{
//Calcular la aceleracion. a=F/m
Vector3D aceleracion = (1.0f / m_Masa) * m_Fuerza
//Modificar la velocidad
m_Velocidad += dt * aceleracion;
//Modificar la posicion
m_Posicion += dt * m_Velocidad;
}
protected:
Vector3D m_Position; //Posicion en el espacio 3D
Vector3D m_Velocidad; //Velocidad actual
Vector3D m_Fuerza; //Fuerza TOTAL aplicada
float m_Masa; //Masa del objeto
};
Como ves tampoco es nada del otro mundo :)
La funcion "Avanzar" se llama cada vez que el bucle del juego hace un calculo de fisicas. Esto modifica el objeto de acuerdo a la diferencia del tiempo (dt). Usando el vector posicion integramos las fisicas y los graficos para tener nuestro objeto visible en la pantalla actuando de un modo real.
Calcular la duraccion del frame
Nos queda algo pendiente, y es ese parametro (dt) que he utilizado en la case anterior. No te has preguntado todo el rato que diablos es eso de la "diferencia de tiempo"??? Pues bien, esta "diferencia de tiempo" sirve nada mas ni nada menos que para indicar cuanto tiempo a pasado desde un frame a otro (ya que por supuesto las unidades de tiempo del mundo real no son las mismas que nuestro juego!)
Este parametro es calculado generalmente por la aplicacion y se pasa a esta funcion (o a cualquier otra funcion de fisicas que implementes).
Una forma facil de medir esta duracion es simplemente anotar la hora del reloj antes del frame y despues, luego restas los valores y ya tienes la duraccion del frame.
aqui tienes el codigo para hacerlo, nos sera de gran utilidad tambien a la hora de detectar colisiones...
DWORD cur=GetTickCount(); float dt=(cur-m_last)*0.001f; if(m_Last==0) dt=0.0.2f; m_Last=cur;
GetTickCount() devuelve el numero de milisegundos que han pasado desde que Windows fue iniciado. m_Last es un valor recordado entre frames que almacena el punto en el tiempo que comienza el frame. Por supuesto, el punto en el que acaba un frame es el comienzo del siguiente. (ammm :-O ) El parametro dt esta en segundos, para ello lo hemos dividido por 1000
>> Cick para siguiente capitulo: Fuerzas en los juegos >>