Unity 2D游戏实现手部动画碰撞后冻结功能技术求助
解决Unity 2D手部动画碰撞冻结问题
针对你的需求,核心问题在于未正确实现动画冻结的状态控制,以及协程参数和触发逻辑的错误。以下是修改后的完整脚本,附带关键逻辑说明:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FacingScript : MonoBehaviour { private SpriteRenderer _render; private Camera _mainCam; private Vector3 _mousePos; private Animator _aniHand; private bool _isAnimationFrozen = false; private Coroutine _freezeCoroutine; void Start() { _render = GetComponent<SpriteRenderer>(); _mainCam = Camera.main; _aniHand = GetComponent<Animator>(); gameObject.SetActive(false); } void Update() { if (!gameObject.activeSelf) return; // 处理鼠标朝向 _mousePos = Input.mousePosition; _mousePos = _mainCam.ScreenToWorldPoint(new Vector3(_mousePos.x, _mousePos.y, _mainCam.transform.position.z - transform.position.z)); Vector3 rotation = _mousePos - transform.position; _render.flipY = rotation.x > 0; // 处理E键逻辑:播放/恢复动画 if (Input.GetKeyDown(KeyCode.E)) { if (!gameObject.activeSelf) { gameObject.SetActive(true); _aniHand.Play("CharacterHand"); } else if (_isAnimationFrozen) { // 强制恢复动画 ResumeAnimation(); } else { // 重新播放动画 _aniHand.Play("CharacterHand"); } } } void OnCollisionEnter2D(Collision2D collision) { // 碰撞到箱子或地面时触发冻结,避免重复触发 if ((collision.gameObject.CompareTag("box") || collision.gameObject.CompareTag("ground")) && !_isAnimationFrozen) { _freezeCoroutine = StartCoroutine(FreezeAnimationCoroutine(5f)); } } /// <summary> /// 冻结动画的协程 /// </summary> private IEnumerator FreezeAnimationCoroutine(float waitTime) { _isAnimationFrozen = true; // 记录当前动画进度,恢复时从当前帧继续 float currentNormalizedTime = _aniHand.GetCurrentAnimatorStateInfo(0).normalizedTime; _aniHand.speed = 0; // 等待5秒,期间如果按E则提前退出 float elapsedTime = 0; while (elapsedTime < waitTime && _isAnimationFrozen) { elapsedTime += Time.deltaTime; yield return null; } // 如果不是被E键提前恢复,自动恢复动画 if (_isAnimationFrozen) { ResumeAnimation(); } } /// <summary> /// 恢复动画播放 /// </summary> private void ResumeAnimation() { _isAnimationFrozen = false; _aniHand.speed = 1; // 从冻结时的进度继续播放 _aniHand.Play("CharacterHand", 0, _aniHand.GetCurrentAnimatorStateInfo(0).normalizedTime); // 停止协程(如果存在) if (_freezeCoroutine != null) { StopCoroutine(_freezeCoroutine); _freezeCoroutine = null; } } }
关键修改说明
状态控制优化
- 新增
_isAnimationFrozen标记动画是否冻结,避免碰撞时重复启动协程 - 用
_freezeCoroutine引用协程实例,方便中途停止
- 新增
动画冻结与恢复逻辑
- 冻结时设置
_aniHand.speed = 0,这是最直接的动画暂停方式,同时记录当前动画进度 - 恢复时重置
speed = 1,并通过Play方法的第三个参数从冻结帧继续播放,避免跳帧
- 冻结时设置
E键逻辑完善
- 首次按E激活手部物体并播放动画
- 动画冻结时按E直接恢复播放
- 非冻结状态按E重新播放动画
碰撞触发修正
- 同时支持"box"和"ground"标签的碰撞检测
- 只有在未冻结状态下才触发冻结协程
协程逻辑优化
- 协程内加入循环判断,允许通过E键提前终止冻结状态
- 自动恢复时先检查冻结状态,避免冲突
内容的提问来源于stack exchange,提问作者Jaxferno
相关产品推荐
相关产品推荐

