Search code examples
mathxnagestureeasing

Scroll screen in XNA - Easing math (flick gesture)


I've been trying back and forth, but I can't figure out the math on how to scroll my view (or rather offset all objects) when using the flick gesture. I would like the scrolling to have some kind of ease-out.

    public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
    {
        float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

        //Some math to change 'matrixOffsetY'
        //I use 'matrixOffsetY' to offset my objects in Draw()

        base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
    }

Here's the gesture event

    public override void HandleInput(InputState input)
    {
        if (input == null)
            throw new ArgumentNullException("input");

        while (TouchPanel.IsGestureAvailable)
        {
            GestureSample gesture = TouchPanel.ReadGesture();

            switch (gesture.GestureType)
            {
                case GestureType.Flick:
                    {
                        //Set a variable with some math? Using:
                        //gesture.Delta

                        //gesture.Delta gives us pixels/sec
                        break;
                    }
                default: return;
            }
        }
    }

This shouldn't be that hard, but I have a brain-freeze :) Please help me out!


Solution

  • You can "lerp" (linear interpolate) between two values to gradually get closer (starting fast, ending slowly).

    I assume you're scrolling in 2D. So the position is a Vector2.

    Try something like this:

    position; //current position of the object.
    targetPosition; //set by scrolling, position should gradually come close to this
    float weigth; //how much the weight is of the targetPosition compared to the position
    //practically this means how fast position approaches targetPosition. 
    //First try values between 0 and 1, for example 0.8f for starters.
    public void Scroll(Vector2 ammount)
    {
       //We assume scrolling the scrollbar 1 pixel down, means the object should go 1 pixel up.
       //So the targetPosition should move the same ammount opposite.
       //If you don't want scrolling to correspond 1:1, you can multiply ammount by a float.
       targetPosition -= ammount;   
    }
    
    public void Update(GameTime gameTime)
    {
        //..
        //Executed every update, position closes in on targetPosition pretty fast.     
        position = Vector2.Lerp(position, targetPosition, weigth);
    
        //Because we Lerp position will only get extremely close to targetPosition. Never exactly at it.
        //most of the time this is good enough, if this isnt use the following code
    
        float omega = 0.05f; // the minimum dinstance between position and targetPosition before we clamp
        if(Vector2.Distance(position, targetPosition) < omega)
        {
            position = targetPosition;
        }
        //..
    }
    
    public void Draw(GameTime gameTime)
    {
        //..
        spriteBatch.Begin();
        spriteBatch.Draw(texture, position, Color.White);
        spriteBatch.End();
        //..
    }