Steph
Steph

Reputation: 41

Mouse movement: Click the sprite "walks" to point clicked

I'm pretty new to C# and XNA and well programing (like I can follow a tutorial but most of the creating it on my own is still really really hard). Right now I'm going round and round trying to figure out how to do this one "simple" thing.

Here's the idea, its going to be a tower defense game; right now I'm working on bare bone basics. I've got my little sprite guy who will move around with Keyboard input, now I want to click somewhere on the screen and have him "walk" to that point. Only I'm lost on the logic. I can click and he'll jump there with

if (aMouse.LeftButton == ButtonState.Pressed)
{
  Position.X = aMouse.X;
  Position.Y = aMouse.Y;
} 

From what I've read for other mousing input, I'm thinking I'll need some kind of loop (bool maybe?) that will move the sprite in a direction and will have to run a check to see if he's got to that point yet. But getting that point after the mouse click and creating that loop, running the check...I'm clueless.

Upvotes: 4

Views: 3025

Answers (4)

Bixel
Bixel

Reputation: 75

I have found this code to be most useful... additionally I have added an extra couple lines to prevent certain situations from occuring. For instance there will be times where direction is 0.83 and speed may have been modified by game factors like terrain/wheather/etc.... if speed is below 1, the sprite may not move at all or even move in the wrong direction!

 if (Vector2.Distance(Position, TargetPosition) > 2.0f)
 {
    velocity = Vector2.Subtract(TargetPosition, Position);
    velocity.Normalize();
    /// Now no matter which direction we are going we are always moving @ sprite.Speed
    /// at velocity or speed below 1 - problems occur where the unit may not move at all!!
    if(current_Speed < 1)
    {
       Vector2 temp = (velocity * 10) * (current_Speed * 10);
       Position += temp / 10;
    }
    else
    { 
       Vector2 temp = velocity * current_Speed;
       Position += temp;
    }
    //convert to int to render sprite to pixel perfect..
    Position = new Vector2((int)Position.X, (int)Position.Y);
 }

Upvotes: 0

Merlyn Morgan-Graham
Merlyn Morgan-Graham

Reputation: 59131

People are answering your question at a very low level. Sometimes it help to think of the problem at a higher level.

What you need is a type of state management. The fancy Computer Science term for that is a Finite State Machine. But don't bother looking that up right now. It's fairly dry and confusing at first :)

Your character currently has one state - "standing around". You need to add and process the "walking to destination" state.

From what I've read for other mousing input, I'm thinking I'll need some kind of loop

You need one loop, called the game loop. If you're using XNA, you've already got one. But you're on the right track.

Every time through the game loop, you should process the current state, and check for what are called State Transitions. That's when you change something in your world from one state to another state. For example, when you click the mouse, you want the guy to start moving.

In your game loop you check to see if a mouse click just happened. If it did, then set up some data (where to move to), and tell him to start walking by setting his state to "walking to destination". Next update, you'll process that state instead.

When your character is in the "walking to desintation" state, you need to update their position, based on the amount of time that passed since the last game update. In XNA, this is calculated for you. If you're not using XNA, then you'll have to check yourself. You might be able to use something like the Stopwatch class, and check the Elapsed field.

If the character is at the destination, you need to switch them back to the "standing around" state.

If you receive another mouse click, it is up to you if you want the "walking to destination" state to pay attention to it or not. If you do pay attention to it, you set up the same sort of data as when you transitioned from the "standing around" state.

So, you'll need these variables:

  • A timer, to find out the elapsed time since the last game loop (XNA gives it to you)
  • The current player state (maybe an enum)
  • The current player position (a vector)
  • The walking speed of the player (a float, probably), measured in units per second (or millisecond)
  • Data for the "walking to destination" state - target position (another vector)
  • Data related to user input (mouse events that occurred since the last update, the position of those clicks, etc)

The character specific data will be different for each character in your game, so you want a new copy of it for each. You'll probably want to put it in a class. The rest of it is more global, so you can keep it separate, or make it part of your game, game loop, input classes, etc (however you choose to organize it).

I won't cover the vector math for how to actually calculate the partial movement stuff, since other people have covered that. No sense in duplicating those answers. It basically boils down to making a vector between your current position and the target position, and multiplying/dividing it by your walking speed (to chop it up to the distance moved in a single update).

Upvotes: 2

corsiKa
corsiKa

Reputation: 82589

I'm assuming you have three things:

  1. Current position
  2. Desired position
  3. Speed to move each 'game tick' // don't know what a game tick is? find out!

You're looking at doing this

enter image description here

// dx, dy are delta x and delta y. It's how far in each direction
// the player must travel
// note, I fixed a typo where they were desired - desired... should be
// desired - current, as they are now
float dx = desiredX - currentX;
float dy = desiredY - currentY;

// d uses the pythagorean theorum to find the distance between current and desired
float d = sqrt(dx*dx + dy*dy);
// fac is how far along that line between desired and current will you move
float fac = d / speed;

// mx is the component of the dx line proportional to the size of fac : d
// which means it's how far in the x direction you'll move
float mx = dx * fac;
float my = dy * fac;

// the new postition is the old position plus the move value
float newPositionX = dx + mx;
float newPositionY = dy + my;

Upvotes: 1

You need to add some instance variables:

Point2D targetPos;

And some constants:

const Point2D speed;

When you run through your Update() loop, update the current position by adding the speed vector to it (in the correct direction of course) until you are within a predefined threshold from the target position (usually the thresholds are calculated from the speed vector - if the distance from the current position to the target position is less than the length of the speed vector, then you're at your position). Using a bool in this case would work well. When you click your mouse set another instance variable (moving) to true, and once you've reached your target position, set moving to false.

Upvotes: 2

Related Questions