简体   繁体   中英

XNA/Monogame: Platformer Jumping Physics and Collider Issue

I have a sprite, Player . I update Player 's position the following way:

_position += (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;

Where _position , _direction and _velocity are Vector2 s.

I have a simple collider( BoxCollider ) which simply generates a rectangle ( BoundingBox ) given the position and dimensions of the collider.

In Initialize() , I create a new List<BoxCollider> and fill it with colliders for the level.

On Update() , I pass the list to Player to check for collisions.

The collision check method:

public void CheckPlatformCollision(List<BoxCollider> colliders, GameTime gameTime)
{
    var nextPosition = _position + (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;
    Rectangle playerCollider = new Rectangle((int)nextPosition.X, (int)nextPosition.Y, BoundingBox.Width, BoundingBox.Height);
    foreach(BoxCollider collider in colliders)
    {
        if(playerCollider.Intersects(collider.BoundingBox))
        {
            nextPosition = _position;
        }
    }
    Position = nextPosition;
}

Right now, every way I've tried to implement gravity has failed. If Player is dropped from too high, nextPosition becomes too far away from Player and leaves it stuck in mid-air.

I'm also having problems with horizontal collisions as well, the issue being similar: Player stops too soon, leaving a space between. Sometimes I've had Player stick to the side of the collider.

What I would like to know is:

How do I properly implement gravity & jumping with _position , _direction , and _velocity ? How do I properly handle collisions both horizontally and vertically?

For gravity, add this just before you update _position :

_velocity += gravity * (float)gameTime.ElapsedGameTime.TotalSeconds;

Where gravity is something like new Vector2(0, 10) .


For jumping, you need to set the vertical component of the velocity when the player presses the jump button:

if (jumpPressed && jumpAvailable)
{
    _velocity.Y = -10; // Numbers are example. You need to adjust this
    jumpAvailable = false;
}

And you need to reset jumpAvailable when the player touches the floor.


Colliding is a much complicated thing. But if you look for "XNA implement collision" on the internet you will find a lot of answers.

There are many ways. One of them is pushing back the player to the border of the boxcollider, instead of not letting him move, like you did in your code. The code would be:

if (IntersectsFromTop(playerCollider, collider.BoundingBox))
{
    _position.Y = collider.BoundingBox.Y - BoundingBox.Height;
}
else if (IntersectsFromRight(playerCollider, collider.BoundingBox))
{
    _position.X = collider.BoundingBox.X + collider.BoundingBox.Width;
}
// And so on...

The helper methods can implemented like:

private static bool IntersectsFromTop(Rectange player, Rectangle target)
{
    var intersection = Rectangle.Intersect(player, target);
    return player.Intersects(target) && intersection.Y == target.Y && intersection.Width >= intersection.Height;
}

private static bool IntersectsFromRight(Rectange player, Rectangle target)
{
    var intersection = Rectangle.Intersect(player, target);
    return player.Intersects(target) && intersection.X + intersection.Width == target.X + target.Width && intersection.Width <= intersection.Height;
}
// And so on...

The rationnale behind that code can be explained with a picture:

顶部碰撞和左侧碰撞

In that picture width and height correspond to the intersection, in purple.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM