游戏架构 游戏架构设计(3)

游戏架构 游戏架构设计(3),第1张

原文地址: https://blog.csdn.net/erlib/article/details/24301303

NPC智能分为两种,一种是被动触发的事件,一种是主动触发的事件。对于被动触发的事件,处理起来相对来说简单一些,可以由事件本身来呼叫NPC身上的函数,比如说NPC的死亡,实际上是在NPC的HP小于一定值的时候,来主动呼叫NPC身上的OnDie() 函数,这种由事件来触发NPC行为的NPC智能,我称为被动触发。这种类型的触发往往分为两种:

一种是由别的物件导致的NPC的属性变化,然后属性变化的同时会导致NPC产生一些行为。由此一来,NPC物件里面至少包含以下几种函数:

这是一个基本的NPC的结构,这种被动的触发NPC的事件,我称它为NPC的反射。但是,这样的结构只能让NPC被动的接收一些信息来做出决策,这样的NPC是愚蠢的。那么,怎么样让一个NPC能够主动的做出一些决策呢?这里有一种方法:呼吸。那么怎么样让NPC有呼吸呢?

一种很简单的方法,用一个计时器,定时的触发所有NPC的呼吸,这样就可以让一个NPC有呼吸起来。这样的话会有一个问题,当NPC太多的时候,上一次NPC的呼吸还没有呼吸完,下一次呼吸又来了,那么怎么解决这个问题呢。这里有一种方法,让NPC异步的进行呼吸,即每个NPC的呼吸周期是根据NPC出生的时间来定的,这个时候计时器需要做的就是隔一段时间检查一下,哪些NPC到时间该呼吸了,就来触发这些NPC的呼吸。

上面提到的是系统如何来触发NPC的呼吸,那么NPC本身的呼吸频率该如何设定呢?这个就好象现实中的人一样,睡觉的时候和进行激烈运动的时候,呼吸频率是不一样的。同样,NPC在战斗的时候,和平常的时候,呼吸频率也不一样。那么就需要一个Breath_Ticker来设置NPC当前的呼吸频率。

那么在NPC的呼吸事件里面,我们怎么样来设置NPC的智能呢?大体可以概括为检查环境和做出决策两个部分。首先,需要对当前环境进行数字上的统计,比如说是否在战斗中,战斗有几个敌人,自己的HP还剩多少,以及附近有没有敌人等等之类的统计。统计出来的数据传入本身的决策模块,决策模块则根据NPC自身的性格取向来做出一些决策,比如说野蛮型的NPC会在HP比较少的时候仍然猛扑猛打,又比如说智慧型的NPC则会在HP比较少的时候选择逃跑。等等之类的。

至此,一个可以呼吸,反射的NPC的结构已经基本构成了,那么接下来我们就来谈谈系统如何组织让一个NPC出现在世界里面。

这里有两种方案可供选择,其一:NPC的位置信息保存在场景里面,载入场景的时候载入NPC。其二,NPC的位置信息保存在NPC身上,有专门的事件让所有的NPC登陆场景。这两种方法有什么区别呢?又各有什么好坏呢?

前一种方法好处在于场景载入的时候同时载入了NPC,场景就可以对NPC进行管理,不需要多余的处理,而弊端则在于在刷新的时候是同步刷新的,也就是说一个场景里面的NPC可能会在同一时间内长出来。而对于第二种方法呢,设计起来会稍微麻烦一些,需要一个统一的机制让NPC登陆到场景,还需要一些比较麻烦的设计,但是这种方案可以实现NPC异步的刷新,是目前网络游戏普遍采用的方法,下面我们就来着重谈谈这种方法的实现:

首先我们要引入一个“灵魂”的概念,即一个NPC在死后,消失的只是他的肉体,他的灵魂仍然在世界中存在着,没有呼吸,在死亡的附近漂浮,等着到时间投胎,投胎的时候把之前的所有属性清零,重新在场景上构建其肉体。那么,我们怎么来设计这样一个结构呢?首先把一个场景里面要出现的NPC制作成图量表,给每个NPC一个独一无二的标识符,在载入场景之后,根据图量表来载入属于该场景的NPC。在NPC的OnDie() 事件里面不直接把该物件destroy 掉,而是关闭NPC的呼吸,然后打开一个重生的计时器,最后把该物件设置为invisable。这样的设计,可以实现NPC的异步刷新,在节省服务器资源的同时也让玩家觉得更加的真实。

(这一章节已经牵扯到一些服务器脚本相关的东西,所以下一章节将谈谈服务器脚本相关的一些设计)

补充的谈谈启发式搜索(heuristic searching)在NPC智能中的应用。

其主要思路是在广度优先搜索的同时,将下一层的所有节点经过一个启发函数进行过滤,一定范围内缩小搜索范围。众所周知的寻路A 算法就是典型的启发式搜索的应用,其原理是一开始设计一个Judge(point_t point)函数,来获得point这个一点的代价,然后每次搜索的时候把下一步可能到达的所有点都经过Judge()函数评价一下,获取两到三个代价比较小的点,继续搜索,那些没被选上的点就不会在继续搜索下去了,这样带来的后果的是可能求出来的不是最优路径,这也是为什么A 算法在寻路的时候会走到障碍物前面再绕过去,而不是预先就走斜线来绕过该障碍物。如果要寻出最优化的路径的话,是不能用A 算法的,而是要用动态规划的方法,其消耗是远大于A*的。

