【问题标题】:How do I assign a method that is inside a prefab to the On Click() event on a button?如何将预制件内的方法分配给按钮上的 On Click() 事件?
【发布时间】:2022-06-10 18:46:17
【问题描述】:

我有一个按钮,应该通过运行 ObjectTheme 脚本中的“ToggleTheme”方法在我的游戏中切换明暗模式,我希望受明暗模式影响的所有对象都具有该按钮。 ToggleTheme 只是更改布尔值“DarkMode”,因为所有对象的转换都使用此 DarkMode 布尔值。如果我只是分配对象并选择 ObjectTheme.ToggleTheme,这一切都很好,但是如果我分配对象的预制件并选择 ObjectTheme.ToggleTheme,我会在按钮按下时收到警告“动画没有播放 AnimatorController”。有没有办法解决这个问题,因为在每个场景中分配每个对象是不切实际的,并且其中一个对象在游戏的每个关卡中都有多达 30 个副本?

附:我知道如果我只使用切换而不是按钮可能会更容易,但我是 Unity 的新手,我无法让切换按我想要的方式工作,所以我改用按钮.

这是 ObjectTheme 脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectTheme : MonoBehaviour
{
    public Animator animator;

    // Start is called before the first frame update
    void Start()
    {
        animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    public void ToggleTheme()
    {
         if(animator.GetBool("DarkMode") == true)
         {
            animator.SetBool("DarkMode", false);
         }
        else
         {
            animator.SetBool("DarkMode", true);
         }
    }
   
}

【问题讨论】:

    标签: c# button onclick animator prefab


    【解决方案1】:

    我理解将预制件分配为按钮的事件目标的愿望。但预制件本身在某种意义上也只是一个不存在于场景中的实例。在编辑模式下,预制件本身的所有更改都将反映在场景实例中。但是当您处于播放模式(运行时)时,场景中的预制实例将不再根据预制文件中的更改自动更新自己。

    在这种情况下,我们试图在 Animator 组件上设置一个 bool 值,但预制件上的 Animator 并没有真正播放 - 只有场景实例上的 Animator 正在播放。这就是您收到“未播放”警告的原因。

    解决问题的一个选项可能类似于以下内容。

    首先向按钮添加一个脚本,该脚本具有可以与按钮的 OnClick() UnityEvent 挂钩的功能。该脚本将在 Start() 上查找另一个脚本的实例(该脚本存在于所有应该对暗模式状态作出反应的对象上)脚本并将它们存储在一个数组中。这个其他脚本可能是您的 ObjectTheme 脚本,但在这里我称之为 DarkModeReceiver。当按钮触发函数时,脚本将简单地在其数组中存储的所有脚本实例上调用一个函数。

    //Put this script on the Button,
    //and hook up the Button's OnClick event with the OnButtonClicked() function
    
    using UnityEngine;
    
    public class DarkModeHandler : MonoBehaviour
    {
    
        DarkModeReceiver[] darkmodeReceivers;
    
        bool isDarkMode;
    
        void Start()
        {
            darkmodeReceivers = FindObjectsOfType<DarkModeReceiver>(true);
        }
    
    
        //Make your Button call this function in its OnClick() event
        public void OnButtonClicked()
        {
            isDarkMode = !isDarkMode;//Toggle bool
            foreach (var receiver in darkmodeReceivers)
            {
                receiver.SetIsDarkMode(isDarkMode);
            }
        }
    
        //Alternatively, if you choose to use a Toggle instead
        //you could hook this function up with the Toggle's OnValueChanged(Boolean) event
        //with the dynamic bool of that event.
        //In that case, the isDarkMode variable is not necessary.
        public void OnToggleValueChanged(bool isToggledOn)
        {
            foreach (var receiver in darkmodeReceivers)
            {
                receiver.SetIsDarkMode(isToggledOn);
            }
        }
    }
    

    然后接收脚本(附加在所有应该响应的游戏对象/预制件上)可能是这样的(或您的 ObjectTheme 脚本的修改版本),使用 UnityEvents 使其灵活:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Events;
    
    public class DarkModeReceiver : MonoBehaviour
    {
        [SerializeField]
        UnityEvent darkModeOnEvent;
    
        [SerializeField]
        UnityEvent darkModeOffEvent;
    
        public void SetIsDarkMode(bool isDarkMode)
        {
            if (isDarkMode)
            {
                darkModeOnEvent.Invoke();
            }
            else
            {
                darkModeOffEvent.Invoke();
            }
        }
    }
    

    但是,如果您要动态实例化和销毁应该对暗模式设置做出反应的对象,那么最好让这些对象自己在 Start() 和 OnDestroy() 上的按钮脚本上注册/注销自己。

    【讨论】:

    • 感谢您的回答。很高兴实际上有一个解决方案。因此,如果我正确理解了您的答案,则其中的第一个脚本应该在按钮上,第二个脚本应该在我希望暗模式影响的对象上。但我仍然有一些问题: 1.我是否需要摆脱原来的 ObjectTheme 脚本,或者这是否可以与我已经拥有的脚本一起使用? 2.我在按钮内的 OnClick() 字段中究竟放了什么,对象内的每个 darkModeOff/On 事件中应该受暗模式影响的内容是什么?
    • 是的,我理解其中的困惑——我可能没有 100% 清楚我的意思。我认为您已经在按钮上有一个自定义脚本,其中一个函数从按钮的 OnClick() 调用。所以我的建议是你制作这样一个脚本并将其添加到按钮游戏对象中。然后按钮的 OnClick() UnityEvent 可以设置为调用该脚本上的切换函数 - 在我的回答中,第一个代码示例将属于按钮上的该脚本,并且 ToggleTheme() 函数将与 OnClick( )。我会更新我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-29
    • 2014-03-29
    • 1970-01-01
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多