Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 4 of 4

Thread: OT: Physics, need help!

  1. #1
    Intern Contributor
    Join Date
    Feb 2000
    Location
    Bremen, Bremen, Germany
    Posts
    58

    OT: Physics, need help!

    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

  2. #2
    Junior Member Newbie
    Join Date
    Feb 2000
    Posts
    24

    Re: OT: Physics, need help!

    calculate all your physics with respect to an independant time variable, perhaps based on the system clock, so acceleration would be based on time, not the number of times the function is called.

  3. #3
    Intern Contributor
    Join Date
    Feb 2000
    Location
    Italy
    Posts
    77

    Re: OT: Physics, need help!

    I think that you should treat input as a set of states, related to the controlling devices. I mean, in each game loop, you read the input values and update your internal states. You'd then use stored information during the physics calculations, based on a delta time. I.e. keys can be pressed or depressed, not too much difficult to handle. For actions, like jumping, you should use a FSM, and switch states on appropriate events from the input state. This should be a fine solution, it lets you to implement acceleration in the FSM state handler.
    Combine this, with a function modulating acceleration over time, and you should get smooth reactions.
    --
    Paolo M.

  4. #4
    Intern Contributor
    Join Date
    Feb 2000
    Location
    Bremen, Bremen, Germany
    Posts
    58

    Re: OT: Physics, need help!

    I think you don't understand my problem. If you look at my SetCustomMotion function, which is called from my keyboard handler, you'll notice that it takes a dwElapsedTime parameter, so that the acceleration don't depends on how often the engine could check the keyboard. But I have problems to keep acceleration with continius keydown's ,like moving forward, in sync with single keystrokes like jumping....

    Tim

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •