当前位置: 首页 > news >正文

Animation控制单条动画播放(手动设置起始帧、结束帧)

代码如下:

using System.Collections; using UnityEngine; // 强制挂载Animation组件,避免忘记添加 [RequireComponent(typeof(Animation))] public class Test : MonoBehaviour { private Animation _anim; // 自身的Animation组件 private AnimationState _animState;// 要控制的单条动画状态(核心控制对象) public string animClipName = ""; // 要控制的动画片段名(和Animation组件中一致,空则用默认片段) public float animFrameRate = 30f; // 【配置】动画帧率(Animation窗口查看的数值) private float _startTime; // 实时计算的起始时间(秒) private float _stopTime; // 实时计算的停止时间(秒) private bool _isPlaying = false; // 动画播放状态标记 void Start() { // 初始化组件和动画状态(只执行一次,无需重复初始化) _anim = GetComponent<Animation>(); InitAnimState(); // 初始化动画为单次播放 if (_animState != null) _animState.wrapMode = WrapMode.Once; // 【调用示例1】立即播放:从0帧开始,30帧停止(无延时) // StartCoroutine(PlayAnimFromSpecifiedFrame(0, 30)); // 【调用示例2】延时播放:延时2秒,从5帧开始,40帧停止 StartCoroutine(PlayAnimFromSpecifiedFrame(450, 500, 2f)); } void Update() { // 动画正在播放时,逐帧检测是否到达停止帧(逻辑不变,复用实时计算的_stopTime) if (_isPlaying && _animState != null) { if (_animState.time >= _stopTime) { PauseAnim(); Debug.Log($"动画已在{Mathf.Round(_stopTime * animFrameRate)}帧停止"); } } } #region 初始化AnimationState(逻辑完全不变) private void InitAnimState() { if (_anim == null || _anim.GetClipCount() == 0) { Debug.LogError("请先给Animation组件添加动画片段!", gameObject); return; } if (string.IsNullOrEmpty(animClipName)) { animClipName = _anim.clip.name; _animState = _anim[animClipName]; } else { _animState = _anim[animClipName]; if (_animState == null) { Debug.LogError($"Animation组件中未找到名为{animClipName}的动画片段!", gameObject); } } } #endregion #region 核心改造:协程版 - 带延时+实时帧参数 播放动画 /// <summary> /// 协程版:指定帧区间播放动画,支持延时调用,实时传帧参数 /// </summary> /// <param name="startFrame">本次播放的起始帧(实时传参)</param> /// <param name="stopFrame">本次播放的停止帧(实时传参)</param> /// <param name="delay">延时播放时间(秒),默认0=立即播放</param> /// <returns>协程迭代器</returns> public IEnumerator PlayAnimFromSpecifiedFrame(int startFrame, int stopFrame, float delay = 0f) { // 前置校验:动画状态为空/帧参数非法,直接退出 if (_animState == null) yield break; if (startFrame < 0 || stopFrame < 0) { Debug.LogError("帧参数不能为负数!", gameObject); yield break; } if (startFrame > stopFrame) { Debug.LogError("起始帧不能大于停止帧!", gameObject); yield break; } // 第一步:延时逻辑(delay>0时等待,默认0则直接执行) if (delay > 0f) { Debug.Log($"动画将延时{delay}秒播放,区间:{startFrame}帧 → {stopFrame}帧"); yield return new WaitForSeconds(delay); } // 第二步:实时计算帧对应的时间(核心:不再依赖Inspector配置,随参数变化) _startTime = startFrame / animFrameRate; _stopTime = stopFrame / animFrameRate; // 第三步:停止其他动画,重置并播放当前动画(重复调用自动重置) _anim.Play(animClipName, PlayMode.StopAll); // 停止其他动画,避免冲突 _animState.time = _startTime; // 跳转到实时传入的起始帧 _animState.speed = 1f; // 恢复播放速度 _isPlaying = true; // 更新播放状态 Debug.Log($"动画{animClipName}开始播放,区间:{startFrame}帧 → {stopFrame}帧"); } #endregion #region 手动控制:播放/暂停/重新播放(逻辑完全不变,可正常使用) public void PauseAnim() { if (_animState == null || !_isPlaying) return; _animState.speed = 0f; _isPlaying = false; } public void ResumeAnim() { if (_animState == null || _isPlaying) return; _animState.speed = 1f; _isPlaying = true; } /// <summary> /// 重新播放指定帧区间(封装协程调用,方便外部直接调用) /// </summary> /// <param name="startFrame">起始帧</param> /// <param name="stopFrame">停止帧</param> /// <param name="delay">延时时间</param> public void ReplayAnim(int startFrame, int stopFrame, float delay = 0f) { StartCoroutine(PlayAnimFromSpecifiedFrame(startFrame, stopFrame, delay)); } #endregion #region 辅助方法(帧转时间,备用) private float FrameToTime(int frame) { return frame / animFrameRate; } #endregion // 编辑器调试:实时显示当前播放帧(适配实时传参的帧区间) void OnDrawGizmosSelected() { Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position + Vector3.up * 2, 0.5f); float currentFrame = _animState == null ? 0 : Mathf.Round(_animState.time * animFrameRate); UnityEditor.Handles.Label(transform.position + Vector3.up * 3, $"当前帧:{currentFrame}\n本次停止帧:{Mathf.Round(_stopTime * animFrameRate)}"); } }
http://www.jsqmd.com/news/346855/

