捕鱼开发日志

最近在用Laya3d做捕鱼,版本是2.x,语言为ts, unity版本为5.6.x最新,底层架构准备使用puremvc singleton版本,js quardtree,然后再自己写个2d碰撞引擎,还有其它边脚料的东西,暂时不述

----2019-08-30 10:40:29-----

-------------------------------------

有些感慨,因为要离职了,三个月的早十晚十,没想到换来的是这种结果,呼呼。

经过三个月的奋斗,捕鱼游戏己经全部完成,大部分BUG也都己修复,乘着离职前的空闲,继续写完这篇博文吧。

关于库:

quardtree并没有用上,因为碰撞引擎的效率还是蛮高的,4个玩家40发子射撞击100条以内的鱼,稳定60帧。

关于设计:

游戏在整体上分了三层,分别为网络层、数据逻辑层、表现层,数据逻辑层由Service和DB两个模块组成,表现层则使用了puremvc框架来实现,随便给张手稿意思下:

网络层:实现心跳,断线重连,服务器重定向,协议封包解包,消息广播等功能

数据层:持有所有游戏逻辑数据,包括由服务端同步过来的玩家数据,鱼数据,子弹数据,技能状态,小游戏状态,服务端时间及网络延时,由表现层传过来的子弹与鱼的碰撞盒信息,以及客户端设置等等。

逻辑层:由3个Service来实现对所有游戏业务的支持,其中:

1. MainService支持用户的登陆登出,大厅的房间选择,游戏的进入和退出等功能。

2. PhysicsService实现游戏中子弹及技能与鱼的碰撞计算,以及鱼的路径与子弹的轨迹计算,同时基于需求,它还负责驱动表现层中的渔场及所有3D模型的镜像翻转和最终位置计算

3. FisheryService专门负责同步服务端与客户端表现层中的渔场状态和玩家操作,包括同步玩家、炮台和子弹信息,同步鱼的路线与状态,同步技能与小游戏状态,上行碰撞信息,处理击杀业务和抽奖业务等等。

表现层:这一层中所实现的功能则与玩家所看到的密切相关,基本的数据模型包括:房间数据,玩家集,子弹集,鱼集,碰撞映射集,小游戏状态等等,组件则包括金币及获得播报,鱼模型及特殊鱼播报,奖励播报,击杀播报及特效,各种技能模型和各种小游戏播报和场景或组件,就不一一叙述了。

在这个架构中,表现层与逻辑层是完全分离的,两层之间的交互完全通过Command与Message来实现,表现层只派发Command,逻辑层只派发Message,故Command只处理View和Model中的数据,Message只处理DB中的数据,若表现层需要向底层或网络写入数据,则应当由Command派发Message消息来间接更新,反之逻辑层也只能以在Message中派发Command的方式来与表现层进行间接交互。

关于实现:

似乎并没有太多可以说的点。就说下碰撞解决方案,渔场镜像的设计和鱼的穿插问题吧。

1. 碰撞解决方案:给鱼加AB盒,A为球体且仅为一个,B为球体或长方体且可能有多个,子弹为2D对象,碰撞的实现为每帧都将鱼的A盒转化成2D圆型,然后与子弹进行碰撞,或未相撞,则跳过,若相撞,则计算所有B盒的2D数据,然后逐一与子弹进行精确碰撞计算。

2. 镜像设计,这个来源于一个在3-4号玩家眼中,要求看自己和12号一样是处于渔场下方,而12号玩家则处于自己对面的需求

前置条件:鱼处于XZ平面

解决思路:当PhysicsService计算完鱼的路线之后,通知表现层计算镜像信息,计算方式为,若玩家为3-4号,则所有鱼的Z取反,角度在6点为0度的前提下根据Z轴取负,鱼的镜像位置确立;由于鱼又有上中下三层的分层,故摄像机的位置,也要绕Z轴进行旋转,否则的话,比如下图中的点A的镜像位置,会与非镜像位置有偏差,散游的鱼身上可能体现不明显,鱼阵出现时可就能明显看出鱼阵整体上移了。

3. 鱼的穿插问题,由于渔场在设计中为一个长16米,宽7.2米,高3.6米的长方体,策划在编辑鱼线路的时候,大鱼在上层,中鱼在中层,小鱼在下层,由于不同分层中的鱼都相互处于同一高度,故游泳时会出现穿插的情况

如上图中,左边长方体为渔场的范围,大鱼123穿模,解决思路将鱼在视锥上以不同的深度进行排列,间距与鱼的A盒直径有关。

那些踩过的坑:

