1
\$\begingroup\$

I'm making a 2D platformer in XNA 4.0. I have created a working tile engine, which works well for my purposes, and Horizontal Scrolling works flawlessly, however I am having great trouble with Vertical scrolling.

I Basically want the camera to scroll up (world to scroll down) when the player reaches a certain Y co-ordinate, and I would also like to automatically scroll back down if coming down, and that co-ordinate is passed. My biggest problem is I have no real way of detecting the direction the player is moving in using only the Y Co-ord.

Here Is My Code Code For The Camera Class (which appears to be a very different approach to most camera classes I have seen).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Marvin
{
    class Camera : TileEngine
    {
        public static bool startReached;
        public static bool endReached;

        public static void MoveRight(float speed = 2)
        {

            //Moves The Position of Each Tile Right
            foreach (Tile t in tiles)
            { if(t!=null) { t.position.X -= speed; } }

        }


        public static void MoveLeft(float speed = 2)
        {
            //Moves The Position of Each Tile Right
            foreach (Tile t in tiles)
            { if(t!=null) { t.position.X += speed; } }

        }

        public static void MoveUp(float speed = 2)
        {
            foreach (Tile t in tiles)
            { if(t!=null) { t.position.Y += speed; } }

        }

        public static void MoveDown(float speed = 2)
        {
            foreach (Tile t in tiles)
            { if(t!=null) { t.position.Y -= speed; } }

        }

        public static void Restrain()
        {
            if(tiles.Last().position.X<Main.graphics.PreferredBackBufferWidth-tiles.Last().size.X)
            { MoveLeft(); endReached = true; }
            else
            { endReached = false; }

            if(tiles[1].position.X>0)
            { MoveRight(); startReached = true;}
            else
            { startReached = false; }
        }
    }
}

Here is My Player Code for Left and Right Scrolling/Moving

        if (Main.currentKeyState.IsKeyDown(Keys.Right))
        { 
            Camera.MoveRight(); 

            if(Camera.endReached)
            { MoveRight(2); }
            else
            {
                if(marvin.GetRectangle().X!=Main.graphics.PreferredBackBufferWidth-(marvin.GetRectangle().X+marvin.GetRectangle().Width))
                { MoveRight(2); Camera.MoveLeft(); }
            }

        }

        if(Main.currentKeyState.IsKeyDown(Keys.Left))
        { 
            Camera.MoveLeft();

            if(Camera.startReached)
            { MoveLeft(2); }
            else
            {
                if(marvin.GetRectangle().X!=Main.graphics.PreferredBackBufferWidth-(marvin.GetRectangle().X+marvin.GetRectangle().Width))
                { MoveLeft(2); Camera.MoveRight(); }
            }

        }

        Camera.Restrain();

        if(marvin.GetRectangle().X>Main.graphics.PreferredBackBufferWidth-marvin.GetRectangle().Width)
        { MoveLeft(2); }

        if(marvin.GetRectangle().X<0)
        { MoveRight(2); }

And Here Is My Player Jumping/Falling Code which may cause some conflicts with the vertical camera movement.

        if (!jumping)
        {
            if(!TileEngine.TopOfTileCollidingWith(footBounds))
            { MoveDown(5); }
            else
            { 
                if(marvin.GetRectangle().Y != TileEngine.LastPlatformStoodOnTop()-marvin.GetRectangle().Height)
                {
                    float difference = (TileEngine.LastPlatformStoodOnTop()-marvin.GetRectangle().Height) - (marvin.GetRectangle().Y);

                    marvin.SetRectangle(marvin.GetRectangle().X,(int)(marvin.GetRectangle().Y+difference));
                    armR.SetRectangle(armR.GetRectangle().X,(int)(armR.GetRectangle().Y+difference));
                    armL.SetRectangle(armL.GetRectangle().X,(int)(armL.GetRectangle().Y+difference));
                    eyeL.SetRectangle(eyeL.GetRectangle().X,(int)(eyeL.GetRectangle().Y+difference));
                    eyeR.SetRectangle(eyeR.GetRectangle().X,(int)(eyeR.GetRectangle().Y+difference));
                }
            }
        }

        if (Main.currentKeyState.IsKeyDown(Keys.Up) && Main.previousKeyState.IsKeyUp(Keys.Up) && TileEngine.TopOfTileCollidingWith(footBounds))
        { jumping = true; }

        if(jumping)
        {
            if(TileEngine.LastPlatformStoodOnTop()>0 && (TileEngine.LastPlatformStoodOnTop() - footBounds.Bottom)<120)
            { MoveUp(5); }
            else
            { jumping = false; }
        }

All player code I have tried for vertical movements has failed, or caused weird results (like falling through platforms), and most have been a variation on the method I described above, hence I have not included it. I would really appreciate some help implementing a simple vertical scrolling into this game, Thanks.

\$\endgroup\$
  • 1
    \$\begingroup\$ Hi and welcome to the site. Do you mean you always want the camera centered vertically on the player, or you actually want scrolling of some sort? \$\endgroup\$ – ashes999 Aug 22 '13 at 18:29
  • \$\begingroup\$ @ashes999 I want to scroll after a certain height is reached by the player, So that the upper part of the tile map is visible. Below this height I want no vertical scrolling. \$\endgroup\$ – alec100_94 Aug 22 '13 at 20:49
1
\$\begingroup\$

I would rather compare the difference between the player and the camera. This is a very simple check:

Vector2 playerInRelationToCamera = playerPosition - cameraPosition;

then if the distance from camera to player is larger than, say a third of a screenheight, then you can move the camera closer:

if(playerInRelationToCamera.Length() > screenHeight/3)
{
  cameraPosition += playerInRelationToCamera / 10;
}

Would this work for you?

\$\endgroup\$
0
\$\begingroup\$

To detect the direction where your character is moving, just compare the character's current position with its position in the previous game loop update:

enum VerticalDirection { Up, Down, Stationary }

VerticalDirection GetDirection(Vector2 previousPosition, Vector2 currentPosition)
{
   if (previousPosition.Y == currentPosition.Y)
   {
      return VerticalDirection.Stationary;
   }
   if (previousPosition.Y > currentPosition.Y)
   {
      return VerticalDirection.Down;
   }
   return VerticalDirection.Up;
}

Issues like you described (falling through platforms) might be caused by missed collisions. This can happen if the difference between the character's current and previous position is too big to be detected by your collision detection method.

\$\endgroup\$
  • \$\begingroup\$ This should not happen, collisions should be checked across a range or a vector of movement. One should avoid checking only the position in the next frame. \$\endgroup\$ – wolfdawn Jan 20 '14 at 22:05

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.