没想到这么快就要重构了,原来常对说思路不清,这下轮到自己头上了。
问题产生在项目不停在膨胀,在思路不够明晰的情况下,每多写一行代码,可控性就少一分。就如同不停的盖房子,在没有蓝图的情况下,盖一个一两层也是没有问题的,但是随着高度不断攀升,随时都有崩塌的危险。这可能是每一个没有规划好的项目都会碰到的问题,而这个问题越晚爆发越糟糕。现在需要重新梳理思路,把前面的代码重构。
基本的流程
+-------------+ | | | load config | +-------------+ | | +----v-----+ +-----v-----+ | new game | | load game | new runtime data | or level | | or level | load runtime data +----------+ +-----------+ | | +--v---v-----+ +------------+ | play game +----------> ??? | change runtime data | | | 不可预知 | +------------+ +------------+ | +-----v------+ | exit | save runtime data | save | +------------+
左边的部分是一个一般软件的流程,但在游戏中,play是不可预知的,可能停电,可能关机等等,实时保存运行时数据变得必要。这个导致我前面没有考虑到了最大的坑。
这里的实时保存,并不是针对所有的数据,这里根据保存的密集度,我分成三类:
- 创建保存,比如地牢,一旦生成,在新建之前都将保持数据。
- 触发保存,比如道具,一旦拾取,道具当前状态为删除。
- 实时保存,比如英雄,每一步都需要储存,玩家肯定不愿意重走一遍。特别的某些随机的的部分,再来一遍数据就不同了,这也是roguelike的魅力,每一局都是独特的。
吐槽一下面向对象
世界既不是对象构成,也不是函数构成,世界怎么构成取决观察者的看法。所以无论面向对象,还是函数式,我的看法是什么合适用什么。但是对于面向对象有一个非常糟糕的事就是:
- 不易变化
- 容易臃肿
不易变化:比如,游戏中需要加入英雄,那么创建一个hero类,过一会,又需要加入狼,那么创建一个wolf类,过一会,英雄需要变成狼,这下麻烦了,建立一个creatures的父类,hero,wolf都继承,各种行为做成接口,看起来似乎解决了。突然又有一个英雄变成桌子的需求,这下就开始为各种特殊性写丑陋的代码了,需求不确定是设计游戏的常态,但对于面向对象来实现这简直就是噩梦。
容易臃肿:比如,有一个创建地牢的类,负责创建地牢,刚开始对象不多,这里面的功能也比较单一,比较好维护,随着需求不断扩展,类的功能越来越多,然后剩下的就是要们忍受,要么重构。
理想的状态是数据驱动,面向组合:entitas是一个优秀的ecs工具,针对不确定的变化,可以非常有效的解决,比如:游戏中需要加入英雄,我们可以为英雄建立一个实体,为它添加渲染,行为,属性等组件,需要变成狼,更改渲染对象为狼的模型,更改行为方式为狼的行为方式,属性略作调整即可,变成桌子,更改渲染对象为桌子,删除行为组件,属性换成桌子属性即可。系统针对某一个或某一些组件实现行为,特别需要保持功能单一,对于不同的对象就是组件的组合,由组件引发的附带的行为功能组合。即便如此,还是被我用成了面向对象,把一个个的system写的臃肿,现在就整理思路,开始改变.
游戏配置是不是可以放到加载游戏的过程中异步加载?
@views63:因为现在的项目好小,瞬间就加载完了,还没有考虑同步异步的问题。欢迎交流,多跟你学习,初学unity,这是第二个练习,中间太多的不足,现在在加足马力恶补中。
@kuaile:我是做了一年多的游戏UI业务,整体项目方面的还是要多跟你学习。我做过的两个项目数据全部加载完成都需要1分钟以上。感觉在第二个公司的项目用数据异步加载用玩家体验会好很多。不过麻烦的是数据什么时候可能要用到数据的时候它还没加载好,又得做进一步处理
@views63:一起探讨吧,不同的项目处理方式不同。