Экран прокрутки в XNA — упрощение математики (жест пролистывания)

Я пытался взад и вперед, но я не могу понять математику, как прокручивать мое представление (или, скорее, смещать все объекты) при использовании жеста щелчка. Я хотел бы, чтобы прокрутка была какой-то непринужденной.

    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);
    }

Вот событие жеста

    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;
            }
        }
    }

Это не должно быть так сложно, но у меня зависание мозгов :) Пожалуйста, помогите мне!


person Frexuz    schedule 20.01.2011    source источник


Ответы (3)


Вы можете «lerp» (линейная интерполяция) между двумя значениями, чтобы постепенно приближаться (начиная быстро, заканчивая медленно).

Я предполагаю, что вы прокручиваете в 2D. Итак, позиция — это Vector2.

Попробуйте что-то вроде этого:

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();
    //..
}
person Roy T.    schedule 24.01.2011
comment
Вот это да. Работает безупречно и лучше, чем я ожидал! Спасибо. - person Frexuz; 25.01.2011
comment
Привет, Frexuz, рад, что смог помочь! - person Roy T.; 25.01.2011

Я предполагаю, что вы имеете в виду под «облегчением», что он постепенно делает то, что должен делать (что мне не совсем ясно (я мало знаю о сенсорных панелях и жестах).

Есть несколько способов сделать это. Вы можете применить физический подход, использовать закон Ньютона и просто решить дифференциальное уравнение.

Обычно я делаю подобные вещи (например, постепенную остановку при прокрутке окна с помощью мыши) — просто постепенно уменьшаю скорость, используя некоторую функцию с параметрами, которые я могу изменить, чтобы получить желаемое ощущение.

В вашем случае я понимаю, что вы пытаетесь сделать, вы просто хотите обновить позицию на основе скорости.

Предположим, вы делаете это горизонтально (обычно вы делаете это для 2D),

X_new = X_old + скорость*dt скорость = макс(0, скорость*0,95 - 0,2)

Что это делает, так это постепенно перемещает координату x (X_old становится X_new каждый раз через цикл (что вы обычно делаете в потоке)) так, что вместо полной остановки он продолжает двигаться, пока скорость не достигнет нуля. Я использую простую функцию pow, чтобы постепенно уменьшать ее, но вы можете придумать любую функцию.

Вы также можете учитывать расстояние указателя до края. Я делаю это в одной из своих программ, поэтому, когда курсор мыши перемещается за край, скорость его прокрутки зависит от того, как далеко (поэтому, если вы хотите немного прокрутить, вы двигаетесь немного, а много вы двигаетесь много).

Имейте в виду, что вам придется обрабатывать это в потоке, вероятно, потому что это то, что продолжает происходить. Вы также можете вычислить ускорение и использовать простую физику для вычисления положения на его основе. x = x0 + x'*t + 1/2*x''*t^2 типа материала.

person AbstractDissonance    schedule 21.01.2011

Как обычно, если это XNA, Шон, вероятно, уже решил вашу проблему. В паре постов он объясняет переходы, используя Lerp, SmoothStep и другие математические операции, а также физический подход. В примерах используется проект Game State Management, но идеи можно использовать где угодно.

И, кстати, вы можете подумать о том, чтобы не перемещать все объекты относительно камеры. Вы можете где-нибудь сохранить vector2 или vector3 cameraOffset и использовать transformMatrix в SpriteBatch.Begin. Конечно, это наиболее полезно, если вы используете один или два цикла спрайтов для рисования всех объектов вашего мира.

person Elideb    schedule 25.01.2011
comment
На самом деле я делал это раньше, но рисование такого количества объектов одновременно дало мне около 3 кадров в секунду, так как мой холст был высотой 5000 пикселей. Поскольку Y объектов не меняется, я не мог понять, как рисовать только видимые объекты. - person Frexuz; 25.01.2011
comment
Точно так же вы выбираете, что рисовать, если камера статична. Вместо того, чтобы рисовать что-либо внутри прямоугольника (0, 0, screenWidth, screenHeight) плюс отступ, прямоугольник будет (cameraPos.X - halfScreenWidth, cameraPos.Y - halfScreenHeight, screenWidth, screenHeight) плюс отступ. Вы даже можете держать прямоугольник прикрепленным к камере и проверять пересечения. Все, что пересекает его viewRect по оси Z, закрашивается. Добавление разделов в игровую зону сделало бы ее еще быстрее. - person Elideb; 26.01.2011