英文:
Only one instance has non-null event action in unity. why?
问题
我有这个脚本分别放在UI的三个按钮上。
我需要确保在按下按钮时只有一个面板是打开的。
我使用另一个脚本来接收OnClickedPanel事件,并在Start()中订阅该事件。
在调试代码时,除了一个实例外,所有实例的OnClickedPanel都为null。
public class PanelControl : MonoBehaviour
{
    [SerializeField] GameObject panel;
    public static PanelControl panelControl;
    public event Action<string> OnClickedPanel;
    private void OnEnable()
    {
        panelControl = this;
        MenuControl.menuControl.OnMakeRoom += MakeRoom;
    }
    
    // Update is called once per frame
    public void TogglePanel()
    {
        panel.SetActive(!panel.active);
        Debug.Log(OnClickedPanel);
        OnClickedPanel?.Invoke(this.name);
    }
    private void MakeRoom(string _openPanel)
    {
        if (_openPanel != this.name)
        {
            Debug.Log("opening" + _openPanel);
            panel.SetActive(false);
        }
    }
    private void OnDestroy()
    {
        MenuControl.menuControl.OnMakeRoom -= MakeRoom;
    }
}
我弄错了什么?
英文:
I have this script in 3 different buttons in the UI.
I need to make sure that just one panel is open when pressing a button.
I use another script to receive the OnClickedPanel event and it subscribe to the event in Start().
When debugging the code all of the instances except one have OnClickedPanel = null.
public class PanelControl : MonoBehaviour
{
    [SerializeField] GameObject panel;
    public static PanelControl panelControl;
    public event Action<string> OnClickedPanel;
    private void OnEnable()
    {
        panelControl = this;
        MenuControl.menuControl.OnMakeRoom += MakeRoom;
    }
    
    // Update is called once per frame
    public void TogglePanel()
    {
        panel.SetActive(!panel.active);
        Debug.Log(OnClickedPanel);
        OnClickedPanel?.Invoke(this.name);
    }
    private void MakeRoom(string _openPanel)
    {
        if (_openPanel != this.name)
        {
            Debug.Log("opening" + _openPanel);
            panel.SetActive(false);
        }
    }
    private void OnDestroy()
    {
        MenuControl.menuControl.OnMakeRoom -= MakeRoom;
    }
}
What am I messing up?
答案1
得分: 2
在OnEnable中,你执行了以下代码:
panelControl = this;
这里的panelControl是static的,而且显然是要实现单例模式... 但是你自己说有3个实例!因此它们会互相覆盖,最终只有最后一个实例会成为panelControl。
我只能猜测,但你的其他脚本可能通过这个本应该是单例的方式来订阅事件:
PanelControl.panelControl.OnClickedPanel += ...;
现在我希望你明白为什么你应该立刻停止在你的用例中使用单例模式,而是引入适当的引用管理!
英文:
Well in OnEnable you do
panelControl = this;
which is static and apparently is supposed to be a singleton pattern ... but you say yourself have 3 instances of it!
So they overwrite each other and you end up with only the very last one to be the panelControl instance.
I can just guess but your other scripts probably subscribe via the supposed to be singleton
PanelControl.panelControl.OnClickedPanel += ...;
Now I hope you see why you should immediately stop using singletons at all for your use case and rather introduce a proper reference management!
答案2
得分: 0
我怀疑你想要的是在所有按钮实例上触发一个单一事件,而不是每个按钮实例都有一个唯一的事件。使用代码来描述这一点,我建议将事件设置为static,如下所示:
public static event Action<string> OnClickedPanel;
然后,您可以使用类类型订阅事件,而不是实例:
PanelControl.OnClickedPanel += ...
这样做后,您可以移除“instance”变量panelControl以及所有对它的引用,因为我怀疑它的唯一目的是尝试访问事件。
英文:
I suspect what you want is a single event being triggered across all your button instances, instead of a unique event for each button instance. Using code to describe the point, I suggest making your event static like so:
public static event Action<string> OnClickedPanel;
And then you’d subscribe to the event using the class type, not an instance:
PanelControl.OnClickedPanel += ...
Once you do that, you can remove the “instance” variable panelControl and all references to it, as I suspect it’s sole purpose was to try and access the events.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论