这是一篇严肃的联机游戏开发入门介绍,本文所述代码开源,文末可获得地址。

关于游戏的实时联机对战,目前是很多游戏开发者研究课题,也延伸出了很多概念,如“状态同步”、“帧同步”,目前很多游戏开发框架也提供了这样的开发一些理念和组件,比如unity的The High Level API等等。

本文不希望传授如何用框架、服务端引擎等来搭建一套商业级的框架。而是希望从最基本的网络通信原理开始,一点点的进行朴素的分解和搭建,旨在从原理上概述联机游戏的设计思路以及抽象于计算机网络的通信框架如何设计和构建。

我个人编写这套DEMO包括完整的客户端和服务器,也是用于调研工作室游戏《汉家江湖》后续的实时联机部分如何搭建和开发,并且后续作为我们自己的一个实时联机通信框架的测试程序。


实际完成的DEMO如上,每个玩家是一个点,只有一个操作:使用左下的虚拟摇杆进行方向控制。在移动过程中不断喷射子弹,命中对方即可扣血,在规定时间内比谁的击杀的人数多。由于是一个简单的DEMO,我们不在美术上做太多东西(请原谅我的五毛钱PS技术),主要是为了讲解程序如何来设计。

工具部分,客户端我们使用unity开发,服务端我们直接从0开始写一个基于socket的服务器。

我们使用状态同步来做这个DEMO(理论上帧同步机制是更加适合这种IO类游戏的,我们为了逻辑清晰简单,先用状态同步来做,后续有时间我再补帧同步的方案。)

状态同步

什么叫状态同步?

简单的来理解就是所有的数据在服务端进行计算和校验,客户端将操作上发到服务器,服务器不断的告诉客户端计算结果,由客户端进行展现。

客户端逻辑结构

客户端的整体框架逻辑非常简单,unity是典型的单线程编程,我们只需要在FixedUpdate里出来所有的消息队列即可。

其实按照socket的非阻塞模型来说,我们客户端也可以不使用接收线程而使用纯粹的单线程。我们在这里不再赘述,再次重申,我们只是很简单粗暴的一切为了编程简单易于理解。

客户端维护一个消息队列的原因是,我们每次收到的数据需要顺序的执行。在unity中我们所有改变UI或者界面相关的逻辑需要写在主线程中。所以我们使用一个消息队列来进行传递,每次FixedUpdate时依次处理所有的队列中的消息。然后处理客户端应该发送的指令。需要注意的是,由于消息队列被两个线程同时访问,作为临界区数据,需要加线程锁。

服务端逻辑结构

我们这里通信协议使用tcp(大家实现也可以使用udp,都类似),那么服务端是一个典型的处理连接、处理请求并分发数据的逻辑结构。我们为了编程简单,也先不顾效率的每一个客户端连接我们起一个专门的接收线程,然后统一分发处理,逻辑结构如下:

使用单线程来处理整个游戏的主逻辑,是一个典型朴素且最简单的编程思想。当然,这里可能会存在瓶颈问题,所以具体中间有很多可以优化的点,比如一些物理计算实际可以拆分成多线程或者跟进一步使用GPU、比如接收客户端数据可以使用非阻塞模型或者线程池……这里不再多做说明。

其实我们抽象一下,以上整个框架实际上适用于任何类型的联机游戏。对于网络连接层,我们需要很清楚几个概念:

每一个客户端连接,在服务端维护一个session,这个session主要处理与客户端的通信(收发数据)以及该客户端的一些临时状态(我们这个游戏没有)。

通信协议

服务端维护了一份完整的数据结构,在本游戏就是当前游戏中剩余时间、一共有多少个玩家、玩家的HP、玩家们所在位置和移动方向及速度、一共有多少颗子弹、子弹的移动方向和速度……

我们称整个以上数据为一份全量状态,它描述了整个游戏当前的情况。

最朴素的思想就是服务端不断的将整个全量状态分发到每个客户端,这样客户端就只用管显示就行了。但实际的开发过程中会发现这样飞快就会达到性能瓶颈(因为发送的数据量太多,网络IO吃不住。而且也可能因为不断的要生成全量数据快照,CPU的计算量也非常大。)所以需要优化,接下来我们具体探讨一下通信协议如何来做。

