如何扩展在 C# 和 Unity 中使用二次插值创建的曲线?

问题描述

我正在尝试使用二次插值来向玩家的位置扔一块石头。岩石只是跟随曲线。然而,如果玩家移动,岩石开始循环并从其原始位置开始。一旦岩石到达曲线的末端,我就停止了它跟随曲线,并向岩石的刚体添加力,但它仅适用于特定示例。我想知道是否有一种方法可以延长曲线,使岩石撞击地面并使用我已有的代码自行摧毁。我正在使用的代码如下。提前致谢。代码如下。

二次插值代码(每帧运行一次)

private void FollowQuadraticPath()
    {
        interpolateAmount = (interpolateAmount + Time.deltaTime) % 1f;
        pointAB.transform.position = Vector3.Lerp(transformerPosition,throwHeightPosition,interpolateAmount);
        pointBC.transform.position = Vector3.Lerp(throwHeightPosition,playerPosition,interpolateAmount);

        transform.position = Vector3.Lerp(pointAB.transform.position,pointBC.transform.position,interpolateAmount);
    }

伤害

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.GetComponent<PlayerHealth>())
        {
            Destroy(pointABInstance);
            Destroy(pointBCInstance);
            collision.gameObject.GetComponent<PlayerHealth>().Dealdamage(damage);
            Destroy(gameObject);
        }
        else
        {
            Destroy(pointABInstance);
            Destroy(pointBCInstance);
            Destroy(gameObject);
        }
    }

这就是我想要发生的事情。假装玩家已经移动,岩石会继续撞击地面,越过玩家点。

相反,再次假装玩家不在那里,物体在到达地面之前被摧毁

编辑:检查我使用的解决方案的答案评论

解决方法

我猜你在 FollowQuadraticPath() 中使用了 Update,所以你总是在玩家的当前更新位置使用它。

相反,我会使用 Coroutine。协程有点像一个临时的更新方法,所以它有一个明确的开始和结束,你可以让局部变量在例程运行的所有帧中持续存在,并做一些事情,例如

private IEnumerator FollowQuadraticPath()
{
    // Cash the target positions ONCE so they are not updated later
    var startAB = TransformerPosition;
    var targetAB = throwHeightPosition;
    var targetBC = playerPosition;

    // Iterates until 1 second has passed
    // linearly increasing interpolateAmount from 0 to 1    
    for(var interpolateAmount = 0f; interpolateAmount < 1f; interpolateAmount += Time.deltaTime)
    {
        pointAB.transform.position = Vector3.Lerp(startAB,targetAB,interpolateAmount);
        pointBC.transform.position = Vector3.Lerp(targetAB,targetBC,interpolateAmount);

        transform.position = Vector3.Lerp(pointAB.transform.position,pointBC.transform.position,interpolateAmount);

        // Tells Unity to "pause" the routine here,render this frame
        // and continue from here in the next frame
        yield return null;
    }

    // Destroy if it reaches the original player position
    Destroy (gameObject);
}

你运行这个ONCE,例如在

private void Start ()
{
    StartCorouine(FollowQuadraticPath());
}

Start 也可以是例程本身,如

private IEnumerator Start()
{
    var startAB = TransformerPosition;
    var targetAB = throwHeightPosition;

    .....
}

您不必担心终止例程,因为它要么到达原始玩家位置然后被销毁,要么之前撞到地面并被销毁。在任何一种情况下,协程也会自动消失。


但我真正不明白的是为什么你有 2 个额外的转换。为什么不简单地只计算 Vector3 本身,如

var ab = Vector3.Lerp(startAB,interpolateAmount);
var bc = Vector3.Lerp(targetAB,interpolateAmount);

transform.position = Vector3.Lerp(ab,bc,interpolateAmount);