tcs

02-20-2000, 12:43 PM

Hello,

I have a question on how to implement physics.

My current physics:

I have a CMotion class that accepts motion vectors. In my message loop,

I call the ApplyMotion(dwTimeElapsedSinceLastCall); function of this

class. Since all my motion behavior (like speed, acceleration) are defined

for one second, my class has to look how many time has elapsed and then

scale the things to this time. Things like gravity and gravity acceleration

are also applied from this class.

This works very well, but I have problems to convert keyboard & mouse input

to vectors for my class. If I pass a forward vector to my class every time

my HandleKeyboard() function realizes the forward key is pressed, my acceleration

would depend on how often this function could be called. Bad. So I have to

scale this too. I call something like AddForwardVector(dwTimeElapsedSinceLastCall);

and the forward vector is so scaled that the whole acceleration is applied when

I hold my forward key a full second down, regardless of how often HandleKeyboard()

is called.

My problem:

This method requires for all forces to be applied over the time. I want to let the player

jump, but to jump you shouldn't have to hold the mouse button down like walking. But when

I call my Jump(); it adds a vector to my CMotion class which will be smoothed out quickly

by the other ones.

Here is my source (sorry):

================================================== ============================

CMotion::CMotion()

{

// Init motion behavior with standard values. Every values is meant

// to be applied in 1000ms

m_SlowDown = 7.5f;

m_MidAirSlowDown = 0.1f;

m_GravityAcceleration = 2.5;

m_Gravity[x] = 0.0f;

m_Gravity[y] = -0.15f;

m_Gravity[z] = 0.0f;

// Init other member variables

m_MidAir = FALSE;

m_SmallestForce = 0.01f;

m_AccelerationTime = 100;

m_MidAirAccelerationTime = 500;

m_JumpForce[x] = 0.0f;

m_JumpForce[y] = 1.0f;

m_JumpForce[z] = 0.0f;

m_CurrentGravity[x] = 0.0f;

m_CurrentGravity[y] = 0.0f;

m_CurrentGravity[z] = 0.0f;

}

CMotion::~CMotion()

{

}

void CMotion::ApplyMotionPhysics(DWORD dwTimeElapsed)

{

// Calculate the movement that would happen in dwTimeElapsed ms

// Copy the current motion vector to cFinalForce

CForce cFinalForce = m_Force;

// Is camera in the air ?

CheckMidAir();

// Apply gravity to the final movement vector

if (m_MidAir)

{

// Camera is diving, apply gravity acelleration

m_CurrentGravity[x] += ScaleToElapsedTime(m_CurrentGravity[x] * m_GravityAcceleration, dwTimeElapsed);

m_CurrentGravity[y] += ScaleToElapsedTime(m_CurrentGravity[y] * m_GravityAcceleration, dwTimeElapsed);

m_CurrentGravity[z] += ScaleToElapsedTime(m_CurrentGravity[z] * m_GravityAcceleration, dwTimeElapsed);

// Apply gravity

cFinalForce += m_CurrentGravity;

}

else

// Camera is on the ground, set current gravity to default gravity

m_CurrentGravity = m_Gravity;

// Scale the final motion vector relative to dwTimeElapsed

cFinalForce[x] = ScaleToElapsedTime(cFinalForce[x], dwTimeElapsed);

cFinalForce[y] = ScaleToElapsedTime(cFinalForce[y], dwTimeElapsed);

cFinalForce[z] = ScaleToElapsedTime(cFinalForce[z], dwTimeElapsed);

// Pass the position after the motion to the CCamera class

SetXPos(GetXPos() + cFinalForce[x]);

SetYPos(GetYPos() + cFinalForce[y]);

SetZPos(GetZPos() + cFinalForce[z]);

// Lift the camera up to the terrain if he has descended below it

float fHeight = GetSurfaceHeight();

if (GetYPos() < fHeight)

{

// Lift camera up

SetYPos(fHeight);

// No acceleration upwards

m_Force[y] = 0.0f;

}

// Slow the motion down

// Use m_MidAirSlowDown when camera is in the air

if (m_MidAir)

// Reduce force as specified in m_MidAirSlowDown. Scale to the elapsed time

m_Force.SlowDown(ScaleToElapsedTime(m_MidAirSlowDo wn, dwTimeElapsed));

else

// Reduce force as specified in m_SlowDown. Scale to the elapsed time

m_Force.SlowDown(ScaleToElapsedTime(m_SlowDown, dwTimeElapsed));

// Set it to zero if it is to small

if (fabs(m_Force[x]) + fabs(m_Force[y]) +

fabs(m_Force[z]) < m_SmallestForce)

m_Force.ResetForce();

}

