Unity切换场景后宝箱动画失效问题求助
问题:场景切换后宝箱动画失效
我的游戏包含两个场景,玩家可通过门对象往返切换,使用DontDestroyOnLoad保留玩家对象。初始场景中的宝箱在玩家进入交互范围时会播放打开动画,首次启动时正常;但切换至第二个场景再返回后,宝箱动画不再生效——尽管Animator组件(含动画控制器)、宝箱脚本均存在,Animator设置为“Always Animate”,且仍可与宝箱交互。
相关脚本
宝箱脚本(Chest.cs)
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Chest : MonoBehaviour, IInteractable { [SerializeField] private string prompt; public string InteractionPrompt => prompt; private bool MouseDn = false; Animator animator; private void Awake() { animator = gameObject.GetComponent<Animator>(); } public void OnMouseDown() { MouseDn = true; } public void OnMouseUp() { MouseDn = false; } public bool Interact(Interactor interactor) { animator.SetBool("isOpen", true); if (MouseDn == true) { MouseDn = false; Debug.Log(message:"Opening Chest!"); return true; } else { return false; } } private void Update() { animator.SetBool("isOpen", false); } }
IInteractable接口
public interface IInteractable { public string InteractionPrompt{ get; } public bool Interact(Interactor interactor); }
玩家Interactor脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; public class Interactor : MonoBehaviour { [SerializeField] private Transform interactionPoint; [SerializeField] private float interactionPointRadius = 0.5f; [SerializeField] private LayerMask interactableMask; private readonly Collider[] colliders = new Collider[3]; [SerializeField] private int numFound; private void Update() { numFound = Physics.OverlapSphereNonAlloc(interactionPoint.position, interactionPointRadius, colliders, interactableMask); if (numFound > 0) { var interactable = colliders[0].GetComponent<IInteractable>(); if (interactable != null) { interactable.Interact(this); } } } }
问题根源与修复方案
1. 核心问题:帧级状态覆盖
Chest脚本的Update方法每帧都会将isOpen设为false,而Interact仅在触发时单次设置isOpen为true。首次运行时动画能生效是因为帧同步刚好让动画启动,但场景切换后,Unity动画状态机的帧逻辑优先级变化,导致Update的重置操作直接覆盖了交互时的状态设置,动画根本来不及播放。
2. 修复方法
方案一:移除强制帧重置,改用状态控制
删掉Update中的animator.SetBool("isOpen", false);,改为按需控制宝箱关闭逻辑。比如添加协程实现打开后自动关闭:
public bool Interact(Interactor interactor) { if (MouseDn) { MouseDn = false; animator.SetBool("isOpen", true); Debug.Log("Opening Chest!"); StartCoroutine(CloseChestAfterDelay(2f)); // 2秒后自动关闭 return true; } return false; } private IEnumerator CloseChestAfterDelay(float delay) { yield return new WaitForSeconds(delay); animator.SetBool("isOpen", false); }
方案二:改用触发器触发动画
将动画控制器中的isOpen布尔参数改为触发器参数(如命名为Open),触发器是一次性触发逻辑,不会被后续的布尔设置覆盖:
public bool Interact(Interactor interactor) { if (MouseDn) { MouseDn = false; animator.SetTrigger("Open"); // 用触发器触发打开动画 Debug.Log("Opening Chest!"); return true; } return false; } // 移除Update中的animator.SetBool("isOpen", false);
3. 场景切换额外校验
确保DontDestroyOnLoad标记的玩家对象不会在场景切换时生成重复实例,避免交互逻辑冲突:
// 在Interactor脚本的Awake方法中添加 private void Awake() { if (FindObjectsOfType<Interactor>().Length > 1) { Destroy(gameObject); } else { DontDestroyOnLoad(gameObject); } }
内容的提问来源于stack exchange,提问作者Bry793
相关产品推荐
相关产品推荐

