网络游戏架构设计
2022-05-15 19:36:20 【

随着 Stream、TapTap 等游戏平台的崛起,越来越多的网络游戏在此平台投放,而且很多新发布的游戏收入都颇丰,这些发布的游戏很多都是几个人开发完成的,而且开发周期都比较短,如何才能快速开发网络游戏?一个比较好的游戏框架是非常必要的。另外,这些平台的崛起,对于独立游戏开发者来说,也是一个非常好的机会,换句话说独立开发者的春天又来了,当然对于那些想从事游戏开发或者说已经在这个行业从事游戏开发的人也是一个机会。


现在游戏不只限于抄袭了,更强调创新,只要有好的创意,再加上一个比较好的游戏框架,几个志道同合的小伙伴就可以开发一款网络游戏。在国外有很多这方面的案例,几个人在不同的地方,一起开发一款游戏。而在国内很多普通程序员在游戏公司估计只是从事某项单一的逻辑功能编写,对整体架构设计并不是很了解,即使自己有好的想法局限于自己的能力估计也是很难做出一款游戏,在游戏公司很少有人会教你架构设计,而且对于开发者来说,要么只会客户端,要么只会服务器,非常少的人同时精通二者,这也困扰着那些想自己做游戏的开发者。本课程正是基于解决这些困扰程序员的问题,提出了一种基于网络服务器的架构设计,让程序员一个人可以同时进行客户端和服务器的网络游戏的开发,这样再加上美术和策划就可以搞定一款网络游戏。


搭建游戏框架首先要搞清楚什么是框架?其实搭建框架的主要目的是便于游戏逻辑的编写,这样非常有利于开发者快速的开发游戏,框架的核心思想是模块之间的耦合性要降低。那我们先搞清楚游戏框架中主要包括哪些技术点,从大的方面说,每款游戏都有自己的 UI 系统、角色系统、技能系统、网络系统等等,往小的方面说就是编码的细节——每个类的编写。下面就把游戏中的几个核心系统的架构设计思想逐步介绍给读者,架构设计没有好坏之分,用着方便就可以,在这里就当是抛砖引玉,读者也可以在此基础上去扩展,去重新编写架构。这样本篇教程的目的就达到了。


先介绍 UI 系统,这个是老生常谈的,UI 架构常用的设计模式是 MVC。读者应该对 MVC 都比较了解,原理就不介绍了,可以去网上查阅。下面讲下 MVC 模式如何在 UI 系统中使用?

我们就围绕着这幅图给读者介绍模块设计。


在设计 UI 框架时首要考虑的事情


首先,要做到 UI 资源和代码逻辑的分离,因为 UI 资源是经常更换的,如果二者不分离,很容易在更换资源时出现各种各样的脚本丢失以及资源和代码逻辑对应不上问题,这个对于程序来说必须要避免的,程序员不应该把时间都浪费在这些事情上面。


其次,逻辑代码之间的耦合性要降低,降低耦合性的方法通过事件的方式进行处理,很多程序使用 SendMessage 这种 Unity 自带的消息发送机制,其实它是非常消耗 CPU 的,为了优化这些,我们会自己封装事件机制。


以上两点是指导我们做架构的指导纲领,不论怎么设计最好围绕二者进行。


接下来介绍 UI 架构搭建的各个逻辑模块,上图中显示的窗体模块并不全面,游戏中的窗体是非常多的,在此以登录窗体和英雄窗体为例进行说明:Loginwindow 和 HeroWindow 它们是负责显示的,也就是说,它对应具体的窗体逻辑,它对应的 MVC 模式中的 V,相当于 View 显示,该模块是不继承 Mono 的,也就是不挂接任何 UI 对象。LoginCtrl、HeroCtrl 模块相当于 MVC 中的 C,Control 控制,用于操作 LoginWindow,HeroWindow 所对应的 UI 窗体,比如用于控制不同窗体的显示、隐藏、删除等等操作,在图中没有列出 MVC 中的 Model 模块,这个模块主要是用于网络消息数据的接收,也可以通过文本文件直接赋值的,它可以使用列表进行存储,相对来说用处并不是不可替代的。


游戏中存在的窗体是非常多的,这么多窗体,如果不同的开发者写逻辑,会搞的很多,不利于统一管理。由此需要一个类 WindowManager 管理类进行统一注册管理各个窗体类模块,这种处理方式也就我们经常说的工厂模式。


另外,窗体之间是经常会进行不同的切换,这些切换也可以对它们进行流程管理,因为窗体之间的切换是一种固定的流程。既然经常转换,我们不免会想到状态机用于处理这种流程。在此,引入了状态机进行统一管理不同窗体状态的变换。各个模块之间的耦合性也是要重点考虑的问题,在此采用了自己封装的事件机制进行解耦合。


具体实现逻辑如下,每个窗体对应自己的类,以登录 UI 为例进行说明,每个 UI 都是一个 Window 窗体对象,它对应着 Loginwindow 类、LoginCtrl 类、LoginState 类。其他的窗体类似,而这些类都不继承 Mono 也就是说不挂接到任何 UI 窗体对象上,这样,彻底实现了资源和代码的分离,UI 系统思想设计完成,接下来再介绍技能模块和角色系统的架构设计。


