2020-01-03【coding】代码架构思考
架构,首先是需要有架构,然后遵守这个架构的规定(当然也需要有规定),才可以称为架构。
有时候不遵守规定的一个变量,就可以影响整体结构。
架构的目的是为了使逻辑更加清晰,减少错误率,使多人协作及代码修改更方便。
看了几个比较大的unity项目,一个一个分析吧;
- MarsFPSKit
需要注意的地方:创建出的scriptableobject资源,在运行后,就是一个实例了,因此如果许多人都引用了这个资源文件,大家就会共同操作这个对象。因此,这玩意可以当作单例来用;但是假如想每个对象都有自己的相关scriptableobject资源文件,就需要使用instiate方法动态复制数据。(instiate相当于一次数据的深拷贝)。
这个感觉是代码最容易读懂的~所以我觉得它的结构最好。
它是基于Photon2作为网络基础的一套CS对战框架。
它充分利用了Unity的ScriptableObject,作为配置文件,使很多东西都可以进行动态配置(或者说,他基本上把所有东西都弄成了可配置的);
然后基于这个可配置的基础上,把很多逻辑分离出来,专门用作配置;
比如,简单点的配置:地图配置;人物模型分组配置;网络房间等限制配置;
复杂点的,武器配置,游戏模式配置。
方式大致都是,首先要有一个抽象类(继承自ScriptableObject),里面写了一些abstract方法,然后,主流程调用这些abstract方法,就会自动调用到子类中去,实现不同的执行产生不同的结果。
这样做的结果,就是,在划分抽象类的时候,已经自动把模块分离出来了;比如说,输入抽象类,武器抽象类,移动抽象类,3D动画播放抽象类,等等。
然后,所有这些模块的拥有者Kit_PlayerBehaviour持有这些模块的实例,以及以object形式存储的数据。传参的时候把这个拥有者传出去,各个模块就能获取到所有想获得的信息。
但是也会存在一些问题:
1.预制体在生成实例后,实例上的物体如何获取,如模型上的mesh网格,碰撞体,特效挂载点,等。
这些是不可以直接拖到配置文件里的,它的做法是,再写相关的脚本,挂在想挂的物体上,然后动态的搜索赋值。
我的做法是,这部分内容就不要用ScriptableObject了,直接继承Mono挂在物体上,然后就能直接拖进去了。
2.各个模块之间的耦合性,相关性,怎样处理。
这些关系,从它的抽象类中就能看出端倪了,下面举几个例子:
image.png
image.png
获得信息的方式,不是直接访问数据,必须是通过特定的方法。这样能保证安全性。调用模块的方法,也要尽量确定模块的简单性,即保证调用该方法尽量是直接的最终效果,而不会带动其他模块。
联网部分,也有很多种做法,先查看进行归纳总结:
1.Movement
它的Movement同步,主要是直接同步了位置及旋转。所以这里的Update就没有单独写。
在播放声音的时候,直接调用All,这样自己和别人都会调用。播放动画也是。
image.png
此部分为实时同步数据。
实时同步数据用来直接给动画播放模块自动判断设置动画播放状态。
2.ThirdPersonController
image.png
image.png
联网部分基本上就分两部分来写,自己调用及同步者调用,调用都是殊途同归,最终调用同一个播放声音,播放特效,播放动画。这些调用看了一下基本都是RPC调用的,而帧同步调用的,比如上面这个移动,是变化频率比较大的。OK先就这样吧。
- 3DGameKit
各种小插件的合辑,简单直接。是一个Kit工具包。
- ThirdPersonController
使用自己的一整套东西,十分复杂。从自定义序列化,到自定义编辑器扩展,环环相扣,到现在我还是没搞清楚,怎样才能把他这么NB的功能拆分出来为我所用。
而直接使用,量级太大,而且还是有一些东西不符合定制化的项目。
后面重点研究这个东西。