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

Unity如何实现可传入时长、外部直接调用的嘴部动画协程

Unity PlayerMouthSpeechController 调用简化方案

问题背景

原有PlayerMouthSpeechController脚本存在标志位冗余、Update逻辑混乱的问题,优化后已经实现了传入时长参数控制嘴部动画的功能,但调用时需要外部手动调用StartCoroutine,希望简化调用方式,无需外部处理协程启动逻辑。

实现方案

核心思路是增加一层公共包装方法,把协程启动的逻辑封装在脚本内部:

  1. 将原有返回IEnumerator的协程方法改为私有,避免外部直接调用
  2. 新增一个公共无返回值的AnimateMouth方法,接收时长参数,内部自行启动协程
  3. 额外增加运行状态判断,避免重复触发协程导致逻辑异常

修改后完整代码

using System;
using System.Collections;
using UnityEngine;

public class PlayerMouthSpeechController : MonoBehaviour
{
    public float duration;
    [Range(0, 100)]
    public float valueRange;

    private bool _isTalking = false;
    private SkinnedMeshRenderer _bodySkinnedMeshRenderer;

    void Start()
    {
        _bodySkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
    }

    //Lerp between startValue and endValue over 'duration' seconds
    private IEnumerator LerpShape(float startValue, float endValue, float duration)
    {
        float elapsed = 0;
        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float value = Mathf.Lerp(startValue, endValue, elapsed / duration);
            _bodySkinnedMeshRenderer.SetBlendShapeWeight(0, value);
            yield return null;
        }
    }

    // 内部协程方法,处理嘴部动画逻辑
    private IEnumerator AnimateMouthCoroutine(float timeToTalk)
    {
        _isTalking = true;
        // 启动计时协程,到时间后关闭说话状态
        StartCoroutine(StopTalkingAfterDelay(timeToTalk));
        
        while (_isTalking)
        {
            yield return StartCoroutine(LerpShape(0, valueRange, duration));
            yield return StartCoroutine(LerpShape(valueRange, 0, duration));
        }
    }

    // 计时协程,指定时间后关闭说话状态
    private IEnumerator StopTalkingAfterDelay(float delay)
    {
        yield return new WaitForSeconds(delay);
        _isTalking = false;
    }

    // 对外暴露的公共调用方法,无需外部处理协程
    public void AnimateMouth(float timeToTalk)
    {
        // 可选逻辑:如果当前正在说话,先打断之前的动画再重新启动
        if (_isTalking)
        {
            StopAllCoroutines();
            // 重置嘴部为闭合状态
            _bodySkinnedMeshRenderer.SetBlendShapeWeight(0, 0);
        }
        // 内部启动协程
        StartCoroutine(AnimateMouthCoroutine(timeToTalk));
    }
}

调用方式

其他脚本不需要任何改动,直接调用即可:

// 直接调用,无需手动写StartCoroutine
blendShapeController.AnimateMouth(10f);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 07:06:09