简体   繁体   English

如何在移动Y轴的物体上平滑地改变X物体位置?

[英]How to change X object position smoothly while object with moving Y axis?

Object is moving by Y axis, i need to move X axis position smoothly. 物体在Y轴上移动,我需要平滑地移动X轴位置。

void FixedUpdate()
{
   playerRigidbody.velocity = new Vector2(0.0f, 2.0f);

    if (Input.GetKeyDown(KeyCode.RightArrow))
    {
        if (newBallPos != 2)
        {
            Vector3 pos1 = this.transform.position;
            Vector3 pos2 = this.transform.position;
            pos2.x += 1f;
            StartCoroutine(Move_Routine(this.transform, pos1, pos2));
        }
    }

   ----
}

----

private IEnumerator Move_Routine(Transform transform, Vector3 from, Vector3 to)
{
    float t = 0f;
    while (t < 1f)
    {
        t += Time.deltaTime;

        transform.position = Vector3.Lerp(from, to, Mathf.SmoothStep(0f, 1f, t));
        yield return null;
    }
}

With this code. 有了这段代码。 X axis changes, but with old Y axis position and it create's kind of shaking for time X axis moves. X轴发生变化,但是旧的Y轴位置会产生X轴移动时的抖动。

On arrow click, i need to change Object X position smoothly, while still moving by Y axis.(I need to change X position by 1) 在箭头上单击,我需要平滑地更改对象X位置,同时仍然按Y轴移动。(我需要将X位置改变1)

Appreciate for your help! 感谢您的帮助!

Try adding the x axis to Time.smoothDeltaTime; 尝试将x轴添加到Time.smoothDeltaTime; in this method, values are averaged over several frames for a more smooth looking effect, it is a preference but sometimes can make a noticeable difference. 在这种方法中,值在几帧上取平均值以获得更平滑的效果,这是一种偏好,但有时会产生明显的差异。

 pos2.x += Time.smoothDeltaTime;

First as far as I understand you only want to smooth the X value of the position so you shoudl rather do 首先,据我所知,你只想平滑位置的X值,所以你应该这样做

private IEnumerator Move_Routine(Transform transform, float from, float to)
{
    float t = 0f;
    while (t < 1f)
    {
        t += Time.deltaTime;

        // only lerp the single float value
        var currentX = Mathf.SmoothStep(from, to, t);

        // let the current other two values unchanged
        transform.position.x = currentX;

        yield return null;
    }

    // Just to be sure there is no under/overshooting I would
    // always set the fixed value in the end
    transform.position.x = to;
}

However, another issue in your case is that you are dealing with RigidBody. 但是,您的另一个问题是您正在处理RigidBody。

  1. You should not use transform.position = on rigidbodies at all but rather either playerRigidbody.position = or playerRigidbody.MovePosition(targetPosition) 你根本不应该在playerRigidbody.position =上使用transform.position =而是使用playerRigidbody.position =或者playerRigidbody.MovePosition(targetPosition)

  2. A Coroutine is executed every Update call but you should change rigidbodies only in FixedUpdate => you can use WaitForFixedUpdate in your coroutine 每次Update调用都会执行一个Coroutine,但是你应该只在FixedUpdate更改刚体=>你可以在你的协程中使用WaitForFixedUpdate

  3. A third issue is that you might have multiple Coroutines running at the same time if you press the button again before the movement was finished. 第三个问题是,如果在移动完成之前再次按下按钮,则可能会同时运行多个Coroutines。 => you can solve this by a simply bool flag. =>你可以通过简单的bool标志解决这个问题。 Alternatively if you want to allow input (eg for moving in the other direction you should StopCoroutine the current routine first) 或者,如果您想允许输入(例如,为了向另一个方向移动,您应StopCoroutine当前例程)

Therefore the jitter etc. So together: 因此抖动等因此在一起:

private bool alreadyLerping;

private void FixedUpdate()
{
    playerRigidbody.velocity = new Vector2(0.0f, 2.0f);

    if (Input.GetKeyDown(KeyCode.RightArrow))
    {
        // only do if not lerping laready otherwise input is ignored
        if (newBallPos != 2 && !alreadyLerping)
        {
            var currentX = transform.position.x;
            var targetX = currentX + 1.0f;
            StartCoroutine(Move_Routine(currentX, targetX));
        }
    }

    ...
}

// I just added an optional duration value
// if you do not pass it it will be 1 second as you had it
// but this way you can still make it faster or slower without having
// to hardcode
// you also don't have to pass in the transform or if you do you should not call it transform
private IEnumerator Move_Routine(float from, float to, float duration = 1.0f)
{
    if(alreadyLerping) yield break;

    alreadyLerping = true;

    var passedTime = 0f;

    do
    {
        yield return new WaitForFixedUpdate();

        var lerpfactor = passedTime / duration;

        var currentX = Mathf.SmoothStep(from, to, lerpfactor);

        playerRigidbody.MovePosition(new Vector3(currentX, transform.position.y, transform.position.z));

        passedTime += Time.deltaTime;

    } while (passedTime < duration);

    // Just to be sure there is no under/overshooting I would
    // always set the fixed value in the end
    playerRigidbody.MovePosition(new Vector3(to, transform.position.y, transform.position.z));

    // release the flag
    alreadyLerping = false;
}

or if you want the StopCoroutine variant 或者如果你想要StopCoroutine变种

private IEnumerator currentRoutine;

private void FixedUpdate()
{
    playerRigidbody.velocity = new Vector2(0.0f, 2.0f);

    if (Input.GetKeyDown(KeyCode.RightArrow))
    {
        // only do if not lerping laready otherwise input is ignored
        if (newBallPos != 2)
        {
            var currentX = transform.position.x;
            var targetX = currentX + 1.0f;

            if(currentRoutine!=null) StopCoroutine(currentRoutine);

            currentRoutine = Move_Routine(currentX, targetX);

            StartCoroutine(currentRoutine);
        }
    }

    ...
}

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

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