• Advertisement
Sign in to follow this  

XNA - Attempting to implement collision level-wide in a 2d platformer

This topic is 470 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

This is my first attempt at a game, it's already been quite the learning experience thusfar but I've now grinded to a halt when trying to figure out how to do my collision detection on a level-wide scale.
 
I started with the basics like a simple player class, an obstacle class for blocks to jump on, then my movement & jumping which went smooth, then collision with 1 block.
 
Now I'm drawing a level on my screen with a simple array and a for loop, but I'm lost on how to proceed to apply my collision level-wide. The way I've attempted it is the best I could come up with myself, running a separate loop with the same array and then running my collision logic. I've looked at tutorials online and the platformer example Microsoft provides in their XNA resources but the way their collision systems are written always seems much more complex and with many more factors such as a more detailed physics system and more complicated level drawing, which would require me to basically start over. Which is no problem if that's required and my foundation is simply not good, but I'd like to know if I can continue with what I have.
 
Edit: I forgot to mention what actually goes wrong. Basically applying my collision logic to my level like this results in two huge bugs, one where my character slowly sinks through the blocks he stands on, another where at certain angles of collision with a block he will teleport to the nearest block. Both these issues did not exist when I applied the same collision to a single block. I've tried playing with the values to push my player away with different methods but with no success. I really just can't figure out what the issue actually is.
 
Here is my class handling level drawing and collision: 
 
namespace GameDevProtoType
{
    public class Level
    {
        Vector2 obstaclePosition;
        protected byte[,] tileArray;
        Obstacle obstacle;
        Rectangle obstacleBounds;

        protected void CreateTileArray()
        {
            tileArray = new byte[,]
            {
            { 0,0,0,0,0,0,0,0,0 },
            { 0,0,0,0,1,0,0,0,0 },
            { 0,0,0,0,0,0,0,0,0 },
            { 0,0,0,1,0,0,0,0,0 },
            { 0,0,0,0,0,0,0,0,0 },
            { 0,0,0,1,1,0,0,0,0 },
            { 1,1,1,1,1,0,0,0,0 },
            { 0,0,0,0,0,0,0,0,0 },
            { 0,0,0,0,0,0,0,0,0 },
            { 0,0,1,0,0,0,0,0,0 },
            { 1,1,1,1,0,0,0,0,0 },
            { 0,0,0,0,0,0,0,1,1 },
            { 0,0,0,1,1,0,1,0,0 },
            { 0,0,1,0,0,0,0,0,1 }
            };
        }

        public void Initialize()
        {
            obstacle = new Obstacle();
        }

        public void CreateLevel(ContentManager content, SpriteBatch spritebatch)
        {
            CreateTileArray();
            Texture2D obstacleSprite = content.Load<Texture2D>("Graphics\\Tile1");
            obstacle.Initialize(obstacleSprite);

            for (int row = 0; row < tileArray.GetLength(0); row++)
            {
                for (int column = 0; column < tileArray.GetLength(1); column++)
                {
                    if (tileArray[row, column] == 1)
                    {
                        obstaclePosition = new Vector2(column * obstacle.Width, row * obstacle.Height);
                        spritebatch.Draw(obstacleSprite, obstaclePosition, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
                    }
                }
            }
        }

        public void Collision(GameTime gameTime, Rectangle playerBounds, Player player, Vector2 playerMoveSpeed)
        {

            CreateTileArray();

            for (int row = 0; row < tileArray.GetLength(0); row++)
            {
                for (int column = 0; column < tileArray.GetLength(1); column++)
                {
                    if (tileArray[row, column] == 1)
                    {
                        obstaclePosition = new Vector2(column * 32, row * 32);
                        obstacleBounds = new Rectangle((int)(obstaclePosition.X), (int)(obstaclePosition.Y), 32, 32);

                        if (playerBounds.Intersects(obstacleBounds))
                        { 
                            float rightEdge = obstacleBounds.X - (player.Position.X + playerBounds.Width);
                            float leftEdge = obstacleBounds.X + obstacleBounds.Width - player.Position.X;
                            float topEdge = obstacleBounds.Y - (player.Position.Y + playerBounds.Height);
                            float bottomEdge = obstacleBounds.Y + obstacleBounds.Height - player.Position.Y;

                            float shortestWidth = Math.Min(Math.Abs(rightEdge), Math.Abs(leftEdge));
                            float shortestHeight = Math.Min(Math.Abs(topEdge), Math.Abs(bottomEdge));
                            float shortestFinal = Math.Min(Math.Abs(shortestWidth), Math.Abs(shortestHeight));

                            if (shortestFinal == Math.Abs(leftEdge))
                            {
                                player.Position.X = obstacleBounds.X + obstacleBounds.Width;
                                playerMoveSpeed.X = 0;
                            }

                            else if (shortestFinal == Math.Abs(rightEdge))
                            {
                                player.Position.X = obstacleBounds.X - playerBounds.Width;
                                playerMoveSpeed.X = 0;
                            }

                            else if (shortestFinal == Math.Abs(bottomEdge))
                            {
                                player.Position.Y = obstacleBounds.Y + obstacleBounds.Height;
                                playerMoveSpeed.Y = 0;
                            }

                            else if (shortestFinal == Math.Abs(topEdge))
                            {
                                player.Position.Y = obstacleBounds.Y - playerBounds.Height;
                                playerMoveSpeed.Y = 0;
                                player.hasJumped = false;
                            }

                        }


                    }
                }
            }
        }
    }
}
 
Here is how I call my collision logic (and update playerbounds which is handled in my game logic) from main game class:
 
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            currentKeyboardState = Keyboard.GetState();

            UserInput(gameTime);

            level.Collision(gameTime, playerBounds, player, playerMoveSpeed);

            playerBounds.X = (int)player.Position.X;
            playerBounds.Y = (int)player.Position.Y;

            base.Update(gameTime);
        }

CreateLevel is called in the final method Draw().

 

 

edit: apologies for some bad programming etiquette, i was focusing on making collision work and go from there and took some shortcuts as you can see

Edited by Xari

Share this post


Link to post
Share on other sites
Advertisement

I've gotten some feedback in the chat and will be working on rewriting my gravity to be based on a onGround flag instead of hasJumped (what I use now) and some other things that aren't necessarily relevant to my collision problem. Will report back!

 

Here's how I handled jumping and falling down for the record

player.hasJumped = (player.Position.Y + player.PlayerSprite.Height <= GraphicsDevice.Viewport.Height);

            if (player.hasJumped)
            {
                playerMoveSpeed.Y += 0.15f;
                player.hasJumped = true;
            }

            else
                playerMoveSpeed.Y = 0f;
Edited by Xari

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement