1
\$\begingroup\$

I'm trying to make a simple 2D platformer in XNA, but I'm having trouble with the vertical scrolling.

What I'm trying to accomplish is that whenever the player is above half the height of the screen, the player should jump and fall. However, if the player is below half the height of the screen, then the player should remain in the middle of the screen and the background image and platforms should move around him instead, creating a scrolling effect.

I'm not sure why, but whenever the player is at half the height of the screen, the background and platforms don't move as much as they should, so the player can't make jumps that he would otherwise be able to.

I'm at a loss as to how to fix this issue, can anyone help? Any assistance would be much appreciated.

        if (keyState.IsKeyDown(Keys.D))
        {
            if (player.position.X < bgView.Width / 2 || bgView.X >= backgroundImage.Width - bgView.Width) //If the player position is less than 400px or if the bgView is greater than 1200 then the player moves, the BG is stationary  
            {
                player.position.X += speed;
            }
            else //If the player is greater than 400px and and the bgView is less than 1200 then the BG elements move instead, the player remains centred
            {
                bgView.X += 4; //moves the BG
                for (int i = 0; i < rows; i++)
                {
                    for (int j = 0; j < cols; j++)
                    {
                        if (block[i, j].position.X < bgView.Width / 2 || bgView.X >= backgroundImage.Width - bgView.Width)
                        {
                            block[i, j].position.X -= speed; //moves the platforms
                        }
                        else
                        {
                            block[i, j].position.X -= speed;
                        }
                    }
                }
            }
        }

        if (keyState.IsKeyDown(Keys.A))
        {
            if (player.position.X > bgView.Width / 2 || bgView.X <= 0)
            {
                player.position.X -= speed;
            }
            else
            {
                bgView.X -= 4;
                for (int i = 0; i < rows; i++)
                {
                    for (int j = 0; j < cols; j++)
                    {
                        block[i, j].position.X += speed;
                    }
                }
            }

        }

        if (player.position.X < 0) //Stops the player from moving backwards from the beginning of the stage
        {
            player.position.X = 0;
        }
        if (player.position.Y + player.image.Height > screenHeight) //Stops the player from falling through the floor
        {
            player.position.Y = screenHeight - (player.rectangle.Height);
        }
        if (player.position.X + player.image.Width > screenWidth) //Stops the player from leaving the end of the stage
        {
            player.position.X = screenWidth - player.image.Width;
        }



        for (int i = 0; i < rows; i++) //Checks the player position to see if it's intersecting a block's rectangle. 
        {
            for (int j = 0; j < cols; j++)
            {
                if (player.position.Y + player.image.Height >= block[i, j].rectangle.Top - 1 && //checks if the player is intersecting the top of a block
                    player.position.Y + player.image.Height <= block[i, j].rectangle.Top + (block[i, j].rectangle.Height / 2) &&
                    player.position.X + player.image.Width >= block[i, j].rectangle.Left + (block[i, j].rectangle.Width / 5) &&
                    player.position.X <= block[i, j].rectangle.Right - block[i, j].rectangle.Width / 5)
                {
                    gravity = 0;
                    jumping = false;
                    player.position = new Vector2(player.position.X, (block[i, j].position.Y + 1) - player.image.Height);
                    touchingTop = true;
                }
                if (player.position.Y <= block[i, j].rectangle.Bottom + (block[i, j].rectangle.Height / 5) && //checks if the player is intersecting the bottom of a block
                    player.position.Y >= block[i, j].rectangle.Bottom - 1 &&
                    player.position.X + player.image.Width >= block[i, j].rectangle.Left + (block[i, j].rectangle.Width / 5) &&
                    player.position.X <= block[i, j].rectangle.Right - (block[i, j].rectangle.Width / 2))
                {
                    player.position = new Vector2(player.position.X, block[i, j].rectangle.Bottom + 5);
                    force = 0;
                }
                if (player.position.X + player.image.Width <= block[i, j].rectangle.Right && //checks if the player is intersecting the left of a block
                    player.position.X + player.image.Width >= block[i, j].rectangle.Left - 5 &&
                    player.position.Y <= block[i, j].rectangle.Bottom - (block[i, j].rectangle.Width / 4) &&
                    player.position.Y + player.image.Height >= block[i, j].rectangle.Top + (block[i, j].rectangle.Width / 4))
                {
                    player.position = new Vector2(player.position.X - 4, player.position.Y);
                }

                if (player.position.X >= block[i, j].rectangle.Left && //checks if the player is intersecting the right of a block
                    player.position.X <= block[i, j].rectangle.Right + 5 &&
                    player.position.Y <= block[i, j].rectangle.Bottom - (block[i, j].rectangle.Width / 4) &&
                    player.position.Y + player.image.Height >= block[i, j].rectangle.Top + (block[i, j].rectangle.Width / 4))
                {
                    player.position = new Vector2(player.position.X + 4, player.position.Y);
                }
            }
        }
        for (int i = 0; i < rows; i++) //sets the block's rectangle position 
        {
            for (int j = 0; j < cols; j++)
            {

                block[i, j].rectangle.X = (int)block[i, j].position.X;
                block[i, j].rectangle.Y = (int)block[i, j].position.Y;
            }
        }
        //Checks whether or not the player is falling
        if (force <= 7)
        {
            falling = true;
        }
        if (force > 7)
        {
            falling = false;
        }

        if (keyState.IsKeyDown(Keys.W)) //After the player jumps, the force of the jump decreases over time, increasing the speed of falling
        {
            jumping = true;
        }
        if (jumping && player.position.Y + (player.image.Height / 2) > screenHeight / 2)
        {
            touchingTop = false;
            player.position.Y -= force;
            force -= 0.3f;
            if (force < 0)
            {
                force = 0;

            }
        }
        if (player.position.Y + (player.image.Height / 2) <= screenHeight / 2)
        {
            player.position.Y = screenHeight / 2 - (player.image.Height / 2);
            bgView.Y -= (int)force;
            bgView.Y += (int)gravity;
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    block[i, j].position.Y += (int)force;
                }
            }
        }
        else
        {
            bgView.Y += (int)force;
        }

        for (int i = 0; i < rows; i++) //Stops the blocks from ascending higher than the position they start at 
        {
            for (int j = 0; j < cols; j++)
            {
                block[i, j].position.Y -= gravity;
                if (block[i, j].position.Y <= block[i,j].startingPos.Y)
                {
                    block[i, j].position.Y = block[i,j].startingPos.Y;
                }
            }
        }
        if (!jumping)
        {
            force = 14f;
        }
        if (bgView.X < 0) //Prevents the background from scrolling backwards from the beginning of the stage
        {
            bgView.X = 0;
        }
        if (bgView.Y > 600)
        {
            bgView.Y = 600;
        }
        if (bgView.Y < 0)
        {
            bgView.Y = 0;
        }
        player.position.Y += gravity; //Gravity is constantly being added to the player's Y position
        base.Update(gameTime);
    }
\$\endgroup\$
  • \$\begingroup\$ Just for clarification; is the player's position on the screen dictating wether the player can jump? Thus, is the gameplay logic tied to the screen position; or do you want the camera to follow the player if the player "falls down"? \$\endgroup\$ – Felsir May 14 at 13:46
  • \$\begingroup\$ Yes, the player's position is dictating whether the player moves or the background elements do. If the player goes above the halfway point of the screen then the force (which makes the player jump) and the gravity (which makes the player fall) is applied to the BG elements instead of the player. If the player isn't intersecting a platform by the time the force is less than the gravity, then the BG elements should scroll in the opposite direction, so he falls. \$\endgroup\$ – MHK May 14 at 14:39
  • \$\begingroup\$ Sorry for not phrasing it correctly, what I mean is- does the WORLD position determine the player movement, or the SCREEN position. So, for example; your gameplay sounds a bit like Downwell. It may look like the screen position dictates the behavior; while in reality the camera simply follows the player. Your question and code make it sound as if you are tieing game logic to the camera position, am I right? \$\endgroup\$ – Felsir May 14 at 14:58
  • \$\begingroup\$ The screen position does. I also don't have a camera. The way it works is that the player only moves while he's below a certain point in the screen. Once he reaches that point, he stops moving and the background image/platforms move instead. \$\endgroup\$ – MHK May 14 at 15:08
  • \$\begingroup\$ The "camera" is the view the player has on the gameplay. You didn't implement it specificly, but since you view the game world- conceptually you have one. \$\endgroup\$ – Felsir May 14 at 15:10
1
\$\begingroup\$

In your code you have tied the game logic of the player directly to the motion of the camera; this creates a situation where the player and the camera play catch-up. Thus the player's "screen" position dictates the behavior, while actually this should be the "world" position.

The best way to solve this, is to untie the camera to the game logic. Basically, the player should move in the game world even when the camera is not watching. So the player falls down if it is not standing on a platform. The camera should then follow the falling player if the player is in the bottom half of the screen. Have a look at this classic article about camera implementations. In your case you want a "camera window" that covers the top half of the screen.

To implement this, a lot of games implement a separate camera class, that follows the player around.

Have a look at my answer to this question for example code (or check the accepted answer to that question- though I'd argue that that answer is less modular, but uses the same principle).

The basic idea is to code the game logic to work on game world coordinates; and worry about what part of the game world you show in a camera implementation.

\$\endgroup\$
  • \$\begingroup\$ Unfortunately this methodology is beyond my understanding, which is why I was attempting to code it in the manner that I was, but thanks anyway. \$\endgroup\$ – MHK May 14 at 22:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.