Laya2.0的坑:

1. 这可能也不能算是Laya的坑,但它这样设计,总觉得有点让人郁闷,Laya2.0中的所有prefab和scene,包括龙骨,3D模型,似乎在引擎中都是以模版的型式存在,当你调用对象的destroy,实际上销毁的只是克降的对象,而非模版数据,这样带来的一个问题就是,如果你使用的骨骼动画,或场景中的资源占的内存比较大,或你游戏素材展开后所占的内存比较大时,安卓还好,苹果直接闪退了,哪个你勾选了场景的autoDestroyAtClosed也是没用的,autoDestroyAtClosed,其实调的destroy接口,也只是对象的接口,引擎并没有提供释放模版数据的接口,这不得不让我觉得这是一个坑,因为我得自己写资源管理器啊。

可能有人说laya提供了gc和lock功能,我只想说,这两个接口弱爆了,因为你没法为不想gc的数据做计数统计,当我两个预置用了同一张资源时,想在游戏中做动态加载和释放,光凭这两个接口是不可能的,好吧,只能自己实现一个Resource管理器了,在这里贴一下接口吧

    /**
     * 资源管理器
     */
    namespace Resource {

        /**
         * 根据url创建对象
         * @method: 创建失败时res为null,仅支持Skeleton和Texture的创建
         * @flag: 目前仅用于代替aniMode的值
         * 说明:
         * 1. 调用此接口创建对象时,会产生一个计数,当计数为0时,资源会被彻底释放
         * 2. 见destroy方法
         */
        function create(url: string, method?: (res: any, url: string) => void, caller?: Object, flag?: number): any;

        /**
         * 销毁对象
         * 说明:
         * 1. 见create方法
         * 2. 调用此接口销毁对象时,会移除一个计数,当计数为0时,当计数为0时,资源会被彻底释放
         * 3. 若存在有部分逻辑未使用此接口加载资源,却调用此接口销毁资源,则可能会导致该资源被卸载或不可用,请注意
         */
        function destroy(url: string, method?: (res: any, url: string) => void, caller?: Object): void;

        /**
         * 资源预加载
         * @method: 预加载完成时,ok为true,id大于0,仅支持Skeleton和Texture
         * @return: 返回资源组ID
         */
        function prepare(urls: string[], method: (ok: boolean, id: number) => void, caller: Object): number;

        /**
         * 释放资源组
         * @id: 资源组ID
         * @return: 始终返回0
         */
        function release(id: number): number;
    }

因为3D资源比较小,而且项目很赶,所以并没有考虑3D资源的加载和释放,所有3D资源统一在游戏启动时加载,加上所有公用图集,合100M左右

若要使用大图或龙骨,则可以通过create方法来创建,若未曾加载,则此接口会先加载,用完后调用destroy来释放资源,此操作会产生计数,当所有对象都destroy掉后,龙骨或图片对应的位置资源也会彻底释放。

场景中的龙骨和大图,若始终存在的,则建议在加载场景之前先加载,若像炮台这种不存在的,则使用create和destroy动态创建和销毁,防止可恶的占坑不拉S。

至于prefab中的龙骨和大图,则可以在创建prefab之前先加载,若prefab中用了多个大图或龙骨,则建议先调用prepare来对所有资源进行预加载,然后销毁时再对该组资源进行释放,防止窗口出现但背景或龙骨没出现的情况。

emmmmmm,原本游戏启动时加载所有资源,总共460M,实现自己的资源管理器之后,GPUMemory在游戏启动后120M,大厅130M,游戏内135M,峰值160不到,+40M GPUMemory刚好200M,完美。

最后说下感慨,其实一直以来都很想进军3D游戏,无奈面试时总是因为答不出造核弹的核心而被刷,其实能有这次机会来做3D捕鱼对我来说是非常幸运的,这是我做的第一个3D项目,虽然是短短的三个月,但足以让我摸索了很多的技术细节,实践了很多曾经想做但却没有机会做的东西,当然也还有很多想法,很多想好的优化思路都没有时间去实施,可能站在产品的角度,三个月太长了,但对我来说,三个月太短了,且凭心而论尤其是对于一个精品游戏,三个月的时间,出来的真的只是一个模子而己,真的还有很多可以调优的地方,回想起这三个月,前期我催人,后期人催我,可能这就是客户端的无奈吧,只能说我无愧于自己,己经成功地在计划内与客户正式对接的时期之前交付了一个稳定的版本。

再见,本以为能实现很多理想的地方。

----2019-12-12 14:17:55-----

-------------------------------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章