Napisałem bardzo prosty silnik fizyczny do obsługi ruchu gracza i kolizji w grze typu FPS.
Chciałbym wiedzieć w jaki sposób najlepiej obsługiwać szybkość świata silnika fizycznego.
Próbowałem stworzyć metodę Entity::update(float ticks)
, która "przeskakiwałaby" odpowiednią wielkość przyśpieszenia (ogólnie zmiany prędkości) oraz liczbę "metrów" o jakie zostałby przeniesiony gracz przy jej wywołaniu, tak, że przy podaniu liczby jej wywołań na sekundę float ticks
, ciągle, niezależnie od ich liczby fizyka miałaby stałą prędkość.
physics.h
#ifndef PHYSICS_H
#define PHYSICS_H
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
class Entity
{
public:
bool collidable;
bool dynamic;
double posx, posy, posz;
float velx, vely, velz;
float gravity;
float acceleration;
float brakes;
float resistance;
float maxFallSpeed;
Entity(void);
~Entity(void){}
void accelerate(float ax, float ay, float az);
void brake(float bx, float by, float bz);
void update(float elapsed);
bool collided(Entity body);
};
class Animal : public Entity
{
public:
float walkSpeed;
float runSpeed;
Animal(bool = true, bool = true);
~Animal(void){}
};
#endif
physics.cpp
#include <iostream>
#include "physics.h"
Entity::Entity(void)
{
posx = 0, posy = 0, posz = 0;
velx = 0, vely = 0, velz = 0;
gravity = 9.80665;
acceleration = 0.2;
brakes = 2.0;
resistance = 2.0;
maxFallSpeed = 90.0;
}
void Entity::accelerate(float ax, float ay, float az)
{
velx += ax;
vely += ay;
velz += az;
}
void Entity::brake(float bx, float by, float bz)
{
//X AXIS BRAKING
if(velx > 0 && bx < velx)
velx -= bx;
else if(velx < 0 && bx > velx)
velx += bx;
else
velx = 0;
//Y AXIS BRAKING
if(vely > 0 && by < vely)
vely -= by;
else if(vely < 0 && by > vely)
vely += by;
else
vely = 0;
//Z AXIS BRAKING
if(velz > 0 && bz < velz)
velz -= bz;
else if(velz < 0 && bz > velz)
velz += bz;
else
velz = 0;
}
void Entity::update(float ticks)
{
if(dynamic)
{ //Tutaj wiem co jest źle, tylko to zostawiłem, może pomoże mnie zrozumieć (co chcę zrobić)
//Tutaj prędkość jest dodawana do pozycji przed ukończeniem jej zwiększania i prędkość grawitacji tak samo(prędkość może być zwiększana co sekundę, ale to by nie było płynne, po za tym jeżeli dam to co 1 ms, to fizyka będzie spowolniona, gdy ktoś nie będzie uruchamiał update() co najmniej 1000 razy na sekundę (potrzebuję czegoś by tego wszystkiego uniknąć)
if(vely < maxFallSpeed)
accelerate(0, -gravity/ticks, 0); //GRAVITY ACCELERATION
brake(resistance/ticks, resistance/ticks, resistance/ticks); //AIR RESISTANCE (SIMPLE)
posx += velx/ticks; //APPLYING POSITION
posy += vely/ticks; //-||-
posz += velz/ticks; //-||-
}
}
Animal::Animal(bool d, bool c)
{
collidable = c;
dynamic = d;
walkSpeed = 0.8;
runSpeed = 2.3;
};
int main()
{
float TICKS_PER_SECOND = 64;
DWORD timer = GetTickCount();
DWORD t = GetTickCount(); //Timer do wyłączania aplikacji
Animal body(true, true);
//body.accelerate(0.0, 0.0, 1);
while(GetTickCount() < t+6000) //Uruchamiam aplikację tylko na sześć sekund
{
if(GetTickCount() > timer + (1000/TICKS_PER_SECOND))
{
timer = GetTickCount();
if(GetAsyncKeyState(VK_SPACE) & 1 && body.velz < body.runSpeed)body.accelerate(0.0, 0.0, 1);
body.update(TICKS_PER_SECOND);
std::cout<<body.posx<<", "<<body.posy<<", "<<body.posz<<"\n";
}
}
return 0;
}
W jaki sposób to zaimplementować, żeby działało?
Prosiłbym także o podanie jakiegoś tutorialu na temat wykrywania kolizji ścian (nie mogą być to sześcienne bounding box'y, muszę wykrywać kolizję z terenem, może być nawet w 2d).