Why won't my sprite move back down?

Thread Starter

magnet18

Joined Dec 22, 2010
1,227
Alright, I'm learning C# and am trying to get the basics down by making a simple 2D game similar to mario. I got the moving don, and am currently trying to get it to jump smoothly, so I came up with the following code- But when I press the jump button, the sprite just moves up, and keeps moving up, and I cant figure out why :(
Rich (BB code):
namespace mario_clone
{   public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        KeyboardState oldState;
        SpriteBatch spriteBatch;
        Boolean jumping;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.IsFullScreen = true;
            Content.RootDirectory = "Content";
        }
        protected override void Initialize()
        {
           base.Initialize();
           oldState = Keyboard.GetState();
           jumping = false; 
           // TODO: Add your initialization logic here

           base.Initialize();
        }

        Texture2D myTexture;

        Vector2 spritePosition = new Vector2(1.0f, 1.0f);

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            myTexture = Content.Load<Texture2D>("mario sprite");
            
        }

     protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            int MaxX =
                graphics.GraphicsDevice.Viewport.Width - myTexture.Width;
            int MinX = 0;
            int MaxY =
                graphics.GraphicsDevice.Viewport.Height - myTexture.Height;
            int MinY = 0;
            int gravity = 5;
            var velocity = 15;

            
            // keyboard logic
            KeyboardState newState = Keyboard.GetState();

            if (newState.IsKeyDown(Keys.Escape))
            {
                if (!oldState.IsKeyDown(Keys.Escape))
                {
                    this.Exit();
                }
            }

            if (newState.IsKeyDown(Keys.Left))
            {
                if (spritePosition.X > MinX)
                {
                    spritePosition.X = spritePosition.X - 2.0f;
                }                
            }

            if (newState.IsKeyDown(Keys.Right))
            {
                if (spritePosition.X < MaxX)
                {
                    spritePosition.X = spritePosition.X + 2.0f;
                }
            }
            
            if (newState.IsKeyDown(Keys.Up) && spritePosition.Y >= MaxY && jumping == false)
            {
                jumping = true;
                velocity = 15;
            }

            if (jumping == true)
            {
                
                spritePosition.Y = spritePosition.Y - velocity;
                velocity = velocity - gravity;
            }


            if (spritePosition.Y == MaxY && jumping == true)
            {
                jumping = false;
                velocity = 0;
            }

            if (spritePosition.Y < MaxY && jumping == false)
            {
                spritePosition.Y = spritePosition.Y + gravity;
            }

            if (spritePosition.Y >= MaxY)
            {
                spritePosition.Y = MaxY;
            }
        
            base.Update(gameTime);
            oldState = newState;
        }

        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            spriteBatch.Draw(myTexture, spritePosition, Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
 

Filox

Joined Oct 11, 2011
7
Hello magnet18,

The fact that the texture continued to move upwards ,was because you didn't have any limiting factor that could actually stop the ascending(examples: when texture reached the top border of the window, based on a timer etc).

I added a TimeSpan variable in the declarations to count the time between the moment you pressed UP and the duration of ascdendance. When the timer passes that time the texture will start falling based on the gravity.

Let's go to the actual code:
Code:
 TimeSpan jumpTimer = TimeSpan.Zero;
And change the if ( jumping == true ) condition's content to:
Code:
jumpTimer += gameTime.ElapsedGameTime;
if (jumpTimer.CompareTo(new TimeSpan(0,0,0,0,500)) == 1) 
{
     jumping = false;
     jumpTimer = TimeSpan.Zero;
}
spritePosition.Y -= gravity;
I didn't want to change your code, just add the functionality you had problem with.Don't hesitate to ask if you want more clarifications on the above.
 
Last edited:

Thread Starter

magnet18

Joined Dec 22, 2010
1,227
Thanks!, it kinda works, but I had to modify your code from if (jumpTimer.CompareTo(new TimeSpan(0,0,0,0,500)) == 1) to if (jumpTimer.CompareTo(new TimeSpan(0,0,0,0,500)) <= 1) to get it to come back down, which doesn't make sense to me, since it shouldn't go above 1 in the first place....

also, now whenever I hit the jump button it moves up the initial velocity in one frame, then falls back down, rather than moving up the velocity, then the velocity - gravity, then the velocity - 2 gravity...

I also am wondering why my initial code didn't work, because it should have moved up by less and less each time, until eventually moving back down by more and more, and triggering the end of the jump when it reached MaxY (bottom of screen)

here's my current code-
Rich (BB code):
namespace mario_clone
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        KeyboardState oldState;
        SpriteBatch spriteBatch;
        Boolean jumping;
        const int move_up = -1;
        const int move_down = 1;
        const int move_left = -1;
        const int move_right = 1;


        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.IsFullScreen = true;
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
           base.Initialize();
           oldState = Keyboard.GetState();
           jumping = false;
           // TODO: Add your initialization logic here

           base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        /// 

        Texture2D myTexture;

        Vector2 spritePosition = new Vector2(1,1);

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            myTexture = Content.Load<Texture2D>("mario sprite");
            
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            int MaxX =
                graphics.GraphicsDevice.Viewport.Width - myTexture.Width;
            int MinX = 0;
            int MaxY =
                graphics.GraphicsDevice.Viewport.Height - myTexture.Height;
            int MinY = 0;
            int gravity = 5;
            var velocity = 0;

            UpdateJump();
            // keyboard logic
            KeyboardState newState = Keyboard.GetState();
            TimeSpan jumpTimer = TimeSpan.Zero;

            if (newState.IsKeyDown(Keys.Escape))
            {
                if (!oldState.IsKeyDown(Keys.Escape))
                {
                    this.Exit();
                }
            }

            if (newState.IsKeyDown(Keys.Left))
            {
                if (spritePosition.X > MinX)
                {
                    spritePosition.X = spritePosition.X - 2;
                }                
            }

            if (newState.IsKeyDown(Keys.Right))
            {
                if (spritePosition.X < MaxX)
                {
                    spritePosition.X = spritePosition.X + 2;
                }
            }
            
            if (newState.IsKeyDown(Keys.Up) && oldState.IsKeyDown(Keys.Up) == false && spritePosition.Y >= MaxY && jumping == false)
            {
                jumping = true;
                velocity = 500;
            }

            jumpTimer += gameTime.ElapsedGameTime;
            if (jumpTimer.CompareTo(new TimeSpan(0,0,0,1,500)) == 1 && jumping == true)
            {
                
                    jumping = false;
                    jumpTimer = TimeSpan.Zero;
                
            }

            if (spritePosition.Y < MaxY && jumping == false)
            {
                spritePosition.Y +=  gravity;
            }

            if (velocity > 0)
            {
                spritePosition.Y -= velocity;
                velocity -= gravity;
            }

            if (spritePosition.Y >= MaxY)
            {
                spritePosition.Y = MaxY;
            }

            if (spritePosition.Y <= MinY)
            {
                spritePosition.Y = MinY;
            }
        
            // Move the sprite by speed, scaled by elapsed time.
            
            

            

            base.Update(gameTime);
            oldState = newState;
        }

        private void UpdateJump()
        {
        }
     

        
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            spriteBatch.Draw(myTexture, spritePosition, Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
[EDIT]
Could the jumpTimer not be "starting" properly, or be running the whole time and being to big, or something?
 
Last edited:

Filox

Joined Oct 11, 2011
7
I believe that there was a misunderstanding there. When I said :
And change the if ( jumping == true ) condition's content to:
I meant that you should keep that condition and replace the code between the braces with the code given. You should keep the initial code that you posted and replace this condition:
Rich (BB code):
if (jumping == true)
{           
     spritePosition.Y = spritePosition.Y - velocity;
     velocity = velocity - gravity;
}
with:
Rich (BB code):
if (jumping == true)
{
     jumpTimer += gameTime.ElapsedGameTime;
     if (jumpTimer.CompareTo(new TimeSpan(0,0,0,0,500)) == 1)
     {
           jumping = false;
           jumpTimer = TimeSpan.Zero;
      }
      spritePosition.Y -= gravity;
}
The jumpTimer should count ONLY after the UP button has been pressed and not always as you had in the second code that you posted, which had as a result , our timer not doing what he was supposed to do.

CompareTo method works like this: Let's say that we have:
Rich (BB code):
timer.CompareTo(value)
This method call returns:
-> (-1) if the value is bigger than timer
-> (0) if the value is equal to the timer
-> (1) if the value is smaller than the timer

This means that :
Rich (BB code):
jumpTimer.CompareTo(new TimeSpan(0,0,0,0,500)) <= 1
will be always true and draw at the most 1 frame.

(Source: http://msdn.microsoft.com/en-us/library/3she1h3z.aspx)
 

Thread Starter

magnet18

Joined Dec 22, 2010
1,227
OK, thankyou, that makes sense now.

I made the modifications, and the sprite moves up smoothly now, but now it won't come back down. :/

Rich (BB code):
        protected override void Update(GameTime gameTime)
        {
            int MaxX =
                graphics.GraphicsDevice.Viewport.Width - myTexture.Width;
            int MinX = 0;
            int MaxY =
                graphics.GraphicsDevice.Viewport.Height - myTexture.Height;
            int MinY = 0;
            int gravity = 5;
            var velocity = 0;

            UpdateJump();
            // keyboard logic
            KeyboardState newState = Keyboard.GetState();
            TimeSpan jumpTimer = TimeSpan.Zero;

            if (newState.IsKeyDown(Keys.Escape))
            {
                if (!oldState.IsKeyDown(Keys.Escape))
                {
                    this.Exit();
                }
            }

            if (newState.IsKeyDown(Keys.Left))
            {
                if (spritePosition.X > MinX)
                {
                    spritePosition.X = spritePosition.X - 2;
                }
            }

            if (newState.IsKeyDown(Keys.Right))
            {
                if (spritePosition.X < MaxX)
                {
                    spritePosition.X = spritePosition.X + 2;
                }
            }

            if (newState.IsKeyDown(Keys.Up) && oldState.IsKeyDown(Keys.Up) == false && spritePosition.Y >= MaxY && jumping == false)
            {
                jumping = true;
                velocity = 30;
            }

            if (jumping == true)
            {
                jumpTimer += gameTime.ElapsedGameTime;
                if (jumpTimer.CompareTo(new TimeSpan(0, 0, 0, 0, 500)) == 1)
                {
                    jumping = false;
                    jumpTimer = TimeSpan.Zero;
                }
                spritePosition.Y -= gravity;
            }

            if (spritePosition.Y < MaxY && jumping == false)
            {
                spritePosition.Y += gravity;
            }

            if (velocity > 0)
            {
                velocity -= gravity;
            }

            if (spritePosition.Y >= MaxY)
            {
                spritePosition.Y = MaxY;
            }

            if (spritePosition.Y <= MinY)
            {
                spritePosition.Y = MinY;
            }

            // Move the sprite by speed, scaled by elapsed time.





            base.Update(gameTime);
            oldState = newState;
        }
any idea why?
 

Filox

Joined Oct 11, 2011
7
Because in the Update method you reset the counter to zero which means that your bool variable jumping is true and the jumpTimer never reaches 500 miliseconds to stop the jumping. Declare it in the start of your class and not in the Update method.
 
Top