首页 > 解决方案 > 如何在 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);
        }
    }

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

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

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

标签: c#unity3dinterpolationquadratic

解决方案


我猜你正在使用FollowQuadraticPath()inside,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);
}

你运行一次,例如

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

或者Start也可以是例程本身

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

    .....
}

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


不过,我真正不明白的是为什么您为此要进行 2 次额外的转换。为什么不简单地只用Vector3自己计算

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

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

推荐阅读