Platformer movement and collision

Started by
8 comments, last by stein102 8 years, 10 months ago

I'm working on getting a platformer prototype up and running in C# using monogame. The movement and collision "work" but are very awkward. For example, if you stand on the edge of a platform and jump straight up, you fall right through the platform. I'll post my code and hopefully someone sees something that doesn't look right. If any additional information is needed I can add more.


public Player(GraphicsDevice device)
        {
            x = 100;
            y = 100;
            width = 32;
            height = 64;
            maxVX = 10;
            gravity = -2;
            grounded = false;

            Rect = new Rectangle(x, y, width, height);

            WhiteRectangle = new Texture2D(device, 1, 1);
            WhiteRectangle.SetData(new[] { Color.White });
        }



        public void Update()
        {
            rect = new Rectangle(x, y, width, height);
            if (!grounded || standingOn==null)
            {
                aY = gravity;
            }else
            {
                aY = 0;
            }

                

            VY += AY;
            VX += AX;

            if (aX > 10) aX = 10;
            if (aX < -10) aX = -10;
            if (vX > maxVX) vX = maxVX;
            if (vX < -maxVX) vX = -maxVX;




            System.Console.WriteLine(vX +":" + aX);

            lastX = x;
            lastY = y;

            x += VX;
            y -= VY;

        }

        public void CollisionCheck(List<Platform> collideables)
        {
            foreach(var p in collideables)
            {
                if (rect.Intersects(p.Rect))
                {
                    Rectangle intersection = Rectangle.Intersect(rect, p.Rect);

                    if(intersection.Height < intersection.Width)
                    {
                        if (y < p.Y)
                        {
                            standingOn = p;
                            grounded = true;
                            y = p.Y - height;
                            vY = 0;
                            aY = 0;
                        }else
                        {
                            y = p.Y + p.Height + 1;
                            vY = 0;
                            
                        }



                    }else
                    {
                        if(x < p.X)
                        {
                            x = p.X - width - 1;
                        }else
                        {
                            x = p.X + p.Width + 1;
                        }
                    }
                
                    vX = 0;
                    aX = 0;
                }
            }

            //Check if player falls off platform
            if (standingOn != null)
            {
                if(x+width < standingOn.X || x > standingOn.X +standingOn.Width)
                {
                    grounded = false;
                    standingOn = null;
                }
            }
        }

        public void ApplyFriction()
        {
            aX = 0;
            if (vX > 0)
                aX -= 2;
            if (vX < 0)
                aX += 2;
        }

EDIT: Almost forgot to include the code that changes the acceleration


            player.AX += (int)(pad.ThumbSticks.Left.X * 10) / 5;
Advertisement

The code snippet is completely missing the jumping part, so we are bound to guess.

My 8ball suggests a common mistake: Turn gravity off when jumping.

Or post at least the jump code and any code that controls both jumping and falling.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

I'm not at my PC at the moment but all the code for jumping does is increase the y velocity by a set amount. I can post a video of the behavior in the morning since I'm a little unsure how to explain it
This is suspicious..

if(intersection.Height < intersection.Width)

If the height of the intersection is larger than the width (as might be when you are on the edge of a platform), then it doesn't bother with checking to see if you landed on something. Seems flawed.

It is more common to check one direction, correct for interpenetration, then re-calculate intersection for the other direction.

This is suspicious..

if(intersection.Height < intersection.Width)

If the height of the intersection is larger than the width (as might be when you are on the edge of a platform), then it doesn't bother with checking to see if you landed on something. Seems flawed.

It is more common to check one direction, correct for interpenetration, then re-calculate intersection for the other direction.

I found that in a thread a while ago(I don't remember where exactly) where it was suggested to check which collision axis was shallower to determine which collision has happened first. I have changed that already but I did so before seeing your post.

What I've done is get two time variables that are basically float timeY = intersection.Height/velocityY and the same for X. This has been a lot more accurate.

My problem I'm having now is that the movement feels VERY unnatural. But I suppose that is just a matter of tweaking values, right? I was also considering changing all my movement related variables from ints to floats to get slightly more smooth movements. Would this help?

Using floats rather than ints is a good idea.

I don't know what "unnatural" means. A video of the movement would be helpful.

Okay, I got a video up. Here's the link. The video is a bit long but it gets the point across.

It's kind of hard to tell from just the video but the change in direction seems to have a pretty large delay.

What is AX and AY (as opposed to ax and ay), and where are they being set?

FWIW, I think you should take a generic approach to this, and it should not be player specific as well as a change to how you handle collisions. What I mean is:

#1, These functions need to be defined in some movable class that handles movement for everything that can move (players, enemies, other objects)

#2, Gravity should be added to an objects y-velocity every frame. This means you'll also have to compute if an object is on the ground every frame too, and reset the y-velocity to 0. This will make handling jumping and walking off platforms a breeze.

#3, Move the object in 1 axis only, then check collisions, then move in the other axis. Imagine a player moving right and jumping into a wall. It will collide with the wall, but do you want to stop the upwards (and downwards) motion of the player when it hits the wall? No, so, move in the X-axis, check collisions, and reset X-position if collided, then move in y-axis and check collision and reset y-axis if colliding. This will handle all sorts of collisions (hitting your head while jumping to the right for example).

Good luck and have fun.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

Video looks okay, so itmust just "feel" wrong.

If you are setting ax instead of vx it is going to feel slow and delayed. Playformers normally let you instantaneously change direction, which means setting vx, at least when airborne.

On the ground you might want to set ax to give the character momentum. Adding an animation will help it feel less delayed, as something will happen i.mediately when you try to change direction.. Try changing the block to an arrow in the direction of ax. Perception matters.

What is AX and AY (as opposed to ax and ay), and where are they being set?

FWIW, I think you should take a generic approach to this, and it should not be player specific as well as a change to how you handle collisions. What I mean is:

#1, These functions need to be defined in some movable class that handles movement for everything that can move (players, enemies, other objects)

#2, Gravity should be added to an objects y-velocity every frame. This means you'll also have to compute if an object is on the ground every frame too, and reset the y-velocity to 0. This will make handling jumping and walking off platforms a breeze.

#3, Move the object in 1 axis only, then check collisions, then move in the other axis. Imagine a player moving right and jumping into a wall. It will collide with the wall, but do you want to stop the upwards (and downwards) motion of the player when it hits the wall? No, so, move in the X-axis, check collisions, and reset X-position if collided, then move in y-axis and check collision and reset y-axis if colliding. This will handle all sorts of collisions (hitting your head while jumping to the right for example).

Good luck and have fun.

AX and AY are the just properties for aX and aY, they basically act as getters and setters for the variables. aX and aY are being set in the main game loop where it just takes the direction of the thumbstick and adds to the variable depending on how much it's pressed.

1. I agree with you, I'll change that after I get it working correctly. This is just a prototype I was throwing together because I've never worked in monogame or C# before(I come from a Java and LibGDX background)

2. That was originally what I had done, but I changed it to what I have now because I was getting some stuttering when the block was on the ground. It would accelerate too quickly into the ground and a collision would occur to move the object back above the ground.

3. That makes a lot of sense, I'll give that one a shot.

Video looks okay, so itmust just "feel" wrong.

If you are setting ax instead of vx it is going to feel slow and delayed. Playformers normally let you instantaneously change direction, which means setting vx, at least when airborne.

On the ground you might want to set ax to give the character momentum. Adding an animation will help it feel less delayed, as something will happen i.mediately when you try to change direction.. Try changing the block to an arrow in the direction of ax. Perception matters.

Oh okay, I see what you mean. That had never occurred to me, I'll try implementing changing the velocity directly as opposed to the acceleration.

I'll look into adding an animation for the play and see what happens. I've never done anything like that with monogame so that means there's some more reading to be done :)

Thanks for all the advice!

This topic is closed to new replies.

Advertisement