【构】框架中如何对待MonoBehaviour脚本

最近在重构局内逻辑,发现很多核心类直接继承自MonoBehaviour,挂在prefab上,其导致很多问题。到底是prefab上面挂脚本,还是脚本中包含prefab,其实这个问题,从自己接触unity开始,就一直困扰着自己。做了项目一年多,对这个问题又有了点新的认识,这里随便说说。

1. Unity的编程模式

假设你需要在游戏中生成一个怪物,这个怪物包括以下内容:模型、骨骼、贴图、动作、动作控制器、血条、控制怪物状态的状态机脚本、控制怪物AI的状态机脚本。那么应该如何组织这些内容?
一个很容易想到的方法是,把模型、骨骼、贴图、动画、动画控制器、血条搞成一个prefab;写一个Monster脚本,其继承MonoBehaviour,把它挂在prefab上;写其他状态类和AI类,Monster持有并更新这些类,同时操作prefab中的动作控制器播放相应动作;如果Monster的HP属性发生变化,则将血条的宽度变窄或者变色,显示怪物血量变化。
如下图所示。
这里写图片描述
我猜想,基本上所有Unity初学者,或者代码初学者,在看完Unity的一些教程后,都会选择这种方法。
先看下这种方法有什么好处:
1. 所见即所得,做好这样一个prefab,直接拖到场景中,运行场景,就能看到怪物行为。(这个对于初学者太赞了)
2. 方便使用Mono的所有方法,如Update,Awake等等。不需要额外提供游戏运行框架。(也很赞)
3. 方便直接控制prefab属性,如transform.position,transform.rotation等等。
4. 方便使用GetComponent获得prefab上挂的各种组件,直接对组件进行操作。
5. 方便调试。哪个怪有问题,把哪个怪拖出来跟一下就行了。
6. 方便序列化。直接让Monster脚本暴露属性,修改属性保存prefab直接保存了该数据。
不可否认,对于小型游戏或者demo期的游戏,这种组件脚本式的编程方法,确实速度很快。但是当游戏规模变大,这种编程方法的弊端就暴露了出来。
挂Mono脚本的弊端:
1. 无法灵活控制资源生存周期。比如,我希望在进入局内的Loading时,缓存怪物的prefab,但是直到玩家行进到某个地点时才刷出怪物。
2. 继承自Mono的类,都无法使用new创建,只能使用创建的GameObject通过GetComponent<>()方法获得脚本。然而有些时候,我们只要逻辑,不需要模型、动作等等。
3. Mono是类,不是接口,所以根据c#的单继承规则,所有继承Mono的类都无法再继承其他基类。想实现其他方法,只能使用接口,而接口比基类,在易用性上往往差一些。
4. 使用Mono,就会自然而然的使用其提供的更新框架,Awake,Start,Update,FixedUpdate等等。而这些更新顺序对于Unity底层之外是透明的,换句话说,你无法确定两个Mono的Update执行顺序。另外,你也很难控制不同模块或者不同对象的更新速率。
5. 序列化难以管理。如果一个相同资源的怪,想要50级,每个级别的攻防血都不一致,那么,按照这样的方式,就要搞出来50个prefab!!!每个prefab暴露出来的属性填上相应的字段!!!OMG
6. 工种不分开。想一想,美术做个资源,还要关心程序挂的脚本,队伍大了,就呵呵了。

2. 一个好的模式

一个好的模式(正确的方法论)应该是:

资源是资源,逻辑是逻辑,资源应该和逻辑分开。

严格执行这种编程方式,能在规模变大后还能良好控制整个游戏。
这里面有几个问题:
1. 如何所见即所得。不挂脚本就意味着没法所见即所得,这个确实是最大的损失,写编辑器吧,如场景编辑器,技能编辑器等等。使用编辑器而不是直接拖拽有一个更好的结果:限制了工种对相同资源的操作,易于管理。
2. 如何更新。全局只用一个单例GameGlobal之类的继承Mono,所有的Update更新,都从这里发出。例如Monster想更新,就需要通过GameGlobal的Update,传递到MonsterManager的Update,再传到Monster的Update,想暂停某个模块或某个实例,只要对相应Manager进行处理即可。同时,管理起来之后,各个实例的创建和销毁也更加明确。
3. Mono脚本完全弃用?答案当然是否定的。在不考虑资源生存周期的情况下,用Mono会非常方便。比如,给一个Plane加上脚本,让其一直对着摄像机,变成一个Billboard,就比写一个Billboard,再初始化加载资源更加方便,因为这时候逻辑资源分离,就一定需要配置文件指定到相应的资源。显而易见,该资源只要出生,就需要对着摄像机,无需额外控制。

3. 方法论

这个问题其实牵扯到一个更深入的方法论问题(道)。

* 任何变化的,都需要考虑抽离出来 *

上面变化的是资源。而挂上脚本的prefab,一定是资源和逻辑都不变的。
这跟设计模式的抽象原则是一致的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值