news 2026/2/25 6:26:11

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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)}"); } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/21 12:18:45

Windows 也能跑 OpenClaw!最完整安装教程 + 飞书接入,全程避坑

⚠️ 小贴士&#xff1a;在开始之前&#xff0c;有一个非常重要的提醒&#xff1a;由于此类工具涉及自动化操作和环境配置&#xff0c;如果你的电脑存有重要的商业/资产或个人隐私信息&#xff0c;强烈建议弄一台干净的备用设备&#xff0c;或者直接租用一个云端虚拟机&#xf…

作者头像 李华
网站建设 2026/2/24 7:18:09

SameSite=Lax属性(前端Set-Cookie属性)(跨站链接跳转保留登录态、防御跨站请求POST CSRF、防御跨站请求资源CSRF)子资源请求、安全铁三角HttpOnlySecure

文章目录SameSiteLax&#xff1a;在安全与体验间走钢丝的现代 Cookie 智慧&#x1f309; 为什么需要 Lax&#xff1f;—— 从“安全困境”说起❌ Strict 的代价❌ None 的风险✅ Lax 的破局&#x1f52c; 深度解析&#xff1a;Lax 到底“宽松”在哪里&#xff1f;&#x1f4ca;…

作者头像 李华
网站建设 2026/2/20 22:00:33

PWA 渐进式Web应用(Progressive Web App)快应用、离线应用(用Web技术构建原生应用体验网站)manifest.json、Service Worker、Instant App

文章目录 拥抱未来&#xff1a;用PWA打造「离线可用、秒开体验」的现代Web应用&#x1f331; 什么是PWA&#xff1f;不止是“网页升级版”&#x1f511; PWA的三大支柱技术&#x1f31f; 为什么开发者与用户都爱PWA&#xff1f;✅ 对用户&#xff1a;✅ 对开发者/企业&#xff…

作者头像 李华
网站建设 2026/2/22 21:28:07

104. 二叉树的最大深度

104. 二叉树的最大深度 简单 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 示例 2&#xff1a; 输入&a…

作者头像 李华