通信协议是客户端和服务端共同约定的一个数据结构,其包含了双方可以发送并对方可以识别处理的数据包。

在设计网络协议的过程中,我们需要有一个的分层概念,我们更多的只需要来关心业务逻辑,也就是具体发送什么样的数据,底层的话这里我使用protobuf(性能最高的开源序列化、反序列化库)。

我们使用protobuf将数据结构序列化为二进制数据,并且通过socket来进行发送,接收方收到后使用protobuf反序列化为业务协议,提供给上层逻辑代码进行解析。所以实际上蓝色部分都是使用开源库来进行的,我们只用关注实际的游戏业务协议(绿色部分)。

我们拆解一下实际的业务协议如下

客户端 -> 服务器:

1、加入游戏

2、角色行动+开火

服务器 -> 客户端:

1、新玩家加入游戏

2、某个玩家被击中/击杀

3、玩家移动+开火

4、全量状态同步(用于游戏进行到一半有玩家加入,发送给他当前对局的整体情况)

5、时间流逝

所以实际上我们游戏的编程,就是在客户端和服务端互相生成并处理以上数据包的过程。对应前面的流程图就是所有的消息队列处理和生成。由于具体和游戏内容相关,各位有兴趣可以看代码,这里不再多做描述。

代码结构

另外,我需要更进一步说一下关于代码结构的一些思考。

由于服务端和客户端实际上有大量的数据结构交换,我认为一个比较好的方式是一份代码两边使用。所以我服务端也是使用C#编程开发,将一个脱离框架的dll(主要是业务通信协议和各种两边使用的数据结构、常量和计算工具)同时分发给两边使用。

具体可见服务端代码中的ShootGameServer.SharedData,这份代码同时会生成dll到客户端Unity的/Assets/Plugins目录下。

另外关于网络层的适配,我整个抽象了出来,所以大家如果有兴趣的话,可以使用UDP重写或者自己来编写底层的通信链路(下图橙色部分)。其TCP实现位于ShootGameServer.SharedData.Network.Impl

其中服务器我写了一个通信链路的集成单元测试,位于

开源代码中通信链路KCP部分代码我尚未集成完毕,大家可以忽略。

未来的一点点计划

目前我们工作室计划针对性的开发一套业务无关的网络链路层框架,主要实现的功能是“开房间”-“加入游戏”-“游戏”-“结束”的一套基于云服务分布式调度的管理框架。

通俗来说就是可以开发 实时联机的IO类游戏、百人联机的吃鸡类游戏、MOBA类游戏这种高实时性互动性要求的游戏。

我们计划将各个模块性能消耗优化到极致,并且未来提供多种高度封装易用的编程模型。

此模块我们会先在自己的内部的游戏项目中实践使用,未来考虑开源+分享出来。或者提供一套便捷易用的SDK,供外部使用。

DEMO开源代码

Github地址:https://github.com/hansquirrel/IOShootGameDemo

由于代码写的比较仓促,很多地方性能等均没有进行优化,主要看编程结构和思想。欢迎大家给我意见,有疑问也欢迎到github与我进行互动。

