游戏框架
副本逻辑框架
概述 一般副本中都会包括各种各样的行为和判断逻辑,下面举一个简单的副本例子,进入副本后,如果组队人数到达三个,则刷出怪物,播放特效,播放对话,与怪物战斗后,弹出结算UI,再播个动画。 如果由策划出完案子后程序负责直接实现的话,每个副本都是定制化的,写起来非常难受,而且维护极不方便,一旦需求改动就要重新写代码 所以需要设计一套副本系统可以灵活配置副本功能,想法是把副本里的每个行为,判断都作为一个节点,类型行为树的概念,从开始节点一直执行到结束节点,这个副本进程就结束了,进入下个副本进程。 编辑器使用连线的方式操作,每个节点的前后置关系,导出lua配置供程序使用,服务端控制执行流程,客户端只需要执行节点逻辑。 例子 节点可以分为执行节点和判断节点,执行节点执行一个行为,流程推进,判断节点在符合条件的时候,推进流程,否则暂停。 端口定义了每个节点间的关系,也就是图中的连线,控制流程走向,比如刷怪战斗节点,输入端口连接“判断组队人数”,有两个输出端口,分别是胜利和失败,连接对应的节点。 把副本流程解构成一个个节点以后,只需要维护节点的行为和端口逻辑即可,组合由策划完成,只有在添加新节点时程序才需要上场。 编辑器 编辑器可以用网上的开源例子xnode组织节点,也可自己实现。 导出的数据包括了节点的类型,参数,前后置节点等一切代码需要的信息。 副本流程 服务端推送当前节点信息 服务端执行/客户端执行 服务端/客户端完成节点,推进流程 直到到达结束节点
场景数据框架
一、概述 一般MMO的游戏由场景和场景中的对象构成,在设计地图时,就会遇到几个问题。怎么有效直观地配置信息,对象都有什么功能,有什么功能是共有的。针对上面的问题,首先需要解决的是抽象出场景对象结构,在此基础上做编辑器,用图形化的界面展示,修改储存数据,供代码使用。 二、场景对象结构 场景本事有数据,如场景资源,组队人数限制等等,这种信息改动不大,也比较直观,一般只要存在excel里面就好,需要的话可以做图形编辑器对excel进行读写和修改。 场景中的对象可以按需分成几类,常见的有npc,采集物,区域,点等等。 NPC NPC主要承载了显示模型的功能,读取NPC表。 采集物 采集物和NPC差不多,只是对话交互改成了点击采集。 区域 区域分成了圆形区域和多边形区域,划分区域可以实现进入和离开区域的逻辑,比如划分了游泳区,飞行区等,进入以后主角切换运动状态。 点 点的功能比较广泛,主要用于定位,也可以添加触发组件以后实现圆形区域的功能。 组件 组件是对象上的属性和功能,公用的组件有缩放,大小,显示隐藏条件等,特殊的组件有巡逻,交互按钮等,按需添加,从而赋予对象特性。 三、场景编辑器 理清了场景对象的结构以后,就可以做编辑器把数据组织起来了,场景编辑器的实现细节不多说,尽量用起来符合直观操作即可,功能如下。 增删改场景信息 直观展示场景中的对象(位置、模型、范围等) 增删改场景中的对象 修改对象的组件属性 导出程序可用数据 四、数据载体 数据可以直接导出lua,也可以导出成json,xml等,只要方便维护,程序方便调用即可。 目前使用的是先储存到excel,再从excel导出到lua中,供程序调用。 使用excel作为中间载体的原因可能是比较直观,但感觉使用json或者Unity序列化的方法也是可行的。
游戏对象框架
概述 游戏对象管理一般是通过总分结构,管理器为RoleMgr,对象为Role,Role的功能由各种功能组件实现,从而实现继承和解耦。 RoleMgr 管理类管理游戏中所有的Role,负责Role的创建、查找、销毁,一般配合UID生成器,给每一个Role分配一个唯一ID作为唯一的标识。 Role Role是游戏中的对象,可以是角色,特效,建筑等等游戏中的一切实体,由BaseRole派生。 BaseRole 基类,定义Role的最基本信息,如GameObject,Transform信息,显示隐藏状态等等。 派生 对BaseRole进行派生就是具体的游戏对象,如添加了控制器以后就是角色,再添加主动移动的控制器以后就是主角,通过绑定不同的组件实现Role的不同方向功能。 Role的功能 Role的功能都由挂载的组件实现,常用的组件有 模型组件 被动移动组件 主动移动组件 显示隐藏组件(多条件) 范围触发组件(当玩家走进时会触发回调) 头顶文本组件 还有各种项目中需要实现的功能 Role的结构
《游戏逻辑思想》学习笔记
前言 这本书忘记从哪里下载了,和别的技术书籍不太一样,大多的内容都比较贴合项目开发,所以有一定的参考价值。 里面有几个章节觉得有收获的,主要是框架的设计,以及一些解决问题的思路,大致做了笔记或者摘录。 一、基础内容交流 代码规范 可读代码:由于动态语言的类型灵活性,可以在变量前加上变量类型简称 正确使用断言与返回 注意什么时候可以为空,不要盲目返回 可拓展接口使用 多参数,下面演示了三种写法,最终应该在保留必要参数的情况下,可选参数做成table addModulePower(nModuleId, nPower); addModulePower(nModuleId,nPower,bSyncMsg,bSendEvent, bOnlyBoss) if( tOption && tOption.bSyncMsg){ //做这个参数该干的事情 } 调试的思维与逻辑 正向和逆向思维,逆向更快 不易复现的bug,埋下日志,下次使用 培养敏锐的异常反应 注意生命周期的创建与销毁 代码修改与重构 我们在项目中秉持一个原则,如果有个接口让你不舒服,比如说多传了几个参数,那么我们一定要提出来,那一定是接口的设计不够简单或者没有提供更简单的接口形式。 优雅的使用外部代码 我们的一个原则就是要尽可能少去直接和引擎进行交互,而是更多的进行局部缓存,把战场拉回到更加通用的逻辑里面。 修改后的代码为: let levelSlider = Core.createBitmapByName("slider_png"); let nSliderX = 0; if(XXX){ nSliderX += 6; } if(XXX){ nSliderX += 8; } if(XXX){ nSliderX -= 2; } levelSlider.x -= nSliderX; 选择简单的接口/参数以及尽量少的使用/调用底层接口就是我们所谓的正确的代码使用方式。 代码审查 取出一个管理器对象。然后直接访问了它的成员函数,这是非常不应该行为。第一个是这个成员不应该是公有的,而应该是私有的,它的公有性质破坏了类的封装。 从面试的角度看面试 基础能力,逻辑能力,硬核能力 如何应对代码错误 作为项目的主程,还需要统一思想。这个过程包括要求大家遵循统一的代码命名等,这也是规避错误的一个重要手段。越是相似的代码风格,代码的阅读速度就会越快。 二、逻辑设计模式式讨论 分层设计 事件的派发遵循从下往上:比如M驱动V 依赖性越强的越靠下层 变化的放上层,底层可以互相依赖,逻辑层不允许相互依赖 主动和被动 被动模式,依赖事件,及时,性能消耗少,当被动模式不在能支持复杂逻辑时,可以考虑主动模式 主动模式,依赖轮询,有点像ESC的系统层监听实体层的感觉了。优点在于可以监听多种条件 阻塞和非阻塞 主要用于资源加载,阻塞速度快 统一与非统一 效率没有打到一定程度的影响时,推荐考虑统一性 三、框架设计初步 基类 存活状态,唯一ID 框架代码结构 子类关注的基类接口一定是个空的实现,意味着子类不需要考虑去调用父类同名的接口。 框架设计 配置化编程:消除重复代码,如协议监听,按钮监听等等 自动化平衡处理:如果没有销毁,帮忙擦下屁股 机制有助于实现全局性的功能,尤其处理大规模需要重复代码的东西 框架拓展的思路 基础能力,封装类,继承到框架中 四、逻辑设计原理 缓存的设计 缓存存放的东西有限,不能所有的东西都放缓存。 缓存应该具备清理功能。 缓存系统应该具备一定的匹配能力。 缓存具备最小保留数量以及预先创建的能力 分线漫谈 分线,是将玩家划分到不同的频道中,不同频道的玩家互不可见,且不会互相同步消息。分线在程序方面主要用于减少网络包,在策划层面会有一些其他的应用。分线是基于场景的,我们的可见性,以及消息同步默认以场景为单位。 ...