相关文章:

  • 必读:用NFT存证你的开源代码贡献值
  • 生物计算测试的崛起与测试员能力重构
  • 情感驱动:星际团队如何建立“光年信任”——软件测试公众号热度内容解析与实战指南
  • 重力适应:2026太空“测试场”上的女性破壁者
  • deepinV23文件管理器改造
  • ‌2026年软件测试热度趋势与生物计算伦理融合报告
  • 高原缺氧环境下的AI压力测试:拉萨样本实战与爆款密码
  • 2026年机械真空泵厂家最新推荐:罗茨真空泵/螺杆式真空泵/螺杆泵真空泵/干式无油螺杆真空泵/干式真空泵/干式螺杆真空泵/选择指南 - 优质品牌商家
  • 从码农到太空农场AI设计师:我的跨域实验与2026公众号热度洞察
  • 基于 .NET Framework 4.8 开发的 WinForms 绑定工具,以极简的代码量实现了完整的双向绑定与数据持久化能力,大幅缩减开发周期与重复编码工作,是桌面工具类项目的高效解决方案。
  • 免费写论文AI工具测评:文献综述一键生成+真实文献交叉引用,这7款神器让论文写作效率翻倍! - 麟书学长
  • 50岁更抢手:2026年太空开发经验资本化术
  • 进程间通信IPC(3)system V标准下基于责任链模式的消息队列,基于建造者模式的信号量
  • 从文献梳理到论文定稿:2026 全流程 AI 写作软件深度推荐
  • 你太久没关注自己了,太久没好好心疼自己了
  • 职业跨界手册:医疗开发者转型基因编辑实战
  • 计算机毕业设计springbootJavaWeb的美食街摊位管理系统 基于SpringBoot框架的集市商铺数字化运营平台设计与实现 智慧夜市摊位资源调度与租赁服务平台开发
  • modbus学习第5天
  • 别再用“雌竞变现”去曲解女性的出片行为了
  • 计算机毕业设计springboot租房数据可视化系统 基于SpringBoot的房屋租赁信息智能分析与展示平台 Java Web驱动的城市租房数据挖掘与可视化管理系统
  • SQLite并发锁问题解决方案
  • PCIe的中断机制
  • 提示工程架构师必备:制定实施计划的6个法律合规要点,避免踩红线
  • azerothCode-更改任务语言显示
  • PWA 渐进式Web应用(Progressive Web App)快应用、离线应用(用Web技术构建原生应用体验网站)manifest.json、Service Worker、Instant App
  • ue 不同版本兼容性测试总结
  • 学术写作效率革命!2026 高精准度 AI 论文写作工具推荐指南
  • SameSite=Lax属性(前端Set-Cookie属性)(跨站链接跳转保留登录态、防御跨站请求POST CSRF、防御跨站请求资源CSRF)子资源请求、安全铁三角HttpOnlySecure
  • 价值投资者如何看待并购和分拆
  • 如何用AR虚拟形象打造开发者IP?2026元宇宙营销