看到了论文的第二条:原则(2): 不要在节点或预制体上直接挂与逻辑相关的代码组件。
这个很好理解,如果我们直接在节点or预制体上挂代码组件,代码极难维护,如果我们要搜索哪些代码在哪些地方调用,根本就无法通过搜索查到,如果一个一个节点,一个一个预制体的点开找,这样维护起来非常麻烦, 也不方便资源更新与代码热更。关于这个(如果不挂在脚本,该怎样控制对象呢希望详细的解释下)感谢您
看到了论文的第二条:原则(2): 不要在节点或预制体上直接挂与逻辑相关的代码组件。
这个很好理解,如果我们直接在节点or预制体上挂代码组件,代码极难维护,如果我们要搜索哪些代码在哪些地方调用,根本就无法通过搜索查到,如果一个一个节点,一个一个预制体的点开找,这样维护起来非常麻烦, 也不方便资源更新与代码热更。关于这个(如果不挂在脚本,该怎样控制对象呢希望详细的解释下)感谢您
晚上好🌙🌙🌙
本答案参考通义千问
你提出的问题非常关键,是Unity开发中一个非常重要且容易被忽视的设计原则。我们来详细解释一下:
原因如下:
可维护性差
如果你把所有逻辑都写在GameObject的脚本上,当需要修改逻辑时,你需要逐一打开每个节点去查看脚本,这会极大降低开发效率。
难以复用
每个节点上的脚本都是独立的,无法统一管理,导致重复代码和功能分散。
不利于热更新
如果你要做资源热更(如换皮肤、换角色等),如果逻辑和对象绑定太紧,就很难实现灵活替换。
不利于团队协作
多人开发时,容易出现脚本冲突或命名混乱,造成开发混乱。
我们可以采用“分离逻辑与对象”的方式,即通过控制器或管理器来控制对象的行为。以下是几种常见方式:
核心思想:
将控制逻辑集中在一个或多个控制器中,通过引用或事件机制来操作对象。
- GameObject: Player
- Script: PlayerController (不挂载到Player上)
- Script: PlayerModel (数据模型,不挂载)
- Script: UIManager (UI管理器)
核心思想:
使用Unity的UnityEvent或者自定义事件系统,让对象之间通过事件进行通信,而不是直接调用方法。
// 定义一个事件监听器
public class PlayerController : MonoBehaviour
{
public void OnPlayerHit()
{
Debug.Log("玩家被击中!");
}
}
// 在另一个对象中触发事件
public class Enemy : MonoBehaviour
{
public void AttackPlayer()
{
// 触发事件
EventSystem.Instance.OnPlayerHit();
}
}
核心思想:
通过构造函数或方法传入所需的对象,而不是在对象上挂脚本。
public class PlayerController : MonoBehaviour
{
private PlayerModel _playerModel;
public void Initialize(PlayerModel model)
{
_playerModel = model;
}
public void Move()
{
_playerModel.Move();
}
}
核心思想:
创建一个全局唯一的管理类,用来控制对象行为。
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上,而是通过控制器、管理器、事件系统等方式进行控制。
避免在GameObject上直接挂逻辑脚本
使用Controller/Manager类集中管理逻辑
PlayerController, EnemyManager 等。通过引用或事件系统进行通信
public 变量、UnityEvent 或自定义事件系统进行对象间通信。使用依赖注入(DI)方式传递数据
使用单例模式管理全局状态
使用设计模式提升可维护性
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中的设计模式与逻辑控制方式。如果你还有疑问,欢迎继续提问!