技能模块设计思想




关于技能的设计,首先要考虑的是这个技能是谁释放的,也就是说的游戏实体类,实体类的设计在此分了三层:IEntity、IPlayer 和 Player,这三个模块同样不继承 Mono,也就是说不挂接到任何对象上,具体的实现会在后面的章节中结合代码详细介绍,技能释放者找到了,接下来设计技能了。


游戏中的技能分好多种:正常释放的技能、被动技能、远程技能等等,这些不同的技能我们也将其进行模块化设计,其实它们的内容是类似的,可以考虑使用脚本自动生成代码。当然对于游戏中众多特效的使用,我们也需要写一个特效管理类,用于创建不同的特效,特效采用的就是模块化管理,特效实现了后,就要考虑特效是根据游戏实体对象的不同动作进行释放的,不同的动作对应着不同的技能,这当然就是不同动作之间的切换,在这里使用了 FSM 有限状态机进行统一调度。


再介绍一个重要的模块——对象池,因为我们的特效会频繁的创建、销毁,还有游戏中的怪物 NPC 也是一样的。当然,其他的游戏管理类在游戏中都比较常见,其他的一些系统比如背包系统、任务系统,这些可以根据消息或者配置文件进行加载读取,这里就不一一说明了。


接下来介绍比较重要的网络游戏服务器,我们的服务器使用的是 Photon Server,用户直接搭建非常方便,在本教程也会把服务器的搭建过程介绍给读者,我们的网络架构采用的是房间模式,同房间的人可以在场景中实时同步,包括技能、动作等等。而该实时同步的实现方式采用的是状态同步,接下来介绍一下 Photon 服务器的体系结构:



为什么选择 Photon Server 作为服务器,因为该服务器提供了负载均衡,以及做大型网络游戏 MMO 等技术实现,用户无需太关心。它的核心使用的是 C++ 编写的,效率无需使用者关心,同时该服务器支持 UDP、TCP、HTTP 和 Web 套接字,它的应用层使用的是 C# 编写的,对于用户编写逻辑非常方便,而且它也支持数据库和非数据库模式,比如 MySQL、SQL Server 等数据库,以及 MongoDB、Redis 等非数据库。


再介绍一下关于服务器的基本工作流程,从客户端角度来看,工作流程也非常简单,非常适合新手学习,客户端连接到主服务器,可以加入大厅,并检索打开游戏列表。当他们在 Master 主服务器上 CreateGame 操作时,游戏实际上并不创建游戏服务器,而是确定人数比较少的游戏服务器,将 IP 地址返回给客户端。当客户端在主服务器上调用 JoinGame 或 JoinRandomGame 操作时,主服务器查找运行游戏的游戏服务器,并将其 IP 返回给客户端。流程图如下所示:




如果客户端与主服务器断开连接,使用刚收到的 IP 连接到游戏服务器,再次调用 CreateGame 或 JoinGame 操作,断线重连都没有任何问题。下面介绍游戏中比较重要的部分,MMO 游戏同步思想。


关于使用 Photon Server 做 MMO 游戏同步实现的思想


客户端中的地图,同样也会在服务器中虚拟一个跟客户端大小完全一样的地图,角色就是在这些虚拟空间中同步,角色同步是在一定的区域内进行同步的,也就是在一定的区域内是互相“看见”的,这种看见与客户端的相机裁剪是完全不同的。




计算哪些对象在某些区域会频繁移动,这些对象可能会非常耗费 CPU 资源。加速这一计算的一个简单的方法是将虚拟空间划分为固定区域,然后计算哪些区域重叠。客户应该接收这些重叠区域中的项目的所有事件。最简单的算法使用方形的网格,有时我们也称为九宫格算法。




物体通过当前的区域推送事件,一旦特定的区域重叠,它自动订阅区域的事件通道,并开始接收包括物品推送的区域事件。为了避免在区域边界频繁地订阅和取消订阅改变,引入了另外的更大的兴趣区域半径:跨越此外半径的订阅区域被取消订阅,客户端停止接收区域事件。用通俗的语言讲就是在服务器虚拟的场景中,会通过不同的玩家生成各自的九宫格区域,其他 NPC 或者玩家在对方的九宫格区域里面,物体都会显示,离开自己的九宫格区域就剪掉,这样也会是考虑到效率问题,因为如果整个场景实时同步计算,这对于客户端和服务器压力都是很大的。九宫格区域如果重合那就把重合的部分都显示出来。




用户创建房间,其他用户加入房间,多人场景在同一房间中同步的效果如下所示:

通过此网络游戏框架可以快速的把网络游戏实现出来,本课程的最后会把服务器和客户端代码都奉献给读者,希望对开发者有所帮助。从下章开始,本教程进行详细介绍架构设计实现。


】【打印关闭】 【返回顶部
上一篇没有了 下一篇弹性伸缩游戏服务器的优选