做游戏网站的话 用哪种服务器比较好的服务器

谈这个话题之前首先要让大家知道,什么是服务器在游戏中,服务器所扮演的角色是同步广播和服务器主动的一些行为,比如说天气NPC AI之类的,之所以现在的很多網络游戏服务器都需要负担一些游戏逻辑上的运算是因为为了防止客户端的作弊行为了解到这一点,那么本系列的文章将分为两部分来談谈网络游戏服务器的设计一部分是讲如何做好服务器的网络连接,同步广播以及NPC的设置,另一部分则将着重谈谈哪些逻辑放在服务器比较合适并且用什么样的结构来安排这些逻辑。

  大多数的网络游戏的服务器都会选择非阻塞select这种结构为什么呢?因为网络游戏嘚服务器需要处理的连接非常之多并且大部分会选择在Linux/Unix下运行,那么为每个用户开一个线程实际上是很不划算的一方面因为在Linux/Unix下的线程是用进程这么一个概念模拟出来的,比较消耗系统资源另外除了I/O之外,每个线程基本上没有什么多余的需要并行的任务而且网络游戲是互交性非常强的,所以线程间的同步会成为很麻烦的问题由此一来,对于这种含有大量网络连接的单线程服务器用阻塞显然是不現实的。对于网络连接需要用一个结构来储存,其中需要包含一个向客户端写消息的缓冲还需要一个从客户端读消息的缓冲,具体的夶小根据具体的消息结构来定了另外对于同步,需要一些时间校对的值还需要一些各种不同的值来记录当前状态,下面给出一个初步嘚连接的结构:

  服务器循环的处理所有连接是一个死循环过程,每次循环都用select检查是否有新连接到达然后循环所有连接,看哪个連接可以写或者可以读就处理该连接的读写。由于所有的处理都是非阻塞的所以所有的Socket IO都可以用一个线程来完成。

  由于网络传输嘚关系每次recv()到的数据可能不止包含一条消息,或者不到一条消息那么怎么处理呢?所以对于接收消息缓冲用了两个指针每次接收都從text_start开始读起,因为里面残留的可能是上次接收到的多余的半条消息然后text_end指向消息缓冲的结尾。这样用两个指针就可以很方便的处理这种凊况另外有一点值得注意的是:解析消息的过程是一个循环的过程,可能一次接收到两条以上的消息在消息缓冲里面这个时候就应该執行到消息缓冲里面只有一条都不到的消息为止,大体流程如下:

  对于消息的处理这里首先就需要知道你的游戏总共有哪些消息,所有的消息都有哪些才能设计出比较合理的消息头。一般来说消息大概可分为主角消息,场景消息同步消息和界面消息四个部分。其中主角消息包括客户端所控制的角色的所有动作包括走路,跑步战斗之类的。场景消息包括天气变化一定的时间在场景里出现一些东西等等之类的,这类消息的特点是所有消息的发起者都是服务器广播对象则是场景里的所有玩家。而同步消息则是针对发起对象是某个玩家经过服务器广播给所有看得见他的玩家,该消息也是包括所有的动作和主角消息不同的是该种消息是服务器广播给客户端的,而主角消息一般是客户端主动发给服务器的最后是界面消息,界面消息包括是服务器发给客户端的聊天消息和各种属性及状态信息

  下面来谈谈消息的组成。一般来说一个消息由消息头和消息体两部分组成,其中消息头的长度是不变的而消息体的长度是可变的,在消息体中需要保存消息体的长度由于要给每条消息一个很明显的区分,所以需要定义一个消息头特有的标志然后需要消息的类型鉯及消息ID。消息头大体结构如下:

  服务器的广播的重点就在于如何计算出广播的对象很显然,在一张很大的地图里面某个玩家在朂东边的一个动作,一个在最西边的玩家是应该看不到的那么怎么来计算广播的对象呢?最简单的办法就是把地图分块,分成大小合適的小块然后每次只象周围几个小块的玩家进行广播。那么究竟切到多大比较合适呢一般来说,切得块大了内存的消耗会增大,切嘚块小了CPU的消耗会增大(原因会在后面提到)。个人觉得切成一屏左右的小块比较合适每次广播广播周围九个小块的玩家,由于广播嘚操作非常频繁那么遍利周围九块的操作就会变得相当的频繁,所以如果块分得小了那么遍利的范围就会扩大,CPU的资源会很快的被吃唍

  切好块以后,怎么让玩家在各个块之间走来走去呢让我们来想想在切换一次块的时候要做哪些工作。首先要算出下个块的周圍九块的玩家有哪些是现在当前块没有的,把自己的信息广播给那些玩家同时也要算出下个块周围九块里面有哪些物件是现在没有的,紦那些物件的信息广播给自己然后把下个块的周围九快里没有的,而现在的块周围九块里面有的物件的消失信息广播给自己同时也把洎己消失的消息广播给那些物件。这个操作不仅烦琐而且会吃掉不少CPU资源那么有什么办法可以很快的算出这些物件呢?一个个做比较顯然看起来就不是个好办法,这里可以参照二维矩阵碰撞检测的一些思路以自己周围九块为一个矩阵,目标块周围九块为另一个矩阵檢测这两个矩阵是否碰撞,如果两个矩阵相交那么没相交的那些块怎么算。这里可以把相交的块的坐标转换成内部坐标然后再进行运算。

  对于广播还有另外一种解决方法实施起来不如切块来的简单,这种方法需要客户端来协助进行运算首先在服务器端的连接结構里面需要增加一个广播对象的队列,该队列在客户端登陆服务器的时候由服务器传给客户端然后客户端自己来维护这个队列,当有人赱出客户端视野的时候由客户端主动要求服务器给那个物件发送消失的消息。而对于有人总进视野的情况则比较麻烦了。

  首先需偠客户端在每次给服务器发送update position的消息的时候服务器都给该连接算出一个视野范围,然后在需要广播的时候循环整张地图上的玩家,找箌坐标在其视野范围内的玩家使用这种方法的好处在于不存在转换块的时候需要一次性广播大量的消息,缺点就是在计算广播对象的时候需要遍历整个地图上的玩家如果当一个地图上的玩家多得比较离谱的时候,该操作就会比较的慢

  同步在网络游戏中是非常重要嘚,它保证了每个玩家在屏幕上看到的东西大体是一样的其实呢,解决同步问题的最简单的方法就是把每个玩家的动作都向其他玩家广播一遍这里其实就存在两个问题:1,向哪些玩家广播广播哪些消息。2如果网络延迟怎么办。事实上呢第一个问题是个非常简单的問题,不过之所以我提出这个问题来是提醒大家在设计自己的消息结构的时候,需要把这个因素考虑进去而对于第二个问题,则是一個挺麻烦的问题大家可以来看这么个例子:

  比如有一个玩家A向服务器发了条指令,说我现在在P1点要去P2点。指令发出的时间是T0服務器收到指令的时间是T1,然后向周围的玩家广播这条消息消息的内容是“玩家A从P1到P2”有一个在A附近的玩家B,收到服务器的这则广播的消息的时间是T2然后开始在客户端上画图,A从P1到P2点这个时候就存在一个不同步的问题,玩家A和玩家B的屏幕上显示的画面相差了T2-T1的时间这個时候怎么办呢?

  有个解决方案我给它取名叫 预测拉扯,虽然有些怪异了点不过基本上大家也能从字面上来理解它的意思。要解決这个问题首先要定义一个值叫:预测误差。然后需要在服务器端每个玩家连接的类里面加一项属性叫latency,然后在玩家登陆的时候对愙户端的时间和服务器的时间进行比较,得出来的差值保存在latency里面还是上面的那个例子,服务器广播消息的时候就根据要广播对象的latency,计算出一个客户端的CurrentTime然后在消息头里面包含这个CurrentTime,然后再进行广播并且同时在玩家A的客户端本地建立一个队列,保存该条消息只箌获得服务器验证就从未被验证的消息队列里面将该消息删除,如果验证失败则会被拉扯回P1点。然后当玩家B收到了服务器发过来的消息“玩家A从P1到P2”这个时候就检查消息里面服务器发出的时间和本地时间做比较如果大于定义的预测误差,就算出在T2这个时间玩家A的屏幕仩走到的地点P3,然后把玩家B屏幕上的玩家A直接拉扯到P3再继续走下去,这样就能保证同步更进一步,为了保证客户端运行起来更加smooth我並不推荐直接把玩家拉扯过去,而是算出P3偏后的一点P4然后用(P4-P1)/T(P4-P3)来算出一个很快的速度S,然后让玩家A用速度S快速移动到P4这样的处理方法是仳较合理的,这种解决方案的原形在国际上被称为(Full plesiochronous)当然,该原形被我篡改了很多来适应网络游戏的同步所以而变成所谓的:预测拉扯。

  另外一个解决方案我给它取名叫 验证同步,听名字也知道大体的意思就是每条指令在经过服务器验证通过了以后再执行动莋。具体的思路如下:首先也需要在每个玩家连接类型里面定义一个latency然后在客户端响应玩家鼠标行走的同时,客户端并不会先行走动洏是发一条走路的指令给服务器,然后等待服务器的验证服务器接受到这条消息以后,进行逻辑层的验证然后计算出需要广播的范围,包括玩家A在内根据各个客户端不同的latency生成不同的消息头,开始广播这个时候这个玩家的走路信息就是完全同步的了。这个方法的优點是能保证各个客户端之间绝对的同步缺点是当网络延迟比较大的时候,玩家的客户端的行为会变得比较不流畅给玩家带来很不爽的感觉。该种解决方案的原形在国际上被称为(Hierarchical

  最后一种解决方案是一种理想化的解决方案在国际上被称为Mutual synchronization,是一种对未来网络的前景的良好预测出来的解决方案这里之所以要提这个方案,并不是说我们已经完全的实现了这种方案而只是在网络游戏领域的某些方面應用到这种方案的某些思想。我对该种方案取名为:半服务器同步大体的设计思路如下:

  首先客户端需要在登陆世界的时候建立很哆张广播列表,这些列表在客户端后台和服务器要进行不及时同步之所以要建立多张列表,是因为要广播的类型是不止一种的比如说囿local message,有remote message,还有global message 等等,这些列表都需要在客户端登陆的时候根据服务器发过来的消息建立好在建立列表的同时,还需要获得每个列表中广播对潒的latency并且要维护一张完整的用户状态列表在后台,也是不及时的和服务器进行同步根据本地的用户状态表,可以做到一部分决策由客戶端自己来决定当客户端发送这部分决策的时候,则直接将最终决策发送到各个广播列表里面的客户端并对其时间进行校对,保证每個客户端在收到的消息的时间是和根据本地时间进行校对过的那么再采用预测拉扯中提到过的计算提前量,提高速度行走过去的方法將会使同步变得非常的smooth。该方案的优点是不通过服务器客户端自己之间进行同步,大大的降低了由于网络延迟而带来的误差并且由于夶部分决策都可以由客户端来做,也大大的降低了服务器的资源由此带来的弊端就是由于消息和决策权都放在客户端本地,所以给外挂提供了很大的可乘之机

  下面我想来谈谈关于服务器上NPC的设计以及NPC智能等一些方面涉及到的问题。首先我们需要知道什么是NPC,NPC需要莋什么NPC的全称是(Non-Player Character),很显然他是一个character,但不是玩家那么从这点上可以知道,NPC的某些行为是和玩家类似的他可以行走,可以战斗可以呼吸(这点将在后面的NPC智能里面提到),另外一点和玩家物件不同的是NPC可以复生(即NPC被打死以后在一定时间内可以重新出来)。其实还有最重要的一点就是玩家物件的所有决策都是玩家做出来的,而NPC的决策则是由计算机做出来的所以在对NPC做何种决策的时候,需偠所谓的NPC智能来进行决策

  下面我将分两个部分来谈谈NPC,首先是NPC智能其次是服务器如何对NPC进行组织。之所以要先谈NPC智能是因为只有當我们了解清楚我们需要NPC做什么之后才好开始设计服务器来对NPC进行组织。

  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的异步刷新在节省服务器资源的同时也让玩家觉得更加的真实。

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

  其主要思路是在广度优先搜索的同时,将下一层的所有节点经过一个启发函數进行过滤一定范围内缩小搜索范围。众所周知的寻路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智能相关的时候已经接触到一些脚本相关的东东了還是先来谈谈脚本的作用吧。

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

4.1、服务器内存管理

  对于服务器内存管理我们将采用内存池的方法也称为静态内存管理。其概念为在服务器初始化的时候申请一塊非常大的内存,称为内存池(Memory pool)同时也申请一小块内存空间,称为垃圾回收站(Garbage recollecting station)其大体思路如下:当程序需要申请内存的时候,艏先检查垃圾回收站是否为空如果不为空的话,则从垃圾回收站中找一块可用的内存地址在内存池中根据地址找到相应的空间,分配給程序用如果垃圾回收站是空的话,则直接从内存池的当前指针位置申请一块内存;当程序释放空间的时候给那块内存打上已经释放掉的标记,然后把那块内存的地址放入垃圾回收站
  下面具体谈谈该方法的详细设计,首先我们将采用类似于操作系统的段页式系統来管理内存,这样的好处是可以充分的利用内存池其缺点是管理起来比较麻烦。嗯下面来具体看看我们怎么样来定义页和段的结构:

  那么内存池和垃圾回收站怎么构建呢?下面也给出一些构建相关的伪代码:

  下面看看垃圾回收站怎么设计:

  也许这样的贴玳码会让大家觉得很不明白嗯,我的代码水平确实不怎么样那么下面我来用文字方式来叙说一下大体的概念吧。对于段页式内存管理首先分成N个页面,这个是固定的而对于每个页面内的段则是动态的,段的大小事先是不知道的那么我们需要回收的不仅仅是页面的內存,还包括段的内存那么我们就需要一个二维数组来保存是哪个页面的那块段的地址被释放了。然后对于申请内存的时候则首先检查需要申请内存的大小,如果不够一个页面大小的话则在垃圾回收站里面寻找可用的段空间分配,如果找不到则申请一个新的页面空間。
  这样用内存池的方法来管理整个游戏世界的内存可以有效的减少内存碎片一定程度的提高游戏运行的稳定性和效率。

4.2、游戏中粅件的寻址

  第一个问题我们为什么要寻址?加入了脚本语言的概念之后游戏中的一些逻辑物件,比如说NPC某个ITEM之类的都是由脚本語言在游戏运行的过程中动态生成的,那么我们通过什么样的方法来对这些物件进行索引呢说得简单一点,就是如何找到他们呢有个佷简单的方法,全部遍历一次当然,这是个简单而有效的方法但是效率上的消耗是任何一台服务器都吃不消的,特别是在游戏的规模仳较大之后

  那么,我们怎么来在游戏世界中很快的寻找这些物件呢我想在谈这个之前,说一下Hash Table这个数据结构它叫哈希表,也有囚叫它散列表其工作原理是不是顺序访问,也不是随机访问而是通过一个散列函数对其key进行计算,算出在内存中这个key对应的value的地址洏对其进行访问。好处是不管面对多大的数据只需要一次计算就能找到其地址,非常的快捷那么弊端是什么呢?当两个key通过散列函数計算出来的地址是同一个地址的时候麻烦就来了,会产生碰撞其的解决方法非常的麻烦,这里就不详细谈其解决方法了否则估计再寫个四,五章也未必谈得清楚不过如果大家对其感兴趣的话,欢迎讨论

  嗯,我们将用散列表来对游戏中的物件进行索引具体怎麼做呢?首先在内存池中申请一块两倍大于游戏中物件总数的内存,为什么是两倍大呢防止散列表碰撞。然后我们选用物件的名称作為散列表的索引key然后就可以开始设计散列函数了。下面来看个例子:

  具体的算法就不说了上面的那一大段东西不要问我为什么,這个算法的出处是CACM 33-6中的一个叫Peter K.Pearson的鬼子写的论文中介绍的算法据说速度非常的快。有了这个散列函数我们就可以通过它来对世界里面的任意物件进行非常快的寻址了。

  在设计脚本语言之前我们首先需要明白,我们的脚本语言要实现什么样的功能否则随心所欲的做丅去写出个C的解释器之类的也说不定。我们要实现的功能只是简单的逻辑判断和循环其他所有的功能都可以由事先提供好的函数来完成。嗯这样我们就可以列出一张工作量的表单:设计物件在底层的保存结构,提供脚本和底层间的访问接口设计支持逻辑判断和循环的解释器。

  下面先来谈谈物件在底层的保存结构具体到每种不同属性的物件,需要采用不同的结构当然,如果你愿意的话你可以所有的物件都采同同样的结构,然后在结构里面设计一个散列表来保存各种不同的属性但这并不是一个好方法,过分的依赖散列表会让伱的游戏的逻辑变得繁杂不清所以,尽量的区分每种不同的物件采用不同的结构来设计但是有一点值得注意的是,不管是什么结构囿一些东西是统一的,就是我们所说的物件头那么我们怎么来设计这样一个物件头呢?

  其中name是在散列表中这个物件的索引号prog则是腳本解释器需要解释的程序内容。下面我们就以NPC为例来设计一个结构:

  OK结构设计完成,那么我们怎么来设计脚本解释器呢这里有兩种法,一种是用虚拟机的模式来解析脚本语言另外一中则是用类似汇编语言的那种结构来设计,设置一些条件跳转和循环就可以实现邏辑判断和循环了比如:

  这种脚本结构就类似CPU的指令的结构,一条一条指令按照顺序执行对于脚本程序员(Script. Programmer)也可以培养他们汇編能力的说。

  那么怎么来模仿这种结构呢我们拿CPU的指令做参照,首先得设置一些寄存器CPU的寄存器的大小和数量是受硬件影响的,泹我们是用内存来模拟寄存器所以想要多大,就可以有多大然后提供一些指令,包括四则运算寻址,判断循环等等。接下来针对鈈同的脚本用不同的解析方法比如说对NPC就用NPC固定的脚本,对ITEM就用ITEM固定的脚本解析完以后就把结果生成底层该物件的结构用于使用。

  而如果要用虚拟机来实现脚本语言的话呢则会将工程变得无比之巨大,强烈不推荐使用不过如果你想做一个通用的网络游戏底层的話,则可以考虑设计一个虚拟机虚拟机大体的解释过程就是进行两次编译,第一次对关键字进行编译第二次生成汇编语言,然后虚拟機在根据编译生成的汇编语言进行逐行解释如果大家对这个感兴趣的话,可以去上下载一份MudOS的原码来研究研究

本人6年手游从业经验一直从事遊戏服务端工作,现任公司架构师

普通的游戏服务端程序员每天具体干什么?

1. 上午开会听需求案:这尼玛策划脑洞太大了这么一个小功能实现成本太高,你想的这案子根本不好玩吧!我是玩家我都觉得无聊! ——跟策划撕逼

2. 下午根据需求案与前端沟通设计接口:哎这蔀分数据我已经在那个XXX接口传给过你了,你干嘛又要传一遍神马?你说这样你方便展示拜托,从我们后端角度想想好伐 ——跟前端撕逼

3. 晚上加班功能提测:我靠,这你也找我这明显是前端表现的问题,我传的数据没错! ——跟测试、前端撕逼

4. 夜里睡觉被电话吵醒:什么线上出事故了?有接口能刷资源论坛里还有截图?你确定截图不是PS的我写的代码是经过测试的!有BUG也是他们没测出来! ——跟運营,测试撕逼

没错后端唯一看的顺眼的就是美术团队,啧啧看人那妹子才叫妹子,姑娘画啥呢?哎你这个黄色用得好啊,我觉嘚你有艺术家的气质~~

====抖机灵结束正经答题,说说我对新人的一些建议====

首先做游戏大的方向是确定自己的要做客户端还是服务端根据自巳的兴趣来

从技术上来说,并没有高低优劣之分客户端做深了做到引擎级别,图形图像算法兼容性,内存优化等层面当你成为这一方面的领域专家,工资方面一样不会亏待你但更像是吃青春饭的行业,原因后面会细说

服务端呢就像你所说的主要的价值含量在高并發,高负载高可用,这些架构层面的东西对每个大规模并发的应用来说都是必不可少的你已经有了一定认识,这方便我就不再细讲

客戶端和服务器从技术发展层面来说一个比较重要的区别是客户端技术更新迭代较快,今天是cocos2dx明天就是u3d,后天可能是就是VR了如果你具備较强的学习能力和时间,做客户端应用其实更能体现你的价值(需要学的东西更多)相比而言,服务端其实更为稳定优势在于,技術的更新迭代没有客户端那么快同时将来你有一天不想做游戏了,转行其他互联网服务比如传统的B/S应用,那么你所积累的知识70%~80%还是用嘚上的

虽然上述描绘的蓝图很美丽,但其实不论你是做客户端还是服务端只要你是给人打工,那么做什么并不是由你决定的

君不见伱做了多么高大上的架构,然而游戏测试数据不好项目被砍根本没有机会上线来验证你的服务器架构,承载能力伸缩扩展性。

君不见伱做2d游戏做的很熟了想做3d对不起公司没有3d项目,你继续做你的2d去

另一方面,你所做的游戏承载了多少用户代表你面临着多大的挑战,也代表着你需要处理多大的问题即你水平的提升空间。举个例子你在小公司做一个平时几百并发在线的2D卡牌游戏,和你再腾讯做5000wDAU的3DMOBA迋者荣耀那么无论从服务器架构到客户端表现甚至美术原画细节上,需要考虑的问题都是天差地别的所以有些人运气不好在小公司打笁几年不管是水平还是薪资待遇都是原地踏步,而有些实习生一毕业进入大公司的大项目学习成长各方面都很快。

做游戏还有一点比较坑的地方在于你所在公司的管理体系如何,你的价值如何体现。一般的游戏公司项目组都是制作人制度即制作人说了算,也是你的直接領导决定着你的升职加薪,而制作人往往是策划出身他们更多关注的是“看得见”的功能性需求,你今天完成了几个游戏模块写的玳码有多少BUG,你加班加了多少h这些是他们能够认知的范畴,至于你说提底层优化了多少性能做了什么高可用架构,使得服务器稳定运荇了多少天excuse me? 这不是你应该的吗 也就是说真正能够代表你价值技术含量的东西在制作人那里往往是不被重视的,当然这种情况在其他技术岗位也是普遍存在的所以还是看你的公司体系,看你的领导

综上所述,不管是从技术成长角度还是公司管理角度作为新人,都建议你先去正规的大公司学习积累

再说说游戏行业的好处互联网拼的是流量经济,而流量需要变现还有比游戏更好的变现渠道吗?没錯去看看新闻,不论是王者荣耀还是阴阳师项目组一年的奖金有多少,努力+运气当你具备这两者,那么行业的回报还是相当不错的当然死了的项目也是不计其数,那么如何能拥有好的运气看看appstore畅销榜排名前10的游戏都是出自哪家,没错去大公司做大IP项目游戏可以顯著提高你的成功概率。。

最后作为一个新人,不论是游戏行业还是任何其他行业都一样先端正你的态度,工作不要挑肥拣瘦先紦领导交给你的工作哪怕是没有任何技术含量的重复性劳动做好做到极致,让领导对你产生足够的信任同时保持自己的主观能动性和学習能力,再去申请更多更有技术含量的工作不要一上来就好高骛远,整天想着搞一些高大上的东西

希望回答能对你有帮助,以上

我要回帖

更多关于 比较好的服务器 的文章

 

随机推荐