In a naive implementation of handling touch input, you could just take the touch point as fact, and the entity would snap directly over to the user's finger in the scenario described above. This may be visually jarring, which of course may be ok for your game. However, if you want your entity to have more of a realistic presence in the game world, to feel more "real", the you probably don't want it teleporting around the screen; At the same time, you want the user's input not to feel laggy or non-responsive.
So how do we handle this fundamental difference in user input techniques?
The problem of incomplete or inconsistent input reminded me of the network prediction sample, which is available on the XNA Creator's Club site (http://creators.xna.com/en-US/sample/networkprediction). In that sample, they present two solutions to deal with the issues brought on by network latency. Particularly, I was interested in their smoothing solution because it solves my problem.
Smoothing is a simple concept. When a network packet is received, rather than teleporting immediately to the new position, we can interpolate gradually from the previous position toward this new location, giving the illusion of continuous motion ...I took that smoothing concept and applied it here so that when the user re-touches in another location, the onscreen entity will smoothly accelerate towards his current touch point. And because it's using interpolation, it will always catch up to the current location after half a second regardless of where the user is moving his finger.
- Required: Windows Phone CTP
- Download: XNATouchSmoothing.zip
Little touches like this add an extra level of polish that players will appreciate ... and yes, I intended the pun ;-)class Entity { private Vector2 lastKnownPosition; private Vector2 touchPosition; private float currentSmoothing;
public Vector2 Position; public Texture2D Texture;
public void Update() { var touches = TouchPanel.GetState(); float decay = 1f / 15f;
bool isTouching = touches.Count > 0; bool isCatchingUp = currentSmoothing > 0;
if (isTouching) { if (isCatchingUp) { currentSmoothing -= decay; }
foreach (var touch in touches) { touchPosition = touch.Position; } } else if (!isCatchingUp) { currentSmoothing = 1; }
if (!isCatchingUp) { lastKnownPosition = touchPosition; }
Vector2 positionToDraw = lastKnownPosition; if (isCatchingUp) { Vector2.Lerp( ref touchPosition, ref lastKnownPosition, currentSmoothing, out positionToDraw); }
this.Position = new Vector2( positionToDraw.X - Texture.Width / 2, positionToDraw.Y - Texture.Height / 2); } }