如何为按钮上的单击()事件分配一个预制器中的方法?

发布于 2025-02-05 05:42:10 字数 1024 浏览 2 评论 0原文

我有一个按钮,该按钮应该在我的游戏中通过在ObjectTheme脚本内运行“ toggletheme”的光线和暗模式之间切换苦味,这是我想要受光/暗模式影响的所有对象。 toggletheme只是更改布尔的“ darkmode”,因为所有对象的过渡都使用此darkmode boolean。如果我只分配对象并选择objecttheme.toggletheme,那么一切都很好,但是如果我分配对象的预制符,然后选择“ objecttheme.toggletheme”,我会收到警告“动画不是在播放AnimatorController a AnimatorController”按钮。有什么方法可以解决这个问题,因为在每个场景中分配每个对象都将是不切实际的,并且其中一个对象在游戏的每个级别中都有多达30份副本?

PS我知道,如果我只使用了一个切换而不是按钮,那可能会更容易反而。

这是对象系数脚本:

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);
         }
    }
   
}

I have a button that is supposed to switch beetween light and dark mode in my game by running the method "ToggleTheme" inside the ObjectTheme script, which all the objects that I want to be affected by light/dark mode have. ToggleTheme just changes the boolean "DarkMode", since all the objects' transitions use this DarkMode boolean. It all works fine if I just assign the objects and select ObjectTheme.ToggleTheme, but if I assign the objects' prefabs and select ObjectTheme.ToggleTheme I get the warning "Animation is not playing an AnimatorController" on button press. Is there any way around this, because assigning every object in every scene would just be to impractical and one of the objects has up to 30 copies in every level of the game?

P.S. I know It probably would have been easier if I just used a toggle instead of a button, but I'm new to Unity and I just couldn't get the toggle to work how I wanted it, so I'm using a button instead.

Here is the ObjectTheme script:

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);
         }
    }
   
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

淡淡の花香 2025-02-12 05:42:10

**在下面的乔纳坦(Jonatan)评论之后进行了编辑。

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

在这种情况下,我们正在尝试在动画仪组件上设置一个布尔值,但是预制器上的动画师并不是真正的播放 - 只有场景实例上的动画师在播放。这就是为什么您会收到“不玩”警告的原因。

解决问题的一种选择可能是以下内容。

首先将脚本添加到具有可以与您的按钮的OnClick()UnityEvent连接的函数的按钮。该脚本将寻找另一个脚本的实例,该实例存在于所有应对黑模式状态反应的对象上。其他脚本可能是您的对象主题脚本,但在这里我称之为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
{
    static bool isDarkMode;
    public static bool IsDarkMode => isDarkmode;//Public get property

    //Make your Button call this function in its OnClick() event
    public void OnButtonClicked()
    {
        isDarkMode = !isDarkMode;//Toggle bool
        SendIsDarkMode();
    }

    //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.
    public void OnToggleValueChanged(bool isToggledOn)
    {
        isDarkMode = isToggledOn;
        SendIsDarkMode();
    }

    void SendIsDarkMode()
    {
        var darkModeReceivers = FindObjectsOfType<DarkModeReceiver>(true);
        foreach (var receiver in darkModeReceivers)
        {
            receiver.SetIsDarkMode(isDarkMode);
        }
    }
}

然后,接收脚本(附加在所有应该对黑模式状态反应的游戏对象 /预制板上)可能是这样(或您的ObjectTheme脚本的修改版本)。

using UnityEngine;

public class DarkModeReceiver : MonoBehaviour
{
    Animator myAnimator;

    void Awake()
    {
        myAnimator = GetComponent<Animator>();
    }

    void Start()
    {
        //Ensure that our state is in sync with the DarkModeHandler
        SetIsDarkMode(DarkModeHandler.IsDarkMode);
    }

    public void SetIsDarkMode(bool isDarkMode)
    {
        myAnimator.SetBool("DarkMode", isDarkMode);
    }
}

另外,您可以做一些Darkmodereceivers/Objectshemes在启动()上在Darkmodehandler上注册的事情,而在其onDestroy()上再次注册自己 - 例如,通过订阅事件。然后,每次点击按钮时,DarkmodeHandler都不必查找接收器。

**Edited after Jonatan's comments below.

I understand the desire to just assign the prefab as the button's event target. But the prefab itself is in some sense also just an instance that is just not living in the scene. While in edit mode, all changes in the prefab itself will reflect in the scene instances. But when you are in play mode (runtime) the prefab instances in the scene will no longer automatically update themselves with changes in the prefab file.

In this case, we are trying to set a bool value on an Animator component, but the Animator on the prefab is not really playing - only the Animators on the scene instances are playing. That is why you get the 'not playing' warning.

One option to solve the issue could be something like the following.

First add a script to the button that has a function that can be hooked up with your button's OnClick() UnityEvent. The script will look for instances of another script, which is present on all the objects that should react to dark mode state. This other script could be your ObjectTheme script but here I call it DarkModeReceiver. When the button triggers the function, the script will simply call a function on all the script instances stored in its array.

//Put this script on the Button,
//and hook up the Button's OnClick event with the OnButtonClicked() function

using UnityEngine;

public class DarkModeHandler : MonoBehaviour
{
    static bool isDarkMode;
    public static bool IsDarkMode => isDarkmode;//Public get property

    //Make your Button call this function in its OnClick() event
    public void OnButtonClicked()
    {
        isDarkMode = !isDarkMode;//Toggle bool
        SendIsDarkMode();
    }

    //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.
    public void OnToggleValueChanged(bool isToggledOn)
    {
        isDarkMode = isToggledOn;
        SendIsDarkMode();
    }

    void SendIsDarkMode()
    {
        var darkModeReceivers = FindObjectsOfType<DarkModeReceiver>(true);
        foreach (var receiver in darkModeReceivers)
        {
            receiver.SetIsDarkMode(isDarkMode);
        }
    }
}

And then the receiving script (attached on all the game objects / prefabs that should react to dark mode state) could be something like this (or a modified version of your ObjectTheme script).

using UnityEngine;

public class DarkModeReceiver : MonoBehaviour
{
    Animator myAnimator;

    void Awake()
    {
        myAnimator = GetComponent<Animator>();
    }

    void Start()
    {
        //Ensure that our state is in sync with the DarkModeHandler
        SetIsDarkMode(DarkModeHandler.IsDarkMode);
    }

    public void SetIsDarkMode(bool isDarkMode)
    {
        myAnimator.SetBool("DarkMode", isDarkMode);
    }
}

Alternatively, you could do something where the DarkModeReceivers/ObjectThemes register themselves on the DarkModeHandler on their Start() and unregister themselves again on their OnDestroy() - for example by subscribing to an event. Then the DarkModeHandler wouldn't have to look for receivers every time the button is clicked.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文