Skip to content

0.Dev Log

大鹏 edited this page Aug 13, 2019 · 1 revision

已完成

)前端后端用 skynet 的 loginserver 通过登录验证
)使用 sproto 协议,按模块分文件和 id 组,开发时拼接所有协议文件,发布版则预导出为二进制(支持 lua 和 c#)
)搭建 apache 服务器提供资源和 lua 代码的热更新
)增加后端通用的 mysql 数据库服务
)在 PC 和安卓手机平台测试通过了,可以连虚拟机上的服务端并登录
)给 xlua 集成了 lpeg, sproto, lua-crypt 第三方库
)创建玩家帐号数据库和相关操作服务
)登录流程相关界面
)导出场景信息(前端 json 后端 lua 格式)
)九宫格加载场景块
)玩家进入退出场景及坐标信息的同步
)人物场景漫游 ECS 做法
)场景切割及动态加载
)人物的移动同步
)AOI(lua 实现的三维十字链表法)
)战斗协议同步
)lua 状态机

各模块的技术选型

)玩法逻辑:使用 Unity2018 自带的 ECS 系统(要用 Unity 的 ECS 只能用 C#),服务端也用 lua 实现一套类似的 ECS 系统
)界面逻辑:使用自制的基于组件的 UI 系统,全 lua 开发,动画也由 lua 实现了一份 cocos 的 action
)网络协议:使用 sproto,玩法用 c# 版本,界面用 lua 版本
)场景管理:因为是自由视角,所以需要预加载场景的 base world(几 m 的简模而已),其它的细节物品就以九宫格动态加载,使用四叉树管理
)资源管理:使用 Unity 新版的 AssetBundleBrowser 打包资源,以逻辑类型分类(如角色,场景,怪物等),ab 包增量更新
)数据管理:使用 redis,后面再看看要不要加入 mysql
)同步模式:基于请求回应的状态+差异同步

开发笔记

