Continuing on last week’s article, this week I’ll be showing you an updated way of handling movement using multi-touch. I’ll be starting with the code base from last week, so you can go ahead and get started by downloading that from my SkyDrive share.
At the end of last week, we had a triangle that was being drawn based on a Vector2 called position. position was being updated based on the TouchPanel state. This means that wherever you touch, that’s where the triangle goes. For some games, this is what we want. But what if you wanted to build a game where you had to navigate through a maze. You start on one side, touch the exit, and bang, you win. Instead, you might want to move towards the touch point. That’s what we’ll be doing here.
To begin, we need to calculate the difference between where we are now, and where we want to be. To do this, we just subtract the current position from the touch position. Let’s create a new variable in Update called direction, and set it equal to the difference. If we added position and direction, of course, we get the touch position, so changing the update we had to the following will give you the same results we saw earlier.
We don’t want to move directly to the new location, though, just in that direction. To do this, you can normalize the vector, which means that you create a new vector that points in the same direction as the original, but has a length of one. Once you’ve done that, we get the behavior we wanted.
You’ll notice, though, that you move very slowly. To increase the rate of movement, you can multiply the normalized vector.
If you have a multi-touch capable computer, or if you have a Windows Phone, you can see that putting more than a single finger on the screen makes the triangle move towards both of them. Ideally, we’ll want to set up a primary touch point, and only move towards that. Luckily, touch points are identified uniquely with an int called Id. If we set up an int to track it, let’s call it movementId, we can determine whether a touch point is it, and only move if it is.
We’ll define movementId up with the other variables:
And then modify Update down below. We’ll set the movementId on Pressed, and reset it on Released. If we didn’t reset it on Released, it would work once, then never again. It’s actually interesting to debug and check movementId each time you press on the touch panel. Each time, it increments by one. I’ve also added some code in here to prevent the wiggle you might see as the triangle jumps back and forth over the touch location. Here’s the updated code:
Now only the first finger down will cause movement.
You’ll notice that the triangle still just points in one direction though. That’s easy enough to address. The SpriteBatch Draw method has an overload that includes an argument of type float called rotation. If we set one of those up, we can pass that over. We’ll start by setting up a variable called rotation:
Then modify Update to get the rotation. We have a Vector2 we called direction, which gives us an X and a Y we can use to find an angle. If you look back at your time in trigonometry, you can remember SOH CAH TOA, Some Old Hippy Caught Another Hippy Tripping On Acid, Sine Opposite Hypotenuse, Cosine Adjacent Hypotenuse, Tangent Opposite Adjacent. Since we have X and Y, Adjacent and Opposite, we want to use Tangent. So tan(theta) = y/x, that means theta = arctan(y/x). We have to be careful here for two reasons. First of all, if X is zero, that’s division by zero, and that’s a problem. Second of all, there is a well known problem in finding out the origin quadrant of the original angle, basically, this means you don’t know the sign. I was given a solution to this when I was giving a presentation at one of the Windows Phone launch events in the Atan2 method. It basically handles all of that for you. So with that in mind, the Update code becomes:
And finally, we have to modify the Draw function to make use of the new rotation information. The arguments it asks for are:
And we’re good to go. Next week, I’ll show how collision works.
Download the latest version of the source code