Unity中能否在协程内修改按引用传递的数值?
Unity协程实现Float平滑过渡的简洁方案
针对你遇到的ref参数在协程和Lambda中受限、C#版本不支持ref字段的问题,这里提供一个无需繁琐委托的解决方案——用轻量引用包装类间接持有需要修改的float值,完美兼容Unity主流C#版本。
1. 定义Float引用包装类
先写一个极简的引用类型,用来包裹要动画的float值:
public class FloatRef { public float Value; public FloatRef(float initialValue = 0f) { Value = initialValue; } }
2. 实现MonoBehaviour扩展协程方法
写一个通用的扩展方法,处理平滑过渡逻辑:
using UnityEngine; using System.Collections; public static class CoroutineExtensions { // 基础线性过渡 public static IEnumerator LerpFloat(this MonoBehaviour mono, FloatRef targetRef, float targetValue, float duration) { float startValue = targetRef.Value; float elapsed = 0f; while (elapsed < duration) { elapsed += Time.deltaTime; float t = Mathf.Clamp01(elapsed / duration); targetRef.Value = Mathf.Lerp(startValue, targetValue, t); yield return null; } // 确保最终值精确到位 targetRef.Value = targetValue; } // 可选:支持自定义缓动曲线的重载 public static IEnumerator LerpFloat(this MonoBehaviour mono, FloatRef targetRef, float targetValue, float duration, AnimationCurve easeCurve) { float startValue = targetRef.Value; float elapsed = 0f; easeCurve ??= AnimationCurve.Linear(0, 0, 1, 1); while (elapsed < duration) { elapsed += Time.deltaTime; float t = Mathf.Clamp01(elapsed / duration); targetRef.Value = Mathf.Lerp(startValue, targetValue, easeCurve.Evaluate(t)); yield return null; } targetRef.Value = targetValue; } }
3. 实际使用示例
在你的业务脚本中直接调用:
public class Example : MonoBehaviour { // 用FloatRef包裹需要动画的float private FloatRef _moveSpeed = new FloatRef(2f); void Start() { // 启动协程:2秒内把_moveSpeed从2过渡到8 StartCoroutine(this.LerpFloat(_moveSpeed, 8f, 2f)); // 可选:用缓动曲线实现非线性过渡 // AnimationCurve ease = AnimationCurve.EaseInOut(0, 0, 1, 1); // StartCoroutine(this.LerpFloat(_moveSpeed, 8f, 2f, ease)); } void Update() { // 直接使用_moveSpeed.Value即可拿到实时动画后的值 transform.Translate(Vector3.forward * _moveSpeed.Value * Time.deltaTime); } }
方案优势
- 避开了Unity协程不支持ref参数的限制,也不需要依赖高版本C#的ref字段特性
- 使用方式简洁,仅需用
FloatRef包装目标float,无需每次写繁琐的委托逻辑 - 支持扩展缓动曲线,满足不同动画需求
内容的提问来源于stack exchange,提问作者Idyia
相关产品推荐
相关产品推荐

