Sign in to follow this  

[C#] Platform game physics using integration. Is it possible?

This topic is 2809 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

If I wan't to move a sprite left and right I currently do the following:
            Vector2 force = Vector2.Zero;
            
            // Get key presses this frame
            if (InputState.Global.IsKeyDown(PlayerIndex.One, Keys.Left))
            {
                Animation.isYFlipped = false;
                force.X = -Speed; 
            }
            if (InputState.Global.IsKeyDown(PlayerIndex.One, Keys.Right))
            {
                Animation.isYFlipped = true;
                force.X = Speed;
            }
            if (force != Vector2.Zero)
            {
                body.AddForce(force);
            }


The force is added to the body and then integrated as follows:
       public void AddForce(Vector2 force)
        {
            // Accumulation stage must take place before the body is integrated
            force_Accumulated += force;
        }

        public void Integrate(float duration)
        {
            // ==========================================================================================================
            // --[Linear]------------------------------------------------------------------------------------------------
            // ==========================================================================================================
            
            // Update acceleration from accumulated forces
            // F = M * A
            // A = F / M
            acceleration = force_Accumulated * mass_Inverse;

            // Update linear velocity from the acceleration
            // V = V + A * dT
            velocity_Linear += acceleration * duration;

            // Update linear position
            // P = V0 * t + 0.5 * a * t^2
            position += velocity_Linear * duration + (0.5f * acceleration * duration * duration);
            
            force_Accumulated = Vector2.Zero;
        }


The two other possible forces acting on the sprite are drag and gravity:
    // A force generator tht applies a gravitational force 
    // (One instance can be used for multiple bodies)
    class RigidBody2D_Gravity : IRigidBody2D_ForceGenerator
    {
        Vector2 gravity;    // Holds the acceleration due to gravity

        // Create the generator with the given acceleration
        public RigidBody2D_Gravity(Vector2 gravity)
        {
            this.gravity = gravity;
        }

        // Applies the gravitational force to the given body
        public override void UpdateForce(RigidBody2D body, float duration)
        {
            if (body.IgnoreGravity || body.Type == RigidBody2D_Type.Static)
            {
                return;
            }

            // Apply the mass-scaled force to the body
            body.AddForce(gravity * body.Mass);
        }
    }

    /// <summary>
    /// A force generator that applies a drag force (One instance can be used for multiple bodies)
    /// <para></para>
    /// <para>See Physics.cs [Common Drag Coefficients] for possible values</para>
    /// </summary>
    class RigidBody2D_Drag : IRigidBody2D_ForceGenerator
    {
        float k1;   // Holds the velocity drag coefficient
        float k2;   // Holds the velocity squared drag coefficient

        public RigidBody2D_Drag(float k1, float k2)
        {
            this.k1 = k1;
            this.k2 = k2;
        }

        // Applies the drag force to the given body
        public override void UpdateForce(RigidBody2D body, float duration)
        {
            if (body.HasInfiniteMass)
            {
                return;
            }

            Vector2 force = body.Velocity;

            // Calculate the total drag coefficient
            float drag_Coefficient = force.Length();
            drag_Coefficient = k1 * drag_Coefficient + k2 * drag_Coefficient * drag_Coefficient;

            // Calculate the final force and apply it
            if (force != Vector2.Zero)
            {
                // Force must be normalised for drag equation to be correct
                force.Normalize();
            }

            force *= -drag_Coefficient;

            body.AddForce(force);
        }
    }


How then can I make the sprite move more like a platform character, where the controlled character will start/stop almost instaneously based on user input. This also applies to jumping, as that again is not instant accelleration. Thank you.

Share this post


Link to post
Share on other sites
You could simply clamp your velocity if you know the character is at a wall, to achieve an instant stop. And for an instant start, just set the velocity to be some initially nonzero velocity when the user presses a key. Since you have your own physics loop, you should be able to do tricks like this pretty easily.

Platformer physics...I'm not sure the force/acceleration thing is entirely appropriate. I know some platformer characters do have periods of acceleration/deceleration. I'm just not sure it makes complete sense to do it formally using forces. You could just have velocity vary as a linear function of time and not worry about forces. Falling or jumping would be a different linear function. Instant starts or stops would be represented easily....anyway, I've never developed a platformer game so I'm kind of speculating about this.

Share this post


Link to post
Share on other sites
One way to incorporate pre-canned motion into your dynamic simulation is to find the value of a that will move the character to the position where you know it should be. This is not what I recommend, however, since the character motion usually needs to be pretty deterministic.

I've found that it is easier to just snap or blend the position of the character to the pre-canned location, then adjust the velocity to take into account the shift in position that you just introduced. When it is time to turn the pre-canned motion off, the dynamics will smoothly take over.

The main disconnect between pre-canned animation and dynamic physics is that a pre-canned animation usually only updates the position. The dynamic physics needs the position AND the velocity to be updated.

Share this post


Link to post
Share on other sites
Quote:
Original post by grhodes_at_work
You could just have velocity vary as a linear function of time and not worry about forces


Something like this for the integration perhaps?


// Apply gravity
velocity_Linear += new Vector2(0, -10) * duration;

// Apply drag
velocity_Linear *= 0.99f;

position += velocity_Linear * duration;


When I change the body's velocity directly, should I use:


Vector2 velocity = Vector2.Zero;

if (InputState.Global.IsKeyDown(PlayerIndex.One, Keys.Left))
{
velocity.X = -Speed;
}
if (InputState.Global.IsKeyDown(PlayerIndex.One, Keys.Right))
{
velocity.X = Speed;
}

if (force != Vector2.Zero)
{
body.Velocity = velocity;
}



OR set speed as

velocity.X = -Speed * duration;

OR just set velocity as

body.Velocity = velocity * duration;

Quote:

I've found that it is easier to just snap or blend the position of the character to the pre-canned location, then adjust the velocity to take into account the shift in position that you just introduced. When it is time to turn the pre-canned motion off, the dynamics will smoothly take over.


This sounds like a great idea as this would allow me to add forces to a characters body from explosions or moving obstacles. I'm not sure how I would do this with my current setup though. Can you explain how the velocity could be changed if I were to adjust just the position.

Are these new methods the same as treating the rigid body as kinematic, or have I got that totally wrong?

Thanks again.

Share this post


Link to post
Share on other sites
Quote:
Original post by Spa8nky
How then can I make the sprite move more like a platform character, where the controlled character will start/stop almost instaneously based on user input.


Player input produces variable force. Make player input force vary inversely to player speed. Then do the opposite when the player lets go of the button add a strong stopping force.

Share this post


Link to post
Share on other sites

This topic is 2809 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this