void CMotion::SetCustomMotion(float fForwardSpeed, float fBackwardSpeed, float fLeftSpeed, float fRightSpeed,

float fUpSpeed, float fDownSpeed, DWORD dwTimeElapsed)

{

// Add the given forces to the current force. Do scale the given forces relative to the

// elapsed time. Do not exceed maximum speed.

// Holds the new motion

CForce cAddForce;

// Calculate the given forces

if (fForwardSpeed > 0.0f)

{

CForce cForward;

cForward[x] = -(sinf(GetYRotation() * PI_OVER_180) * fForwardSpeed);

cForward[y] = 0.0f;

cForward[z] = -(cosf(GetYRotation() * PI_OVER_180) * fForwardSpeed);

cAddForce += cForward;

}

if (fBackwardSpeed > 0.0f)

{

CForce cBackward;

cBackward[x] = sinf(GetYRotation() * PI_OVER_180) * fBackwardSpeed;

cBackward[y] = 0.0f;

cBackward[z] = cosf(GetYRotation() * PI_OVER_180) * fBackwardSpeed;

cAddForce += cBackward;

}

if (fLeftSpeed > 0.0f)

{

CForce cLeft;

cLeft[x] = sinf((GetYRotation() - 90.0f) * PI_OVER_180) * fLeftSpeed;

cLeft[y] = 0.0f;

cLeft[z] = cosf((GetYRotation() - 90.0f) * PI_OVER_180) * fLeftSpeed;

cAddForce += cLeft;

}

if (fRightSpeed > 0.0f)

{

CForce cRight;

cRight[x] = sinf((GetYRotation() + 90.0f) * PI_OVER_180) * fRightSpeed;

cRight[y] = 0.0f;

cRight[z] = cosf((GetYRotation() + 90.0f) * PI_OVER_180) * fRightSpeed;

cAddForce += cRight;

}

if (fUpSpeed > 0.0f)

{

CForce cUp;

cUp[x] = 0.0f;

cUp[y] = fUpSpeed;

cUp[z] = 0.0f;

cAddForce += cUp;

}

if (fDownSpeed > 0.0f)

{

CForce cDown;

cDown[x] = 0.0f;

cDown[y] = -fDownSpeed;

cDown[z] = 0.0f;

cAddForce += cDown;

}

// Is camera in the air ?

CheckMidAir();

// Scale length of additional force vector relative to the acceleration time

if (m_MidAir)

cAddForce.SetVectorLength((GetSpeed() / m_MidAirAccelerationTime) * dwTimeElapsed);

else

cAddForce.SetVectorLength((GetSpeed() / m_AccelerationTime) * dwTimeElapsed);

// Add the additional force vector to the current force

m_Force += cAddForce;

// Do not exceed maximum speed

m_Force.SetVectorLength(GetSpeed());

}

void CMotion::SetDefaultMotion(bool bForward, bool bBackward, bool bLeft, bool bRight,

bool bUp, bool bDown, DWORD dwTimeElapsed)

{

// Add the enabled motion vectors with default accelerations to the array

// Convert parameters for SetCustomMotion() and pass them

SetCustomMotion(bForward * GetSpeed(), bBackward * GetSpeed(),

bLeft * GetSpeed(), bRight * GetSpeed(),

bUp * GetSpeed(), bDown * GetSpeed(), dwTimeElapsed);

}

void CMotion::Jump()

{

// Add jump acceleration to there current force if player

// is on the ground

CheckMidAir();

if (!m_MidAir)

m_Force += m_JumpForce;

}

void CMotion::CheckMidAir()

{

// Checks if the camera is in the air

// Use offset to avoid calculation accurancy problems

if (GetYPos() > GetSurfaceHeight() + 0.0000001f)

m_MidAir = TRUE;

else

m_MidAir = FALSE;

}

================================================== ============================

Any ideas ? I think my physics code is good, but my way to keep the motion vector

in sync with the mouse + keyboard input is bad...

Any ideas would be great !!!

Hope my English was good enough to make myself clear

(Sorry again for being off-topic. If you don't want to reply on the board, please

mail me)

