0
\$\begingroup\$

So, I'm trying to make my sprite walk to the X-coordinate of my mouse click. This is my code:

currentMouseState = Mouse.GetState();
            MouseState mouseState = Mouse.GetState();
            if (lastMouseState.LeftButton == ButtonState.Released && currentMouseState.LeftButton == ButtonState.Pressed)
            {
                int mouseposx = mouseState.X;
                if (playerPosition.X < mouseposx)
                    {
                        playerPosition.X += 3;
                    }               
                if (playerPosition.X > mouseposx)
                    {
                        playerPosition.X -= 3;                           
                    }
            }`

The problem is that the sprite will walk only 3 pixels and then stop. If I use while instead, like this:

  currentMouseState = Mouse.GetState();
            MouseState mouseState = Mouse.GetState();
            if (lastMouseState.LeftButton == ButtonState.Released && currentMouseState.LeftButton == ButtonState.Pressed)
            {
                int mouseposx = mouseState.X;
                while (playerPosition.X < mouseposx)
                    {
                        playerPosition.X += 3;
                    }               
                while (playerPosition.X > mouseposx)
                    {
                        playerPosition.X -= 3;
                    }
            }

it will simply teleport to the X-coordinate instead. I tried adding a delay using Thread.Sleep(ms), but that just made it freeze and then teleport anyway.

So, what should I do?

EDIT: This is the new code, by Byte56.

currentMouseState = Mouse.GetState();
            MouseState mouseState = Mouse.GetState();
            if (lastMouseState.LeftButton == ButtonState.Released && currentMouseState.LeftButton == ButtonState.Pressed)
            {
                if (playerPosition.X - mouseState.X < 3)
                {
                    playerPosition.X = mouseState.X;
                }
                else if (playerPosition.X < mouseState.X)
                {
                    playerPosition.X += 3;
                }
                else if (playerPosition.X > mouseState.X)
                {
                    playerPosition.X -= 3;
                }
            }

edit3:

 void update()
        {
            // Check if the player has reached the target, if not, move towards it. 
            if (playerPosition.X - playerTarget.X < 3)
            {
                playerPosition.X = playerTarget.X;
            }
            else if (playerPosition.X > playerTarget.X)
            {
                playerPosition.X -= 3;
            }
            else if (playerPosition.X < playerTarget.X)
            {
                 playerPosition.X += 3;
            }


        }

and

 currentMouseState = Mouse.GetState();
            MouseState mouseState = Mouse.GetState();

            if (lastMouseState.LeftButton == ButtonState.Released && currentMouseState.LeftButton == ButtonState.Pressed)
            {
                // This will give the player a target to go to. 
                playerTarget.X = mouseState.X;
            }
            update();
\$\endgroup\$
3
  • \$\begingroup\$ Is this coding running in a spearate thread? \$\endgroup\$
    – olevegard
    May 13, 2013 at 17:48
  • \$\begingroup\$ No, this code is directly inside the update() method \$\endgroup\$ May 13, 2013 at 18:07
  • \$\begingroup\$ look up how a game loop works. \$\endgroup\$
    – Stephen
    May 13, 2013 at 19:45

3 Answers 3

8
\$\begingroup\$

Using a while loop inside your game loop is a basic no-no. Think about how the code is being executed and you'll realize why it just teleported or was frozen and then teleported. (hint: how much of that code do you think is run before the next time your graphics are updated?)

You want to have a target position, then on each iteration of your game loop check to see if your character has arrived at the target position. If it hasn't arrived yet, move it slightly closer.

if (lastMouseState.LeftButton == ButtonState.Released && currentMouseState.LeftButton == ButtonState.Pressed) 
{
    targetPosition.set(mouseState.X, mouseState.Y);
}

if (Math.Abs(playerPosition.X - targetPosition.X) < playerSpeed) 
{ 
   //handle the case where we're very close and would over shoot the position by moving
   playerPosition.X = targetPosition.X; 
}
else if (playerPosition.X < targetPosition.X)
{
    //we're at a position less than the target, add to our position
    playerPosition.X += playerSpeed;
} 
else if (playerPosition.X > targetPosition.X)
{
    //we're at a position greater than the target, subtract from our position
    playerPosition.X -= playerSpeed;
}

Remember that computers only do exactly what you tell them.

\$\endgroup\$
8
  • 4
    \$\begingroup\$ Also using Thread.sleep() should be discouraged. It's better to have a timer that gives you a delta time for making movement correct. \$\endgroup\$
    – olevegard
    May 13, 2013 at 17:51
  • \$\begingroup\$ I tried using your code, but it still doesn't work. Now it moves 3pxl and stops if mousepos.X < playerPosition.X and teleports if mousepos.X > playerPosition.X... \$\endgroup\$ May 13, 2013 at 18:00
  • \$\begingroup\$ @EliasFinoli your post with your new code. \$\endgroup\$
    – olevegard
    May 13, 2013 at 18:12
  • \$\begingroup\$ @olevegard, the new code is now in the bottom of my Question. Could not answer my own question since I dont have enough rep for that. \$\endgroup\$ May 13, 2013 at 18:18
  • \$\begingroup\$ @EliasFinoli Mark this as the accepted answer, then. This is the correct fix for your issue. \$\endgroup\$ May 13, 2013 at 18:57
2
\$\begingroup\$

You need a variable that stores the position that was clicked ( the target of the object. ) This position could be set when you check the rest of your input like this

MouseState mouseState = Mouse.GetState();
if (lastMouseState.LeftButton == ButtonState.Released && currentMouseState.LeftButton == ButtonState.Pressed)
{
    // This will give the player a target to go to. 
    playerTarget.X = mouseState.X;
}

Now we have the position the object is supposed to go to. Now we need to move it towards it. We need to do this every iteration of the main loop, but outside of the code that checks the input. It is useful to put this in a separate function.

 void update( )
 {
     // Check if the player has reached the target, if not, move towards it. 
     if (playerPosition.X < playerTarget.X)
     {
         playerPosition.X += 3;
     }
     else if (playerPosition.X > playerTarget.X)
     {
         playerPosition.X -= 3 ;
     }

 }

This function works just like your function, but it will be execute ever frame regardless of pressed buttons. Now all you have to do is add a function call to this function in your main loop :

 update ( ); 
\$\endgroup\$
5
  • \$\begingroup\$ I don't really understand the logic in this code. Could you explain? Appreciate your help! \$\endgroup\$ May 13, 2013 at 19:29
  • \$\begingroup\$ @EliasFinoli Added some explanation and simplified to make my logic more clear \$\endgroup\$
    – olevegard
    May 13, 2013 at 19:43
  • \$\begingroup\$ Thank you. Though, how/where do I declare playerTarget? Can't seem to figure that little bit out. \$\endgroup\$ May 13, 2013 at 20:00
  • \$\begingroup\$ @EliasFinoli Declare it in the same place as playerPosition. It's just a 2d vector that holds the target of the player. \$\endgroup\$
    – olevegard
    May 13, 2013 at 20:01
  • \$\begingroup\$ This worked, except when it reaches it's destination, it sometimes (most cases actually) lags back and forth like 3 pixels (I'm guessing 3 pixels since that's my speed) I tried adding this line: else if (playerPosition.X - playerTarget.X < 3) { playerPosition.X = playerTarget.X; } but that didn't really help. Any ideas? \$\endgroup\$ May 13, 2013 at 20:20
-2
\$\begingroup\$

Could this be causing your issues?

if (lastMouseState.LeftButton == ButtonState.Released && currentMouseState.LeftButton == ButtonState.Pressed)

You are saying here:

If the left mouse button was released AND is being pressed currently;

This seems like contradicting actions, mouse buttons are usually pressed first, then released to signify a singular action (or continuously pressed to signify on-going action(s)). Perhaps what you are looking for is here is:

If the left mouse button was released OR is being pressed currently;

if (lastMouseState.LeftButton == ButtonState.Released || currentMouseState.LeftButton == ButtonState.Pressed)

Try that out and see what it does to your teleporting and short-stops.

\$\endgroup\$
3
  • \$\begingroup\$ No, was released && isDown is just a way of making sure this is the first frame this button was pressed. The or statement will be true in all cases except if the button was down in the previous frame and was pressed in this one. \$\endgroup\$
    – olevegard
    May 13, 2013 at 18:42
  • \$\begingroup\$ In one way, it's behaving more like I want it to, but it's moving regardless if I click or not. This is what the movement looks like: youtube.com/watch?v=jFpzCXrKpFI&feature=youtu.be \$\endgroup\$ May 13, 2013 at 18:56
  • 2
    \$\begingroup\$ He is actually checking if the "lastMouseState" was released and the "currentMouseState" is pressed. So the if statement itself is fine. \$\endgroup\$ May 13, 2013 at 19:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .