简体   繁体   English

统一 2D 的物理运动

[英]Physics movement for unity 2D

I have a player on XY position.我有一个 XY 位置的球员。 After player's swipe position must be increased or decreased on 1 for x-area.对于 x 区域,玩家的滑动位置必须在 1 上增加或减少。 Tryed to do this by addForce and velocity , but these ways are increasing x-area pos to infinity.试图通过addForcevelocity来做到这一点,但这些方法正在将 x-area pos 增加到无穷大。 So - How i can stop increasing after then position will be (1,0) after (0,0)?那么 - 在(0,0)之后,我如何停止增加位置(1,0)? or mb anything else method can help me?或 mb 有什么其他方法可以帮助我吗?

    void FixedUpdate()
    {
        if (Input.touchCount > 0)
        {
            theTouch = Input.GetTouch(0);

            if (theTouch.phase == TouchPhase.Began)
            {
                theTouchStartPos = theTouch.position;   
            }

            if (theTouch.phase == TouchPhase.Ended)
            {
                theTouchEndPos = theTouch.position;     

                if (theTouchEndPos.x <= theTouchStartPos.x)
                {
                    Debug.Log("swipe left");
                    Move(Vector2.left);
                }

                if (theTouchEndPos.x >= theTouchStartPos.x)
                {
                    Debug.Log("swipe right");
                    Move(Vector2.right);
                }
            }
        }
    }

    void Move(Vector2 direction)
    {
        //playerRb.velocity = new Vector2(direction.x, direction.y) * speed;
        float step = speed * Time.deltaTime;
        playerPos = Vector2.Lerp(playerPos, playerPos + direction, step);
    }

Do not take single frame inputs such as TouchPhase.Began or GetKeyDown in FixedUpdate() .不要在FixedUpdate()采用单帧输入,例如TouchPhase.BeganGetKeyDown It may work on your machine but it will not register the input every time on a faster machine.它可能适用于您的机器,但不会每次都在更快的机器上注册输入。

"FixedUpdate is often called more frequently than Update. It can be called multiple times per frame, if the frame rate is low and it may not be called between frames at all if the frame rate is high ." “FixedUpdate 通常比 Update 更频繁地调用。如果帧速率低,它可以每帧调用多次,如果帧速率高,则可能根本不会在帧之间调用它。” - https://docs.unity3d.com/Manual/ExecutionOrder.html - https://docs.unity3d.com/Manual/ExecutionOrder.html

What this means is that FixedUpdate is not guaranteed to run on the frame when you pressed down, so inputs that only last for one frame such as TouchPhase.Began or GetKeyDown may not register if the framerate is high enough.这意味着当您按下时,不能保证FixedUpdate在帧上运行,因此如果帧速率足够高,则仅持续一帧的输入(例如TouchPhase.BeganGetKeyDown可能不会注册。

It's surprising to me how noone else noticed this.令我惊讶的是没有其他人注意到这一点。

So it sounds like what you are trying to achieve is: Each swipe moves your player one "step" to left or right on the X-axis but smoothly.所以听起来您想要实现的是:每次滑动都会使您的播放器在 X 轴上向左或向右移动一个“步”,但要平稳。

In your current approach you call the Lerp only in one single frame when the touch ends so the object will barely move at all.在您当前的方法中,当触摸结束时,您仅在一帧内调用Lerp ,因此对象几乎不会移动。

I would rather set the target x-axis position and let the playeroventowards that with the given speed in every physics update call.我宁愿设置目标 x 轴位置,并让玩家在每次物理更新调用中以给定的速度向其移动。

As SpicyCatGames pointed out correctly, you should always separate the handling of User Input ( Update ) from the physics ( FixedUpdate ).正如SpicyCatGames正确指出的那样,您应该始终将用户输入 ( Update ) 的处理与物理 ( FixedUpdate ) FixedUpdate

private float targetX;

private void Awake ()
{
    targetX = playerRb.position.x;
}

void FixedUpdate()
{
    // Move the player towards the target position but only on X
    // -> keep the Y velocity
    var position = playerRb.position;
    position.x = Mathf.MoveTowards(position.x, targetX, speed * Time.deltaTime);
    playerRb.MovePosition(position);
}

private void Update ()
{        
    if (Input.touchCount > 0)
    {
        theTouch = Input.GetTouch(0);

        if (theTouch.phase == TouchPhase.Began)
        {
            theTouchStartPos = theTouch.position;   
        }
        else if (theTouch.phase == TouchPhase.Ended)
        {
            theTouchEndPos = theTouch.position;     

            if (theTouchEndPos.x < theTouchStartPos.x)
            {
                Debug.Log("swipe left");
                Move(-1);
            }
            else if (theTouchEndPos.x > theTouchStartPos.x)
            {
                Debug.Log("swipe right");
                Move(1);
            }
        }
    }
}

void Move(float direction)
{
    targetX += direction;
}

This seems to get discussed a lot.这似乎得到了很多讨论。

FixedUpdate is for physics "calculations" . FixedUpdate用于物理“计算”

If you are animating something - that is to, say, you want to draw something each time the scene is drawn (perhaps changing the position) - you very much use Update, not FixedUpdate.如果你正在制作动画——也就是说,你想在每次绘制场景时绘制一些东西(可能改变位置)——你会经常使用 Update,而不是 FixedUpdate。

It's both pointless (and inaccurate) to change the position of on object on the FixedUpdate calls.在 FixedUpdate 调用上更改对象的位置既没有意义(也不准确)。

Say this represents time and the F are fixed update events and the D (draw) are update events假设这代表时间,F 是固定更新事件,D(平局)是更新事件

F  F  F    F F  F F  F  F   F  F  F  F F  F F  F 
 D       D           D  D       D         D

You (of course, obviously) only need to set the position of the object when you are about to draw it.您(当然,显然)只需要在要绘制对象时设置对象的位置。

And indeed, when you're about to draw it: you (obviously) want the position it should be in at that actual time.事实上,当你要绘制它时:你(显然)想要它在那个实际时间应该处于的位置。

(The script given here shows "F" and "D" running .. https://docs.unity3d.com/ScriptReference/MonoBehaviour.FixedUpdate.html ) (此处给出的脚本显示“F”和“D”正在运行 .. https://docs.unity3d.com/ScriptReference/MonoBehaviour.FixedUpdate.html

As it explains in the documentation, FixedUpdate is for physics >>calculations<<.正如文档中所解释的,FixedUpdate 用于物理>>计算<<。 So, if you are extending the physics engine, simulating something, applying the precise rules of a bullet game, or whatever.因此,如果您要扩展物理引擎、模拟某些东西、应用子弹游戏的精确规则,或者其他什么。 (I've rarely had to use it.) Note that interestingly, if for some reason you were calculating a planet or something and doing that every FixedUpdate, you'd still have to actually set the position of the planet (or whatever it is) at the exact moment when you're about to draw it! (我很少使用它。)请注意,有趣的是,如果由于某种原因你正在计算一个行星或其他东西并且在每次 FixedUpdate 时都这样做,你仍然需要实际设置行星的位置(或任何它是) 在您即将绘制它的确切时刻! (ie in Update.) (即在更新中。)


It's another good example of the famously touchy Unity doco.这是著名的 Unity doco 的另一个很好的例子。 In dozens of places they show something being moved (ie, using Update, when the draw happens).在许多地方,它们显示某些东西正在移动(即,使用更新,当平局发生时)。 On that FixedUpdate page it very confusingly just mentions physics "calculations" which is very vague.在那个 FixedUpdate 页面上,它非常令人困惑地只是提到了非常模糊的物理“计算”。 If they had added a couple more words ("for behind the scenes physics calculations where you are not actually getting the position to draw something that's about to be drawn") it would all be clearer!如果他们再添加几个词(“对于幕后物理计算,您实际上并没有获得绘制即将绘制的东西的位置”) ,一切都会更清楚!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM