【问题标题】:Component driven design architecture - communication between components组件驱动的设计架构——组件之间的通信
【发布时间】:2018-09-14 11:32:47
【问题描述】:

我正在使用 Unity3D 构建游戏,但我有一个关于如何构建我的 Actor 架构的问题(我的 Actor 是指可以以某种方式与其他对象交互的对象)。

所以,我遵循了组件驱动的设计,每个组件负责处理对象的不同方面(例如动画组件、移动组件、攻击者组件等),但我在决定组件应如何通信时遇到了麻烦彼此。我的想法是:

  1. 每个对象都有一个组件管理器,它保存对附加在对象上的每个组件的引用。组件之间通过组件管理器的引用进行通信。

  2. 每个组件都负责保存自己的引用并在内部处理通信。我能想到的缺点是多个组件将持有相同的引用。

  3. 使用自动消息传递系统处理通信。(事件和侦听器)

我的问题是:有没有更好的方法来处理组件通信? 每种方式的优缺点是什么?

p.s 我不是在询问 Unity 或特定语言的答案,只是对正确方向的微小推动。提前致谢!

【问题讨论】:

    标签: unity3d architecture components


    【解决方案1】:

    每个对象都有一个组件管理器,它保存对附加在对象上的每个组件的引用。

    如果组件继承自 MonoBehaviour,这已经成为可能。有 GetComponent() 从 GameObject 获取组件,这适用于脚本和组件。

    您是否有任何特殊原因希望制作自己的管理系统而不是使用解耦的内置系统?

    来源:https://docs.unity3d.com/ScriptReference/GameObject.GetComponent.html

    【讨论】:

    • 其实没有。我想我只是想多了,因为这是我第一次使用这种设计架构。非常感谢您的回答!
    • 乐于助人,不用担心,理解会及时到来的。由于您是新来的,请允许我向您表示欢迎来到 Stackoverflow。请注意,如果您愿意,可以在帮助中心阅读有关 Stackoverflow 工作原理的更多信息:stackoverflow.com/help
    • @ΕρωτόκριτοςΒαλλιανάτος,如果您是 Unity 新手,此链接可能对您有用,它概述了 Unity 的生命周期方法,例如开始和更新,它们将在游戏引擎中被调用。 docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg
    【解决方案2】:

    每个对象都有一个组件管理器来保存对每个对象的引用 附着在物体上的组件。组件相互通信 其他通过组件管理器的引用。

    使用自动消息传递系统处理通信。(事件 和听众)

    我会说在这两者之间进行混合。为每个对象配备一个组件管理器会很有帮助,尤其是在将来添加新组件时。只需在管理器中为这个新的参考字段创建一个参考字段,您就完成了。管理器也可以充当外部实体和管理器组件之间的入口点。

    相反,让对象拥有自己对其他组件的引用肯定是不好的,因为当新组件出现时,您必须为所有组件分配引用。另外,这可能不会使组件彼此独立工作,因为他们将不得不在某个时间点访问彼此的函数、属性或变量。

    使用事件在同一对象的组件之间进行通信可能不是一个好主意。在某些情况下,您可能想要调用一个函数并使用它的返回值来确定是否继续。例如,假设玩家有机会阻止传入的攻击,并且只有在攻击成功时才应该更新玩家 UI。你可以做类似的事情

    void OnPlayerDamagedCommon() {
        bool damaged = PlayerDefense.OnPlayerDamaged();
        PlayerUI.OnPlayerDamaged(damaged);
    }
    

    但是,在不同对象之间进行通信时,事件将非常有用。例如玩家可以在攻击发生时触发OnAttack事件,所有订阅该事件的敌人都可以做出相应的反应。此外,任何类型的实体都可以订阅事件。成为敌人、NPC 或环境物体。这将使行为逻辑更容易本地化。

    您还可以使用接口将一个对象添加到另一个对象的处理列表中。

    class Enemy : IShootable {
        void Enemy() { 
            playerManager.AddToShootable(this); 
            public void OnShoot() {...}    
        }
    }
    
    class PlayerAttack {
        void OnShoot () {
            foreach(IShootable s in _shootableList) {
                if(CheckRaycast(s)) 
                { 
                    s.OnShoot() 
                }
            }
        }
    }
    

    这有助于本地化代码以确定敌人是否被击中到一个地方,而不是每个敌人都有自己的光线投射检查代码,如果您使用事件时就会出现这种情况

    【讨论】:

    • 非常感谢您的回复,真的很有帮助!
    • 乐于助人。 :)
    猜你喜欢
    • 1970-01-01
    • 2014-12-21
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 2016-06-09
    • 2015-09-18
    • 2016-05-01
    • 2017-09-04
    相关资源
    最近更新 更多