You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 20:10:29