18.05.17:开始动工,以 luaframework 和 skynet 为基础快速搭建一个前后端骨架来。
18.05.20:在 linux 搭建好 skynet 服务端后就开始着手协议模块了,对比了 gpb 和 sproto 最后还是选了后者,因为 sproto 简洁好多。协议按模块划分为不同的 lua 文件,每个模块占用最多100个 id。开发模式时就在游戏启动时拼合所有模块的协议内容生成 proto 对象,正式发布时可以通过 Tools/sprotodump 工具预生成二进制文件提高初始化效率。
18.05.24:skynet 本身就提供了登录服务,所以后端不需要做多少东西。前端需要留意的就是读取网络字节流需要分两种方式,一种以大端方式仅取前两字节为包长度,一种是基于行区分网络包,详细见 NetworkManager.cs,登录流程见 LoginController.lua。
18.05.30:skynet 的登录验证用了 lua-crypt 库,但想在 windows 上使用还需要把几个 linux 仅有的接口改成 windows 版本的,还好要改的地方不多,然后加入 tolua 的 run_time 项目里用 mingw 生成新的 tolua.dll(项目后来把 tolua 改成 xlua 了,做法也是差不多的)。
18.06.02:用 apache 搭建了文件服务器,用于在手机跑游戏时热更代码和资源。遇到下载流程卡住不动,调试了下才知道是没处理好下载 0kb文件的情况。
18.06.11:luaframework 的资源管理使用 assetsbundle 名和资源名加载,每次资源一改就要重新打包,这样项目一大就很蛋疼了,要打很久包。其实开发阶段就不需要打包,直接找本地资源就行了,但就需要建立 ab 名与具体目录的映射表,我在工作项目就是这么处理的,所以这里我换成引用资源时用相对于 Assets 目录的长路径,在正式发布包里把长路径转换为 ab 包名,发现和上个方案好不了多少。现在为了方便开发,许多资源都打在同一包里,后面再慢慢细分吧。
18.06.20:简化游戏启动流程,因为启动状态有限,所以改成 switch case 的形式(之前的状态机算是过度设计了,各文件跳来跳去),然后统一放在 Main.cs 文件,状态间的跳转也在里面,只是每状态具体的工作交给各 mgr 处理,处理完后通过回调告知 Main.cs 然后在 Main.cs 里决定跳转去哪个状态,这样整个启动流程有哪些状态及跳转关系都一目了然了。
18.07.11:初步可运行了,先上传到 github 上
18.07.19:先做了个简单的协议分发器,收到前端发过来的协议时先解 id 号,然后根据其 id 号找到注册的模块及函数回调。
18.07.23:做了一个简单的基于组件的 ui 框架,功能不再集中于一个 ui manager,而是拆分为一个个组件挂在每个界面上,比如延迟销毁组件或隐藏底下所有界面的组件。先做了个登录界面,后面再慢慢补充组件完善功能。
18.07.30:创建玩家帐号数据库,完成创建和选择角色进入游戏等协议。
18.08.04:增加世界和场景服务,粗暴地广播全场景中各玩家的坐标变更信息,后面再加入 aoi
18.08.09:这几天心血来潮就把 tolua 换成 xlua,主要是因为工作项目就是用 tolua 的,还没试过 xlua,还好两者区别不大所以很快就改好了,用 xlua 的好处就是 c# 代码也可以热更,虽然很怀疑其性能,因为是运行时把某 c# 方法换为某 lua 函数,这个肯定不是迫不得已也不用的。
10.08.19:写了几个 UnityECS 的 System 用于创建和操作角色,我打算和后端只用一条通用的同步协议,无论是有东西进入退出场景,或者是其某些状态变更了都通过那条通用同步协议告知,协议内容可搜索 scene_get_objs_info_change。
10.09.21:前后端可以同步各玩家坐标信息了,就是前端的模型太丑了而且还没有动作。
10.09.26:增加场景分块加载模块,引用场景分块加载方案,本来想用摄像机碰撞到地图块就显示的方式,但是在手机上性能一般,同时加载的地图块太多了,最后还是决定了把地图块分为高低模两级别,低模是进入大场景后预加载的,然后有一大一小九宫格,小九宫格用高模,边加载边释放不可见的,小九宫格就显示隐藏视角碰见的地图块低模。还有一种方案是低模不分块直接显示,高模用九宫格,但要处理复杂地型两高低模之间穿透问题,还有超大世界时整个低模也挺大的了,这个后面也要改成 ECS 做法的。
18.10.02:因为要做大世界无缝加载,所以必须先分割大地图为 n 块,试了几个插件最后选择了 Terrain To Mesh,然后写了个脚本导出各地图块及其上的细节物件的坐标等信息,生成为 json 格式。
19.10.03:先加入第三人称控制插件,快速测试场景的分块加载,人物控制这块以后还要改成 ECS 实现方式的。
19.10.09:增加摇杆界面,支持在手机上移动角色了
18.10.10:考虑到资源越来越多,都放一起的话本项目 clone 会超级久,所以以后就把资源放在另外一个项目吧
19.10.15:增加 lua 版本的 cocos action(后来还是改成 c# 实现)
19.10.25:增加本地存档接口 cookiemgr,保存一些本地设置如历史输入帐号
18.11.08:写脚本导出场景信息给后端使用(npc 和怪物列表),直接生成 lua 代码。
18.11.13:初步完成的大世界场景分块加载(还在考虑无限场景的 NavMesh 资源管理,先尝试用跳跃点连接 n 个地图块的 navmesh)
18.11.23:由于 unity 的 entities 版本更新修改较多导致之前的部分逻辑要重写了,感觉还是暂时先不弄前端的 game play 逻辑较好,先弄寻路和后端逻辑吧。开始写后端逻辑后想用 ecs,考虑了两种方案:1把 unity 的 entites 去掉 unity 引擎的依赖并移植到 linux 然后导出接口给 lua,2用 lua 实现一份 ecs。最后选择了方案2,因为方案1需要在 linux 上运行c#,连带上了整个 mono 运行时,这就太累赘了。所以还是用 lua实现多一份的好,虽然已经有很多第三方 ecs 库了,但还是自己实现的好玩。
18.12.15:unity 的 entities 框架从 c# 转换为 lua 实现时需要留意几点:1)数组从0起始,而 lua 习惯了从1开始,0索引会放在 hash 部分,所以大部分代码都要改成1起始,用起来也方便一点,有个例外就是 ChunkDataUtility.lua 里面的函数还是0起始,因为要直接操作指针。
2)为了保证组件信息尽量存放在连续内存中,从而提高缓存命中率,组件信息都平坦地保存在名为 Chunk 的 userdata 里,引用时根据偏移算出指针地址进行读写。
19.01.23:初步完成了可运行的 lua 版本 ecs 框架了(因为公司游戏上线忙死了所以基本上没什么时间弄),开始做后端的 NPC 和怪物逻辑吧,边做功能边给lua ecs补特性吧。后端的寻路就用 recastnavigation 库吧,要先导出接口给 lua,其次是 unity-navmesh 导出的数据不能直接用的,所以还要写个脚本把 unity 生成的 navmesh 导出成 recast 支持的格式
19.02.03:前端的寻路资源流程确定为大世界的 navmesh 分块打包(需要划分到不同的 scene 把所有节点删光,这样就只有 navmesh 数据了),然后运行时可以 Additive 模式加载该 Scene,当然导出 navmesh 前还需要拉几个 OffMeshLink,这样加载多个 scene 时会就自动把多个 navmesh 关联起来。
19.02.13:终于把 unity 的 navmesh 导出成 recastnavigation 可以使用的数据了,主要思路是利用 unity 的 NavMesh.CalculateTriangulation方法返回的三角形数据转化为 recast 里的 rcPolyMesh 对象然后再参照 RecastDemo 那样创建出 dtNavMesh 对象,详细见 Navigator
19.03.17:把人物场景漫游的逻辑换成 ECS 实现了,不过动作还是用 Animator,场景加载还是先改成 baseworld 加细节物件九宫格加载。
19.03.26:用 Timeline 实现了普攻和技能,省下了开发技能编辑器的功夫。接下来就弄个好看的轻功四段跳和场景同步逻辑了。另外资源方面还没上传最新的,主要是两点原因:1我还在纠结资源命名规范和目录结构等细节,未来会经常变动。2因为懒得在网上找资源所以直接用了公司项目的了,这个不好直接上传,等功能做得差不多了我再找替代资源。
19.04.08:用 lua 实现了 aoi 模块,用的是十字链表法,因为是 3d 的所以用3条链表,以后有空再改成 c 实现吧,终于可以不用全场景广播了。
19.04.22:增加了一些怪物逻辑,但还缺 AI 部分(还在考虑用哪种行为树方案,还是自己弄一套算了?)。另外角色控制方面由于跳跃状态不是定长的,比如跳崖后就会一直处于跳跃状态中,所以还是不适合使用 timeline,所以改成代码计算高度并控制动作状态。
19.04.25:做战斗飘字时需要针对该艺术字节点做动画,虽然有现成的 TweenLite 可以用,但感觉还是 cocos action 的接口更好用,所以又实现了一个 c# 版本:
UnityCocosAction
19.05.08:实现了个简单的状态机并完成了怪物的巡逻状态逻辑。
19.05.13:把 LuaECS 实现为纯 lua 了,因为 c 和 lua 交互的消耗太大,数据平坦放置带来的性能提升都弥补不了,而且用纯 lua 后可以使用 table 为组件,方便多了。
19.05.20:完成怪物追捕和攻击的逻辑
19.06.11:完成怪物扣血和死亡复活逻辑
19.06.16:升级 unity 版本到2019及 Entities 到最新的 0.0.12preview32(代码又大换血)
19.06.18:增加寻路,点到哪里去哪里
19.07.03:初步实现了自动寻路去找 npc 对话和打怪两种任务:
image
19.07.10:增加一个副本场景:
image
19.07.31:初步完成背包和 GM 系统
19.08.11:初步完成基于 action 组件的技能系统,见 Server/lualib/Action及 FightMgr,Hurt 和 PickTarget.lua
19.08.13:完成复活流程

Clone this wiki locally