Tim

I have a question on how to implement physics.

My current physics:

I have a CMotion class that accepts motion vectors. In my message loop,

I call the ApplyMotion(dwTimeElapsedSinceLastCall); function of this

class. Since all my motion behavior (like speed, acceleration) are defined

for one second, my class has to look how many time has elapsed and then

scale the things to this time. Things like gravity and gravity acceleration

are also applied from this class.

This works very well, but I have problems to convert keyboard & mouse input

to vectors for my class. If I pass a forward vector to my class every time

my HandleKeyboard() function realizes the forward key is pressed, my acceleration

would depend on how often this function could be called. Bad. So I have to

scale this too. I call something like AddForwardVector(dwTimeElapsedSinceLastCall);

and the forward vector is so scaled that the whole acceleration is applied when

I hold my forward key a full second down, regardless of how often HandleKeyboard()

is called.

My problem:

This method requires for all forces to be applied over the time. I want to let the player

jump, but to jump you shouldn't have to hold the mouse button down like walking. But when

I call my Jump(); it adds a vector to my CMotion class which will be smoothed out quickly

by the other ones.

Here is my source (sorry):

================================================== ============================

CMotion::CMotion()

{

// Init motion behavior with standard values. Every values is meant

// to be applied in 1000ms

m_SlowDown = 7.5f;

m_MidAirSlowDown = 0.1f;

m_GravityAcceleration = 2.5;

m_Gravity[x] = 0.0f;

m_Gravity[y] = -0.15f;

m_Gravity[z] = 0.0f;

// Init other member variables

m_MidAir = FALSE;

m_SmallestForce = 0.01f;

m_AccelerationTime = 100;

m_MidAirAccelerationTime = 500;

m_JumpForce[x] = 0.0f;

m_JumpForce[y] = 1.0f;

m_JumpForce[z] = 0.0f;

m_CurrentGravity[x] = 0.0f;

m_CurrentGravity[y] = 0.0f;

m_CurrentGravity[z] = 0.0f;

}

CMotion::~CMotion()

{

}

void CMotion::ApplyMotionPhysics(DWORD dwTimeElapsed)

{

// Calculate the movement that would happen in dwTimeElapsed ms

// Copy the current motion vector to cFinalForce

CForce cFinalForce = m_Force;

// Is camera in the air ?

CheckMidAir();

// Apply gravity to the final movement vector

if (m_MidAir)

{

// Camera is diving, apply gravity acelleration

m_CurrentGravity[x] += ScaleToElapsedTime(m_CurrentGravity[x] * m_GravityAcceleration, dwTimeElapsed);

m_CurrentGravity[y] += ScaleToElapsedTime(m_CurrentGravity[y] * m_GravityAcceleration, dwTimeElapsed);

m_CurrentGravity[z] += ScaleToElapsedTime(m_CurrentGravity[z] * m_GravityAcceleration, dwTimeElapsed);

// Apply gravity

cFinalForce += m_CurrentGravity;

}

else

// Camera is on the ground, set current gravity to default gravity

m_CurrentGravity = m_Gravity;

// Scale the final motion vector relative to dwTimeElapsed

cFinalForce[x] = ScaleToElapsedTime(cFinalForce[x], dwTimeElapsed);

cFinalForce[y] = ScaleToElapsedTime(cFinalForce[y], dwTimeElapsed);

cFinalForce[z] = ScaleToElapsedTime(cFinalForce[z], dwTimeElapsed);

// Pass the position after the motion to the CCamera class

SetXPos(GetXPos() + cFinalForce[x]);

SetYPos(GetYPos() + cFinalForce[y]);

SetZPos(GetZPos() + cFinalForce[z]);

// Lift the camera up to the terrain if he has descended below it

float fHeight = GetSurfaceHeight();

if (GetYPos() < fHeight)

{

// Lift camera up

SetYPos(fHeight);

// No acceleration upwards

m_Force[y] = 0.0f;

}

// Slow the motion down

// Use m_MidAirSlowDown when camera is in the air

if (m_MidAir)

// Reduce force as specified in m_MidAirSlowDown. Scale to the elapsed time

m_Force.SlowDown(ScaleToElapsedTime(m_MidAirSlowDo wn, dwTimeElapsed));

else

// Reduce force as specified in m_SlowDown. Scale to the elapsed time

m_Force.SlowDown(ScaleToElapsedTime(m_SlowDown, dwTimeElapsed));

// Set it to zero if it is to small

if (fabs(m_Force[x]) + fabs(m_Force[y]) +

fabs(m_Force[z]) < m_SmallestForce)

m_Force.ResetForce();

}