如何从0开始开发一个实时联机游戏相关推荐

  1. 如何从零开始开发一个实时联机游戏?

    本文作者为明星团队汉家松鼠游戏工作室的CEO成功(CG),他将于11月10日在深圳举办的第四期腾讯游戏学院品鉴会上,分享汉家松鼠旗下<汉家江湖>.<江湖X>等游戏从立项.研发到 ...

  2. 如何开发一个扫雷小游戏?

    如何用C#开发一个扫雷小游戏? 十分自豪的说,计算机编程就是变魔术,每一个coder都是一个魔术师. 初学C#的时候,我相信很多人都和我一样,学会了基本语法,掌握了基本的数据结构,也见过了不少微软提供 ...

  3. 开发一个Canvas小游戏 实现一个游戏“引擎”

    前言 这个游戏其实在三四年前就写了,中间还重构过好几次,之前都是用简单的面向对象和函数式编程来写,游戏中的元素关系到还是分的挺开,但是游戏的渲染,运算等逻辑分的不够清晰,整个逻辑基本都是自顶向下的流水 ...

  4. 用python开发一个推箱子游戏

    好的,为了开发一个推箱子游戏,你需要了解一些基本的编程概念,如变量,循环,条件语句和函数. 首先,你需要定义游戏场景,即箱子和人物所在的空间.你可以使用二维数组表示游戏场景,每个元素都代表一个格子. ...

  5. 如何开发一个小程序游戏?

    小程序游戏开发需要开发人员具备以下几点能力: 有一定的编程基础,例如 JavaScript.TypeScript 至少熟悉一种游戏开发引擎,比如 Cocos.Unity等 对游戏机制.游戏系统有一定的 ...

  6. 如何利用状态同步开发一款联机游戏

    游戏状态同步 1.前言 目前市场上单机游戏占比高,因为相对联机游戏开发周期短.成本低,但联机游戏的社交属性强,玩家粘性高.总体来说,开发联机游戏有一定的技术门槛. 2.帧同步和状态同步 •     帧 ...

  7. 从0开始搭建一个战棋游戏的AI(初级教程)

    战棋类游戏一直以高策略性著称,其中不乏经典之作如"三国志英杰传"."三国曹操传"."炎龙骑士团"."金庸群侠传"等等. ...

  8. Step by Step 使用HTML5开发一个星际大战游戏(1)

    本系列博文翻译自以下文章 http://blog.sklambert.com/html5-canvas-game-panning-a-background/ Languages: HTML5, Jav ...

  9. Silverlight C# 游戏开发:Flyer01开发一个有趣的游戏

    前面扯了很多理论,虽然很无聊但是对于开发游戏来说非常的有用,在早年的开发环境,没有这么多可视的工具,一切靠的是对画面的理解以及游戏感觉Coding代码,然后不厌其烦的测试修改测试修改. 在未来的一段时 ...

最新文章

  1. 第三百三十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—深度优先与广度优先原理...
  2. 部署Chromedriver
  3. Access denied (java.lang.RuntimePermission getClas
  4. 三星手机怎么恢复删除的图片_手机相册照片突然删除了怎么恢复?这个方法好用...
  5. python编程书籍1020python编程书籍_代写INFT 1020作业、Database作业代做、Java课程作业代写、c++,Python编程作业代做...
  6. c语言中c为字符型便量,c='97'是否正确,C语言判断题Word版
  7. 注意:python flask 里image文件 css文件 html文件都必须有固定存放位置!
  8. Android自动测试之MonkeyRunner之monkeyrunner
  9. YBTOJ:彩色圆环
  10. ElasticSearch 聚合查询
  11. 深度学习(参数选择)
  12. Maven生命周期和插件的那些事(2021版)
  13. (24)FPGA减法器设计(第5天)
  14. Atitit.eclipse git使用
  15. 通过Docker Cloud部署应用
  16. ActiveMQ笔记(二)
  17. jsp java 购物车,jsp简单购物车
  18. android电池管理软件,四款安卓手机电池管理软件横测
  19. mysql数据脱敏_数据脱敏|静态脱敏|动态脱敏—数据库脱敏_产品
  20. 哨兵-2 Sentinel-2 数据下载(USGS)

热门文章

  1. 【D3.js实战】 品牌排名动态可视化
  2. 【开源访谈】Kingshard 作者陈非访谈实录【项目简介】 Kingshard 是一个由Go开发高性能MySQL Proxy项目,kingshard在满足基本的读写分离的功能上,致力于简化MySQ
  3. 怎样分析crash dump(内存错误)
  4. 基于Exynos4412的lcd驱动1
  5. 为IPN做铺垫的航天任务-好奇号,信使号,深度撞击,月球轨道侦查LRO
  6. 修改(My)Eclipse默认的Servlet和jsp代码模板
  7. 我是上海宝付新手来学习代码
  8. 黑盒测试(一)-----边界值测试
  9. 恋曲1990——罗大佑
  10. 2013电大计算机综合应用能力实训将邮件保存到考生文件夹,计算机综合应用能力实训...