课程简介
本书主要讲述大型多人在线游戏开发的框架与编程实践,以实际例子来介绍从无到有地制作网络游戏框架的完整过程,让读者了解网络游戏制作中的所有细节。全书共12章,从网络游戏的底层网络编程开始,逐步引导读者学习网络游戏开发的各个步骤。
本书通过近50个真实示例、近80个流程图,以直观的方式阐述和还原游戏制作的全过程,涵盖了网络游戏设计的核心概念和实现,包括游戏主循环、线程、Actor模式、定时器、对象池、组件编码、架构层的解耦等。
本书既可以作为网络游戏行业从业人员的编程指南,也可以作为大学计算机相关专业网络游戏开发课程的参考书。
关键词:网络游戏,游戏程序,程序设计
本次介绍1.1节的内容 单机游戏与网络游戏的区别,课程完整版可前往UWA学堂观看《多人在线游戏架构实战:基于C++的分布式游戏编程》。
1.1 单机游戏与网络游戏的区别
本章主要介绍网络编程的基础知识,单机游戏与网络游戏的本质区别在于有了网络层的介入,有了异步。本章的重点在于网络编程的基本概念和网络底层函数的使用。本章包括以下内容:
- 介绍网络编程的基本概念。
- 给出一个阻塞式的网络示例。
- 给出一个非阻塞式的网络示例。
要了解网络游戏,需要先从单机游戏出发,这里讨论的单机游戏是指PC端的游戏,而非XBOX这类游戏机上的游戏。
就国产游戏来说,1995年推出《仙剑奇侠传》之后,随后的几年,《仙剑奇侠传》系列、《轩辕剑》系列一度盛行,在2000年左右,单机游戏发展至巅峰。2001年1月,华义推出了网络游戏《石器时代》,直到2006年左右,巨人网络推出《征途》,第九城市代理的《魔兽世界》公测,将网络游戏推至巅峰,单机游戏才慢慢淡出市场。这一系列的单机游戏都有一个特点:没有服务器的概念,玩家不需要与别的玩家进行交互,所有数据、算法、存储都在本地完成。所以,在单机游戏的早期,很多游戏修改器应运而生,这些游戏修改器要么修改本地的存储文件,要么修改内存数据,以达到“无限金币”“超强武力值”等目的。
作为玩家,我们可以体验游戏、打开游戏界面、点击操作、得到反馈、继续游戏。下面从编程的角度来看看单机游戏的设计流程。
单机游戏的设计思路如图1-1所示。在游戏开始时,需要加载一些资源,这些资源包括地图信息、基本的图素、用户界面(UI)等。加载完成之后,用账号登录游戏,每个账号都有其数据,选择角色真正进入游戏。
图1-1 单机游戏逻辑
从编码的角度来说,游戏一旦开始,运行的就是一个无限循环(Loop),我们可以认为它是一个while(true){…},除非离开游戏,否则这个循环会一直执行下去。循环的每一次执行称为一帧。在一帧中包括3个主要操作:
(1)检测玩家输入。
(2)根据输入更新内存数据,刷新场景、人物模型和界面。
(3)捕捉退出请求,如果有退出请求,这个循环就会被打破,游戏结束。
理论上来讲,一秒能产生的循环数越大,程序的反应就越灵敏。举例说明,假如输入够快,在0.3秒和0.6秒产生了两个输入,例如触发了两个执行技能请求,如果执行一帧需要0.5秒,在0秒进入第一帧,0.5秒之后才会发现0.3秒的输入,而0.6秒的输入则要等到执行第三帧,也就是1秒的时候才会被发现。假如执行一帧只需要0.1秒,则0.3秒和0.6秒的操作会很快被触发。
单机游戏不需要异步的过程,所有操作可以马上得到答案,不需要等待结果,类似于调用函数的过程。调用之后,函数必定马上会有一个返回值。数据都在本地内存中,方便读取,也方便判断。单机游戏创建角色是在本地进行的,不需要向外部请求数据。加载角色选择界面也不需要谁许可,只要能从本地文件中读到角色,就可以马上进入角色选择界面。而网络游戏在这一点上与单机游戏有很大的区别。
了解了单机游戏的流程之后,再来看看网络游戏。
网络游戏和单机游戏一样也有一个循环,只是多了一个网络层的处理。实际上因为异步的关系,逻辑会变得更为复杂,图1-2充分展示了这种不同。下面以登录为例来展示一下具体的不同之处,流程如图1-3所示。
图1-2 网络游戏逻辑
图1-3 客户端登录逻辑
在登录界面输入账号和密码之后,要经历一个异步的操作,客户端向服务端发送协议,等待服务端返回数据,由此来判断登录成功或者失败。网络游戏的客户端发出命令,只有等到服务端给它结果,它才会做出反应。客户端向服务端请求账号验证,这个请求数据不是一个函数可以完成的,这就是一个异步的过程。
第一个需要了解的概念是“异步”。与“异步”一起出现的概念有“同步”“并行”(并发)等,这几个概念往往比较容易混淆。
举一个加载的例子,如果需要加载几个不同的资源,先加载A,等到A加载完成后再加载B,加载完B,再加载C,直到所有资源加载完成,这就是同步操作。以同步方式实现加载,加载者必须等到加载完成之后才能继续后续的加载。
如果用3个线程同时加载A、B、C资源,由于线程之间是不会相互影响的,加载A的同时另外两个线程在加载B和C,这就是并行操作。但这种情况不能算是异步,因为在加载A时,要等待A加载完成之后退出线程。这个等待产生了阻塞。
那么,什么是异步呢?异步不会等待,也不会阻塞。
假设加载一个资源需要10秒,加载3个资源,在串行时需要30秒,在并行时需要10秒,异步也需要10秒。那么,异步与并行的差别在哪里呢?
以图1-4为例来看一下异步的流程。在第N帧发出了加载A命令,这一帧会马上结束,不需要等待10秒,直接进入下一帧,不关心A是否加载成功,当它加载成功之后,会在某一帧收到加载成功的回调。因为是异步,同时加载A、B时,得到结果的顺序可能是不一样的,可能A先发出加载命令,但是B的回调却先发生。
图1-4 异步加载
那么,程序是如何知道回调完成的呢?一般来说,有两种方式可以知道A是否加载成功:
(1)主动询问,每间隔一段时间询问A是否加载完成。
(2)被动接收,一般在启动事件时会要求注册一个回调函数,事件完成时会主动调用回调函数,以标记事件完成。
所谓异步,简而言之,就是在不阻塞进程的情况下完成操作。
网络游戏大部分情况下都是异步的操作。例如,要分解背包中的一个道具。首先要发起一个分解道具的请求,这个请求从客户端发送到服务端,再把结果从服务端传回到客户端。假设它需要0.5秒,采用非异步的方式需要在发起请求之后等0.5秒,等收到服务端的结果再进行后续操作。
如果按这种方式编写游戏代码,效率是非常低下的。在这0.5秒内,进程将暂停在此处,图形引擎得不到刷新,输入操作在这0.5秒内暂停了,也得不到响应。
为了解决这个问题,需要将功能在这里中断。这意味着向服务端发起请求时,这个分解功能就中断了。当分解道具的协议从服务端传回到客户端时,再进行后续的处理。这就是一个异步的操作。
对于编码来说,单机游戏在一个函数中可以完成的操作需要拆分成两步或者更多步。简而言之,单机游戏和网络游戏的一个根本不同就是后者因为网络层介入而产生的异步。接下来将研究网络,包括数据是如何发送的,又是如何接收的。
课程完整版可前往UWA学堂观看《多人在线游戏架构实战:基于C++的分布式游戏编程》。
本书特色
1、从网络游戏的底层编码开始,深入讲解游戏开发的详细步骤、游戏主循环、线程的使用、Actor模式的应用等。
2、以直观的方式阐述和还原游戏制作的全过程,全面介绍游戏编码过程中众多的核心概念和具体实现,如定时器、对象池、组件编码、架构层的解耦等。
3、使用C++来实现游戏的架构,读者也可以举一反三,使用其他的编程语言轻松实现游戏开发目标。
你将获得
1、充分了解业务逻辑和底层框架的设计意图
2、立足实践的服务端学习思路,深入浅出
3、用实际案例贯穿各知识点,在实践中学习
4、了解商业游戏的设计思路和实现方法