void CMotion::SetCustomMotion(float fForwardSpeed, float fBackwardSpeed, float fLeftSpeed, float fRightSpeed,

float fUpSpeed, float fDownSpeed, DWORD dwTimeElapsed)

{

// Add the given forces to the current force. Do scale the given forces relative to the

// elapsed time. Do not exceed maximum speed.

// Holds the new motion

CForce cAddForce;

// Calculate the given forces

if (fForwardSpeed > 0.0f)

{

CForce cForward;

cForward[x] = -(sinf(GetYRotation() * PI_OVER_180) * fForwardSpeed);

cForward[y] = 0.0f;

cForward[z] = -(cosf(GetYRotation() * PI_OVER_180) * fForwardSpeed);

cAddForce += cForward;

}

if (fBackwardSpeed > 0.0f)

{

CForce cBackward;

cBackward[x] = sinf(GetYRotation() * PI_OVER_180) * fBackwardSpeed;

cBackward[y] = 0.0f;

cBackward[z] = cosf(GetYRotation() * PI_OVER_180) * fBackwardSpeed;

cAddForce += cBackward;

}

if (fLeftSpeed > 0.0f)

{

CForce cLeft;

cLeft[x] = sinf((GetYRotation() - 90.0f) * PI_OVER_180) * fLeftSpeed;

cLeft[y] = 0.0f;

cLeft[z] = cosf((GetYRotation() - 90.0f) * PI_OVER_180) * fLeftSpeed;

cAddForce += cLeft;

}

if (fRightSpeed > 0.0f)

{

CForce cRight;

cRight[x] = sinf((GetYRotation() + 90.0f) * PI_OVER_180) * fRightSpeed;

cRight[y] = 0.0f;

cRight[z] = cosf((GetYRotation() + 90.0f) * PI_OVER_180) * fRightSpeed;

cAddForce += cRight;

}

if (fUpSpeed > 0.0f)

{

CForce cUp;

cUp[x] = 0.0f;

cUp[y] = fUpSpeed;

cUp[z] = 0.0f;

cAddForce += cUp;

}

if (fDownSpeed > 0.0f)

{

CForce cDown;

cDown[x] = 0.0f;

cDown[y] = -fDownSpeed;

cDown[z] = 0.0f;

cAddForce += cDown;

}

// Is camera in the air ?

CheckMidAir();

// Scale length of additional force vector relative to the acceleration time

if (m_MidAir)

cAddForce.SetVectorLength((GetSpeed() / m_MidAirAccelerationTime) * dwTimeElapsed);

else

cAddForce.SetVectorLength((GetSpeed() / m_AccelerationTime) * dwTimeElapsed);

// Add the additional force vector to the current force

m_Force += cAddForce;

// Do not exceed maximum speed

m_Force.SetVectorLength(GetSpeed());

}

void CMotion::SetDefaultMotion(bool bForward, bool bBackward, bool bLeft, bool bRight,

bool bUp, bool bDown, DWORD dwTimeElapsed)

{

// Add the enabled motion vectors with default accelerations to the array

// Convert parameters for SetCustomMotion() and pass them

SetCustomMotion(bForward * GetSpeed(), bBackward * GetSpeed(),

bLeft * GetSpeed(), bRight * GetSpeed(),

bUp * GetSpeed(), bDown * GetSpeed(), dwTimeElapsed);

}

void CMotion::Jump()

{

// Add jump acceleration to there current force if player

// is on the ground

CheckMidAir();

if (!m_MidAir)

m_Force += m_JumpForce;

}

void CMotion::CheckMidAir()

{

// Checks if the camera is in the air

// Use offset to avoid calculation accurancy problems

if (GetYPos() > GetSurfaceHeight() + 0.0000001f)

m_MidAir = TRUE;

else

m_MidAir = FALSE;

}

================================================== ============================

Any ideas ? I think my physics code is good, but my way to keep the motion vector

in sync with the mouse + keyboard input is bad...

Any ideas would be great !!!

Hope my English was good enough to make myself clear

(Sorry again for being off-topic. If you don't want to reply on the board, please

mail me)

Tim