那么,除了在寻路之外,还有哪些地方可以应用到启发式搜索呢?其实说得大一点,NPC的任何决策都可以用启发式搜索来做,比如说逃跑吧,如果是一个2D的网络游戏,有八个方向,NPC选择哪个方向逃跑呢?就可以设置一个Judge(int direction)来给定每个点的代价,在Judge里面算上该点的敌人的强弱,或者该敌人的敏捷如何等等,最后选择代价最小的地方逃跑。下面,我们就来谈谈对于几种NPC常见的智能的启发式搜索法的设计:

首先获得地图上离该NPC附近的敌人列表。设计Judge() 函数,根据敌人的强弱,敌人的远近,算出代价。然后选择代价最小的敌人进行主动攻击。

在呼吸事件里面检查自己的HP,如果HP低于某个值的时候,或者如果你是远程兵种,而敌人近身的话,则触发逃跑函数,在逃跑函数里面也是对周围的所有的敌人组织成列表,然后设计Judge() 函数,先选择出对你构成威胁最大的敌人,该Judge() 函数需要判断敌人的速度,战斗力强弱,最后得出一个主要敌人,然后针对该主要敌人进行路径的Judge() 的函数的设计,搜索的范围只可能是和主要敌人相反的方向,然后再根据该几个方向的敌人的强弱来计算代价,做出最后的选择。

这个我并不推荐用A*算法,因为NPC一旦多起来,那么这个对CPU的消耗是很恐怖的,而且NPC大多不需要长距离的寻路,只需要在附近走走即可,那么,就在附近随机的给几个点,然后让NPC走过去,如果碰到障碍物就停下来,这样几乎无任何负担。

这里有两种方法,一种方法NPC看上去比较愚蠢,一种方法看上去NPC比较聪明,第一种方法就是让NPC跟着目标的路点走即可,几乎没有资源消耗。而后一种则是让NPC在跟随的时候,在呼吸事件里面判断对方的当前位置,然后走直线,碰上障碍物了用A*绕过去,该种设计会消耗一定量的系统资源,所以不推荐NPC大量的追随目标,如果需要大量的NPC追随目标的话,还有一个比较简单的方法:让NPC和目标同步移动,即让他们的速度统一,移动的时候走同样的路点,当然,这种设计只适合NPC所跟随的目标不是追杀的关系,只是跟随着玩家走而已了。

在这一章节,我想谈谈关于服务器端的脚本的相关设计。因为在上一章节里面,谈NPC智能相关的时候已经接触到一些脚本相关的东东了。还是先来谈谈脚本的作用吧。

在基于编译的服务器端程序中,是无法在程序的运行过程中构建一些东西的,那么这个时候就需要脚本语言的支持了,由于脚本语言涉及到逻辑判断,所以光提供一些函数接口是没用的,还需要提供一些简单的语法和文法解析的功能。其实说到底,任何的事件都可以看成两个部分:第一是对自身,或者别的物件的数值的改变,另外一个就是将该事件以文字或者图形的方式广播出去。那么,这里牵扯到一个很重要的话题,就是对某一物件进行寻址。恩,谈到这,我想将本章节分为三个部分来谈,首先是服务器如何来管理动态创建出来的物件(服务器内存管理),第二是如何对某一物件进行寻址,第三则是脚本语言的组织和解释。其实之所以到第四章再来谈服务器的内存管理是因为在前几章谈这个的话,大家对其没有一个感性的认识

1-技术有什么区别

首先通信上目前的主流是HTTP协议和SOCKET这两种(HTML5提供了一种新的协议,WebScoket,对此了解并不多,因此不做评论,以免误导)。

HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。

(注:在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。)

Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。

以J2SDK-1.3为例,Socket和ServerSocket类库位于http://java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。(摘自百科)

在WEB服务器中,一般情况是只需要使用HTTP协议的。因为它不太需要去与浏览器进行主动推送,只需要响应浏览器的访问就足够了

而在游戏服务器,这样的连接方式肯定是不够用的。很多时候游戏服务器是需要主动推送消息,如系统广播。

2-思维有什么区别

WEB服务器并不需要高频即时通讯,对响应速度要求不高。而游戏服务器,大多数是需要很及时的响应速度(暂不讨论弱联网游戏)。如DOTA,这种竞技类型的游戏,1秒就能发生很多事。

因此,在思考方向上,WEB服务器应该考虑是的多平台的兼容,大量用户访问的高并发。

而游戏服务器应该考虑的是高频通讯,高并发。

3-架构的侧重点有什么区别

在架构上面,一般访问量不是很大的网站是只有一台服务器的,访问量高的才会进行分布式设计或者集群设计。

而大部分游戏服务器都是需要分布式设计的。

在现有的网络游戏服务器端架构中,多是以功能和场景来划分服务器结构的。具体的划分是根据项目的需求进行的,并没有一个十分通用的架构。

以上是比较常见的结构,客户端登录的时候,连接GateServer,然后由GateServer去连接LoginServer进行登录。登录后通过CenterServer转发到GameServer(GameServer即是服务器大区)。

而其中的DCServer,主要的功能是缓存玩家角色数据,保证角色数据能快速的读取和保存。

LogServer便是保存日志的了。

4-本质有无区别

本质上,两者并无区别,只是需求不同,侧重点不同罢了。


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/260589.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-16
下一篇2023-04-16

发表评论

登录后才能评论

评论列表(0条)

    保存