XNA 中的滚动屏幕 - 简化数学(轻拂手势)

发布于 2024-10-13 06:16:39 字数 1199 浏览 7 评论 0原文

我一直在来回尝试,但我无法计算出在使用轻弹手势时如何滚动视图(或者更确切地说偏移所有对象)的数学原理。我希望滚动有某种缓出效果。

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

这应该不难,但我脑子冻结了:) 请帮帮我!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

二手情话 2024-10-20 06:16:39

您可以在两个值之间进行“lerp”(线性插值)以逐渐接近(快速开始,缓慢结束)。

我假设你正在二维滚动。所以该位置是一个 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();
    //..
}

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();
    //..
}
指尖凝香 2024-10-20 06:16:39

我假设你所说的“缓出”的意思是它逐渐做它应该做的事情(我不太清楚(我对触摸屏和手势不太了解)。

有几种方法可以做到这一点。你可以采用物理方法并使用牛顿定律并简单地求解微分方程,

我通常做这样的事情(例如用鼠标滚动窗口时逐渐停止)的方法是简单地使用带有参数的函数逐渐降低速度。我可以修改以获得我想要的感觉。

在你的情况下,我已经明白你想要做什么,你只是想根据速度更新位置

(通常你会这样做) 。对于 2D),

X_new = X_old + 速度*dt
velocity = max(0,velocity*0.95 - 0.2)

它的作用是逐渐移动 x 坐标(每次循环时 X_old 都会变成 X_new(通常在线程中执行)),这样它就不会完全停止,而是继续移动直到速度达到零。我使用一个简单的 pow 函数来逐渐减少它,但你可以想出任何类型的函数。

您实际上还可以考虑指针到边缘的距离。我在我的一个程序中这样做,这样当鼠标光标移离边缘时,它滚动的速度取决于多远(所以如果你想滚动一点,你就移动一点,如果你想移动很多,你就移动很多)。

请注意,您必须在线程中处理此问题,可能是因为它会持续发生。您还可以计算加速度并使用简单的物理原理来计算基于它的位置。 x = x0 + x'*t + 1/2*x''*t^2 类型的东西。

I assume you mean by "ease out" that it gradually does what it's suppose to do(which I'm not quite clear on(I don't know much about touchpanels and gestures).

There are several ways to do this. You could take a physical approach and use newton's law and simply solve the differential equation.

The way I generally do things like this(such as a gradual stop when scrolling a window with the mouse), is to simply reduce the speed gradually using some function with parameters that I can modify to get the feel I want.

In your case, I've I get what you trying to do, you simply want to update the position based on the velocity.

Suppose your doing it horizontally(in generally you'll do it for 2D),

X_new = X_old + velocity*dt
velocity = max(0, velocity*0.95 - 0.2)

What this does is gradually move the x coordinate(X_old becomes X_new each time through the loop(which you'll usually do in a thread)) so that instead of stopping completely it continues to move until velocity has reached zero. I use a simple pow function to gradually reduce it but you can come up with any type of function.

You can also actually take into account the distance of the pointer to the edge. I do this in one of my programs so that when the mouse cursor is moved off the edge the speed it scrolls depends on how far(so if you wanna scroll a little you move a little and a lot you move a lot).

Be aware you'll have to handle this in a thread probably because it is something that continues to happen. You could also compute the acceleration and use the simple physics to compute the position based on it. x = x0 + x'*t + 1/2*x''*t^2 type of stuff.

小傻瓜 2024-10-20 06:16:39

和往常一样,如果是 XNA,Shawn 可能已经解决了您的问题。在几篇文章中,他使用 Lerp、SmoothStep 和其他数学运算,以及 基于物理的方法。这些示例使用游戏状态管理项目,但这些想法可以在任何地方使用。

顺便说一句,您可能需要考虑不要相对于相机移动所有对象。您可以将向量2或向量3的cameraOffset存储在某处,并在SpriteBatch.Begin中使用transformMatrix。当然,如果您使用一两个 spritebatch 循环来绘制所有世界对象,则这是最有用的。

As usual, if it's XNA, Shawn has probably solved your problem already. In a couple of posts he explains transitions using Lerp, SmoothStep and other math operations, and a physics based approach. The examples use the Game State Management project, but the ideas can be used anywhere.

And, by the way, you might want to consider not moving all the objects around relative to the camera. You can store a vector2 or vector3 cameraOffset somewhere and use a transformMatrix in SpriteBatch.Begin. Of course, this is most useful if you use one or two spritebatch cycles to paint all your world objects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文