You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让LineRenderer的SetPosition实现平滑动画?

如何让LineRenderer控制的变色龙舌头伸缩动画更平滑?

我正在制作一款2D游戏,需要实现变色龙舌头从嘴部伸出到目标点再收回的效果。目前通过LineRenderer的SetPosition控制舌头位置,但动画速度过快,不够流畅。以下是我的相关代码,请问有什么方法能让SetPosition的动画更平滑缓慢?

EdgeCollider2D edgeCollider;
LineRenderer myLine;
public Transform pointOne;
public Transform pointfinalZero;
public Transform pointfinal;
public bool isTongue;

void Start()
{
    edgeCollider = this.GetComponent<EdgeCollider2D>();
    myLine = this.GetComponent<LineRenderer>();
}

void Update()
{
    SetEdgeCollider(myLine);
    myLine.SetPosition(0, pointOne.position);
    if(isTongue)
    {
        myLine.SetPosition(1, pointfinal.position);
    }
    if(!isTongue)
    {
        myLine.SetPosition(1, pointfinalZero.position);
    }
}

void SetEdgeCollider(LineRenderer lineRenderer)
{
    List<Vector2> edges = new List<Vector2>();
    
    for(int point = 0; point<lineRenderer.positionCount; point++)
    {
        Vector3 lineRendererPoint = lineRenderer.GetPosition(point);
        edges.Add(new Vector2(lineRendererPoint.x, lineRendererPoint.y));
    }
    edgeCollider.SetPoints(edges);
}

目前功能正常,但希望能让舌头伸出的动画更平滑可见。


解决方案

你当前的代码是直接让舌头从起点跳转到终点,自然会显得突兀。可以通过插值计算实现平滑过渡,这里提供两种实用方案:

方案一:线性插值配合时间增量实现基础平滑伸缩

添加变量记录舌头当前末端位置,在Update中逐步向目标位置插值,保证不同帧率下速度一致:

EdgeCollider2D edgeCollider;
LineRenderer myLine;
public Transform pointOne;
public Transform pointfinalZero;
public Transform pointfinal;
public bool isTongue;
// 控制伸缩速度,值越小动作越慢
public float tongueSpeed = 2f;
// 记录舌头末端当前位置
private Vector3 currentTongueEndPos;

void Start()
{
    edgeCollider = GetComponent<EdgeCollider2D>();
    myLine = GetComponent<LineRenderer>();
    // 初始化舌头到收回状态
    currentTongueEndPos = pointfinalZero.position;
    myLine.SetPosition(1, currentTongueEndPos);
}

void Update()
{
    SetEdgeCollider(myLine);
    myLine.SetPosition(0, pointOne.position);

    // 确定当前目标位置
    Vector3 targetPos = isTongue ? pointfinal.position : pointfinalZero.position;
    // 线性插值过渡到目标位置
    currentTongueEndPos = Vector3.Lerp(currentTongueEndPos, targetPos, tongueSpeed * Time.deltaTime);
    // 更新LineRenderer末端位置
    myLine.SetPosition(1, currentTongueEndPos);
}

void SetEdgeCollider(LineRenderer lineRenderer)
{
    List<Vector2> edges = new List<Vector2>();
    
    for(int point = 0; point < lineRenderer.positionCount; point++)
    {
        Vector3 lineRendererPoint = lineRenderer.GetPosition(point);
        edges.Add(new Vector2(lineRendererPoint.x, lineRendererPoint.y));
    }
    edgeCollider.SetPoints(edges);
}

方案二:协程+动画曲线实现带缓动的自然动画

如果想要更贴近真实生物的运动节奏(比如伸出加速、收回减速),可以用协程结合动画曲线自定义缓动效果:

EdgeCollider2D edgeCollider;
LineRenderer myLine;
public Transform pointOne;
public Transform pointfinalZero;
public Transform pointfinal;
public bool isTongue;
// 单次伸缩动画的总时长
public float animationDuration = 0.5f;
// 自定义缓动曲线,可在Inspector面板调整
public AnimationCurve tongueCurve = AnimationCurve.EaseInOut(0,0,1,1);
// 标记动画是否正在播放,避免重复触发
private bool isAnimating;

void Start()
{
    edgeCollider = GetComponent<EdgeCollider2D>();
    myLine = GetComponent<LineRenderer>();
    myLine.SetPosition(1, pointfinalZero.position);
}

void Update()
{
    SetEdgeCollider(myLine);
    myLine.SetPosition(0, pointOne.position);

    if(isTongue && !isAnimating)
    {
        StartCoroutine(MoveTongueTo(pointfinal.position));
    }
    else if(!isTongue && !isAnimating)
    {
        StartCoroutine(MoveTongueTo(pointfinalZero.position));
    }
}

IEnumerator MoveTongueTo(Vector3 targetPos)
{
    isAnimating = true;
    float elapsedTime = 0f;
    Vector3 startPos = myLine.GetPosition(1);

    while(elapsedTime < animationDuration)
    {
        elapsedTime += Time.deltaTime;
        // 用动画曲线计算插值比例,实现自定义缓动
        float t = tongueCurve.Evaluate(elapsedTime / animationDuration);
        Vector3 newPos = Vector3.Lerp(startPos, targetPos, t);
        myLine.SetPosition(1, newPos);
        yield return null;
    }
    // 确保最终位置精准到达目标点
    myLine.SetPosition(1, targetPos);
    isAnimating = false;
}

void SetEdgeCollider(LineRenderer lineRenderer)
{
    List<Vector2> edges = new List<Vector2>();
    
    for(int point = 0; point < lineRenderer.positionCount; point++)
    {
        Vector3 lineRendererPoint = lineRenderer.GetPosition(point);
        edges.Add(new Vector2(lineRendererPoint.x, lineRendererPoint.y));
    }
    edgeCollider.SetPoints(edges);
}

注意事项

  • 两种方案都使用Time.deltaTime,确保动画速度不受帧率波动影响。
  • 方案二中的isAnimating标记必须保留,防止动画未完成时重复触发导致动作错乱。
  • 可通过调整tongueSpeed或animationDuration参数,找到最适合的动画节奏。

内容的提问来源于stack exchange,提问作者João Carlos P.P.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 10:50:37