You need to enable JavaScript to run this app. 如何在C#与Unity中延伸二次插值生成的运动曲线?
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#与Unity中延伸二次插值生成的运动曲线?

问题核心原因

  • 插值计算使用%1f取模,interpolateAmount超过1后会重置为0,导致石块位置跳回曲线起点,出现循环往返的问题
  • 原代码每帧读取实时playerPosition计算曲线,玩家移动后曲线终点会实时偏移;且碰撞逻辑未筛选碰撞体,只要触发碰撞就销毁,导致石块未落地就被提前删除

修复方案

步骤1:修改曲线运动逻辑

移除取模逻辑,插值超过1后切换为惯性运动,同时缓存石块生成时的玩家位置作为固定曲线终点,避免玩家移动导致曲线偏移。

// 新增需要声明的变量
private Rigidbody2D rb;
// 缓存石块生成时的玩家位置,作为固定曲线终点
private Vector3 initialPlayerPosition;
// 标记曲线运动是否结束
private bool isCurveCompleted = false;

private void Awake()
{
    rb = GetComponent<Rigidbody2D>();
    initialPlayerPosition = playerPosition;
    // 曲线运动阶段关闭重力,避免干扰插值位置
    rb.gravityScale = 0;
}

private void FollowQuadraticPath()
{
    if (isCurveCompleted) return;

    // 移除%1f取模,避免插值循环
    interpolateAmount += Time.deltaTime;

    // 插值到终点后切换为物理惯性运动
    if (interpolateAmount >= 1f)
    {
        interpolateAmount = 1f;
        // 计算曲线终点的切线方向,作为后续飞射的初速度方向
        Vector3 curveEndTangent = (pointBC.transform.position - pointAB.transform.position).normalized;
        // 可根据手感调整速度倍率
        float throwSpeed = 5f;
        // 开启重力,施加初速度
        rb.gravityScale = 1;
        rb.velocity = curveEndTangent * throwSpeed;
        isCurveCompleted = true;
        // 提前销毁不需要的辅助点
        Destroy(pointABInstance);
        Destroy(pointBCInstance);
        return;
    }

    pointAB.transform.position = Vector3.Lerp(transformerPosition, throwHeightPosition, interpolateAmount);
    // 用缓存的初始玩家位置计算曲线,不要用实时playerPosition
    pointBC.transform.position = Vector3.Lerp(throwHeightPosition, initialPlayerPosition, interpolateAmount);
    transform.position = Vector3.Lerp(pointAB.transform.position, pointBC.transform.position, interpolateAmount);
}

步骤2:修改碰撞销毁逻辑

仅在碰到玩家或地面时销毁石块,避免碰到其他物体提前销毁。

private void OnCollisionEnter2D(Collision2D collision)
{
    // 碰到玩家造成伤害后销毁
    if (collision.gameObject.TryGetComponent<PlayerHealth>(out var playerHealth))
    {
        playerHealth.DealDamage(damage);
        DestroySelf();
        return;
    }

    // 碰到地面后销毁,可替换为你项目的地面Layer判断逻辑
    if (collision.gameObject.CompareTag("Ground"))
    {
        DestroySelf();
    }
}

// 封装销毁逻辑,避免重复代码
private void DestroySelf()
{
    if (pointABInstance != null) Destroy(pointABInstance);
    if (pointBCInstance != null) Destroy(pointBCInstance);
    Destroy(gameObject);
}

注意事项

  • 需提前给地面物体设置对应Tag(比如Ground)或专属Layer,避免石块误触其他场景物体提前销毁
  • 速度倍率、重力缩放值可根据游戏需求调整,保证石块飞出去后的运动轨迹符合手感预期
  • 如果不需要重力影响的抛物轨迹,可保持rb.gravityScale = 0,石块会沿曲线切线方向匀速直线运动,直到碰到碰撞体

内容的提问来源于stack exchange,提问作者Njal_Inferno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 01:48:02