本文就将围绕三个主题来给大家讲述一下网络游戏的网络互连实现方法 |
网络游戏与单机游戏有一个很显著的差别,就是网络游戏除了一个供操作游戏的用户界面平台(如单机游戏)外,还需要一个用于连接所有用户,并为所有用户提供数据服务的服务器,从某些角度来看,游戏服务器就像一个大型的数据库,提供数据以及数据逻辑交互的功能。让我们来看看一个简单的网络游戏模型执行流程:
客户机:
Login()// 登入模块 { 初始化游戏数据; 获取用户输入的用户和密码; 与服务器创建网络连接; 发送至服务器进行用户验证; ... 等待服务器确认消息; ... 获得服务器反馈的登入消息; if( 成立 ) 进入游戏; else 提示用户登入错误并重新接受用户登入; } Game()// 游戏循环部分 { 绘制游戏场景、人物以及其它元素; 获取用户操作输入; 将用户的操作发送至服务器; ... 等待服务器的消息; ... 接收服务器的反馈信息; switch( 服务器反馈的消息数据 ) { case 本地玩家移动的消息: { if( 允许本地玩家移动 ) 客户机处理人物移动; else 客户机保持原有状态; } break; case 其他玩家/NPC的移动消息: { 根据服务器的反馈信息进行其他玩家或者NPC的移动处理; } break; case 新玩家加入游戏: { 在客户机中添加显示此玩家; } break; case 玩家离开游戏: { 在客户机中销毁此玩家数据; } break; ... 其它消息类型处理; ... default: break; } } Exit()// 游戏结束 { 发送离开消息给服务器; ... 等待服务器确认; ... 得到服务器确认消息; 与服务器断开连接; 释放游戏数据; 离开游戏; } |
服务器:
Listen() // 游戏服务器等待玩家连接模块 { ... 等待用户的登入信息; ... 接收到用户登入信息; 分析用户名和密码是否符合; if( 符合 ) { 发送确认允许进入游戏消息给客户机; 把此玩家进入游戏的消息发布给场景中所有玩家; 把此玩家添加到服务器场景中; } else { 断开与客户机的连接; } } Game() // 游戏服务器循环部分 { ... 等待场景中玩家的操作输入; ... 接收到某玩家的移动输入或NPC的移动逻辑输入; // 此处只以移动为例 进行此玩家/NPC在地图场景是否可移动的逻辑判断; if( 可移动 ) { 对此玩家/NPC进行服务器移动处理; 发送移动消息给客户机; 发送此玩家的移动消息给场景上所有玩家; } else 发送不可移动消息给客户机; } Exit() // 游戏服务=器结束 { 接收到玩家离开消息; 将此消息发送给场景中所有玩家; 发送允许离开的信息; 将玩家数据存入数据库; 注销此玩家在服务器内存中的数据; } } |
让我们来说明一下上面简单网络游戏模型的运行机制。先来讲讲服务器端,这里服务器端分为三个部分(实际上一个完整的网络游戏远不止这些):登入模块、游戏模块和登出模块。登入模块用于监听网络游戏客户端发送过来的网络连接消息,并且验证其合法性,然后在服务器中创建这个玩家并且把玩家带领到游戏模块中; 游戏模块则提供给玩家用户实际的应用服务,我们在后面会详细介绍这个部分; 在得到玩家要离开游戏的消息后,登出模块则会把玩家从服务器中删除,并且把玩家的属性数据保存到服务器数据库中,如: 经验值、等级、生命值等。
接下来让我们看看网络游戏的客户端。这时候,客户端不再像单机游戏一样,初始化数据后直接进入游戏,而是在与服务器创建连接,并且获得许可的前提下才进入游戏。除此之外,网络游戏的客户端游戏进程需要不断与服务器进行通讯,通过与服务器交换数据来确定当前游戏的状态,例如其他玩家的位置变化、物品掉落情况。同样,在离开游戏时,客户端会向服务器告知此玩家用户离开,以便于服务器做出相应处理。
以上用简单的伪代码给大家阐述了单机游戏与网络游戏的执行流程,大家应该可以清楚看出两者的差别,以及两者间相互的关系。我们可以换个角度考虑,网络游戏就是把单机游戏的逻辑运算部分搬移到游戏服务器中进行处理,然后把处理结果(包括其他玩家数据)通过游戏服务器返回给连接的玩家。