万镜之下 2026-01-10 20:23 采纳率: 16.7%
浏览 1
已采纳

unity的设计模式的理解,不太懂

看到了论文的第二条:原则(2): 不要在节点或预制体上直接挂与逻辑相关的代码组件。

这个很好理解,如果我们直接在节点or预制体上挂代码组件,代码极难维护,如果我们要搜索哪些代码在哪些地方调用,根本就无法通过搜索查到,如果一个一个节点,一个一个预制体的点开找,这样维护起来非常麻烦, 也不方便资源更新与代码热更。关于这个(如果不挂在脚本,该怎样控制对象呢希望详细的解释下)感谢您

  • 写回答

2条回答 默认 最新

  • 檀越@新空间 2026-01-10 20:24
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    你提出的问题非常关键,是Unity开发中一个非常重要且容易被忽视的设计原则。我们来详细解释一下:


    一、为什么不能在节点或预制体上直接挂与逻辑相关的代码组件?

    原因如下:

    1. 可维护性差
      如果你把所有逻辑都写在GameObject的脚本上,当需要修改逻辑时,你需要逐一打开每个节点去查看脚本,这会极大降低开发效率。

    2. 难以复用
      每个节点上的脚本都是独立的,无法统一管理,导致重复代码和功能分散。

    3. 不利于热更新
      如果你要做资源热更(如换皮肤、换角色等),如果逻辑和对象绑定太紧,就很难实现灵活替换。

    4. 不利于团队协作
      多人开发时,容易出现脚本冲突或命名混乱,造成开发混乱。


    二、那如果不挂在脚本,该怎么控制对象呢?

    我们可以采用“分离逻辑与对象”的方式,即通过控制器管理器来控制对象的行为。以下是几种常见方式:


    ✅ 方式一:使用Controller/Manager模式

    核心思想:
    将控制逻辑集中在一个或多个控制器中,通过引用或事件机制来操作对象。

    示例结构:

    - GameObject: Player
    - Script: PlayerController (不挂载到Player上)
    - Script: PlayerModel (数据模型,不挂载)
    - Script: UIManager (UI管理器)
    

    优点:

    • 所有逻辑集中在控制器中,便于维护。
    • 对象本身只负责渲染和基础属性。
    • 支持热更新和模块化开发。

    ✅ 方式二:通过事件系统(Event System)通信

    核心思想:
    使用Unity的UnityEvent或者自定义事件系统,让对象之间通过事件进行通信,而不是直接调用方法。

    示例代码(简化版):

    // 定义一个事件监听器
    public class PlayerController : MonoBehaviour
    {
        public void OnPlayerHit()
        {
            Debug.Log("玩家被击中!");
        }
    }
    
    // 在另一个对象中触发事件
    public class Enemy : MonoBehaviour
    {
        public void AttackPlayer()
        {
            // 触发事件
            EventSystem.Instance.OnPlayerHit();
        }
    }
    

    ✅ 方式三:使用依赖注入(DI)

    核心思想:
    通过构造函数或方法传入所需的对象,而不是在对象上挂脚本。

    示例代码:

    public class PlayerController : MonoBehaviour
    {
        private PlayerModel _playerModel;
    
        public void Initialize(PlayerModel model)
        {
            _playerModel = model;
        }
    
        public void Move()
        {
            _playerModel.Move();
        }
    }
    

    ✅ 方式四:使用单例模式(Singleton)

    核心思想:
    创建一个全局唯一的管理类,用来控制对象行为。

    示例代码:

    public class GameManager : MonoBehaviour
    {
        public static GameManager Instance { get; private set; }
    
        private void Awake()
        {
            if (Instance == null)
                Instance = this;
            else
                Destroy(gameObject);
        }
    
        public void SpawnPlayer()
        {
            Instantiate(playerPrefab);
        }
    }
    

    三、总结:如何正确控制对象?

    重点在于:不要把逻辑写在GameObject上,而是通过控制器、管理器、事件系统等方式进行控制。


    四、具体解决方案步骤(有序列表)

    1. 避免在GameObject上直接挂逻辑脚本

      • 不要将游戏逻辑写在GameObject的脚本中。
    2. 使用Controller/Manager类集中管理逻辑

      • 创建专门的控制器类,例如 PlayerController, EnemyManager 等。
    3. 通过引用或事件系统进行通信

      • 使用 public 变量、UnityEvent 或自定义事件系统进行对象间通信。
    4. 使用依赖注入(DI)方式传递数据

      • 通过构造函数或方法传入所需的数据模型或对象。
    5. 使用单例模式管理全局状态

      • 用于管理游戏状态、资源加载、UI显示等全局功能。
    6. 使用设计模式提升可维护性

      • 如MVC(Model-View-Controller)、Observer、State等。

    五、示例:不直接挂脚本的完整项目结构

    Assets/
    ├── Scripts/
    │   ├── Models/
    │   │   └── PlayerModel.cs
    │   ├── Controllers/
    │   │   └── PlayerController.cs
    │   ├── Managers/
    │   │   └── GameManager.cs
    │   ├── Events/
    │   │   └── EventSystem.cs
    │   └── UI/
    │       └── UIManager.cs
    ├── Prefabs/
    │   └── Player.prefab
    └── Scenes/
        └── MainScene.unity
    

    六、修改后的代码示例(非直接挂脚本)

    ❌ 原始错误写法(不推荐):

    // 玩家脚本直接挂在Player prefab上
    public class PlayerScript : MonoBehaviour
    {
        public void Attack()
        {
            Debug.Log("玩家攻击!");
        }
    }
    

    ✅ 修改后正确写法:

    // PlayerController 不挂在Player prefab上
    public class PlayerController : MonoBehaviour
    {
        public PlayerModel playerModel;
    
        public void Attack()
        {
            playerModel.Attack();
        }
    }
    
    // PlayerModel 是数据模型,不挂载
    public class PlayerModel
    {
        public void Attack()
        {
            Debug.Log("玩家攻击!");
        }
    }
    

    七、结语

    记住:Unity不是用来写“游戏逻辑”的,而是用来“组织和控制游戏对象”的。

    通过合理的设计模式和架构,可以大幅提升项目的可维护性和扩展性。希望这些内容能帮助你更好地理解Unity中的设计模式与逻辑控制方式。如果你还有疑问,欢迎继续提问!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 已采纳回答 1月10日
  • 创建了问题 1月10日