GJM : Unity3D - NetWork - Hight Level API ( HLAPI) [转载]
介绍
在本系列教程中,我们将使用的网络高级API(HLAPI)来构建一个小型的多人网络案例。即使我们的例子很简单,但也会涵盖以下关键概念,这应该可以帮助大家使用HLAPI构建大型游戏项目。
- 在第一部分,我们将使用NetworkBehaviours,SyncVars和Commands来介绍客户端和服务器之间的通信。
- 在第二部分,我们将实现客户端预测和服务器同步。
- 在第三部分,我们将快速看看服务通道质量希望通过尽量保持项目精简,可以很容易的提炼并理解教程演示的网络原理,从而可以将这些概念应用到你自己的游戏中。
预备知识
需要熟悉基本概念。具体来说就是知道MonoBehaviour是什么,以及与GameObject的关系,并且知道里面诸如Awake、Start、Update之类的事件函数是如何及何时被调用的。不了解Unity Networking也没关系。
我们的实现是基于Gabriel Gambetta在他的系列文章Fast-Paced Multiplayer(快节奏多人游戏)中所描述的架构。引用了他系列文章的第二篇来理解如何在项目中实现客户端预测和服务器同步。
应该说这篇文章基本来自Unity文档《将单人游戏转换为多人游戏》的附加说明。想尽快上手HLAPI的开发者可以看看这个文档。也可将其作为HLAPI的使用指南。
项目文件可以在文末下载。项目大部分由自定义的MonoBehaviour驱动,并且它带上空白行也只有115行。建议下载示例工程,以查看所有代码并实际运行,再学习本文就可以更好的理解整个工作原理。
开工我们先创建一个Cube,可以用方向键控制它从一个网格位置移动到另一个。
用结构体存储Cube的当前位置:
[C#] 纯文本查看 复制代码12345structCubeState {publicintx;publicinty;}CubeState state;在Awake函数里设置Cube的初始位置:
[C#] 纯文本查看 复制代码123456789voidAwake () {InitState();}voidInitState () {state =newCubeState {x = 0,y = 0};}大部分工作在Update函数中去做,这里简单检测方向键按下并做出相应动作:
[C#] 纯文本查看 复制代码0102030405060708091011voidUpdate () {KeyCode[] arrowKeys = {KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.RightArrow, KeyCode.LeftArrow};foreach(KeyCode arrowKeyinarrowKeys) {if(!Input.GetKeyDown(arrowKey))continue;state = Move(state, arrowKey);}SyncState();}voidSyncState () {transform.position =newVector2(state.x, state.y);}如果方向键真的被按下,就用Move函数计算Cube的新网格位置,这个函数将Cube的前一个网格位置和方向键作为参数,并返回Cube的新网格位置:
[C#] 纯文本查看 复制代码010203040506070809101112131415161718192021CubeState Move(CubeState previous, KeyCode arrowKey) {intdx = 0;intdy = 0;switch(arrowKey) {caseKeyCode.UpArrow:dy = 1;break;caseKeyCode.DownArrow:dy = -1;break;caseKeyCode.RightArrow:dx = 1;break;caseKeyCode.LeftArrow:dx = -1;break;}returnnewCubeState {x = dx + previous.x,y = dy + previous.y};}现在只是简单的使用了Unity的非多人游戏的基础特性。希望大家都比较熟悉。否则建议大家先熟悉Unity基础,然后再回到本文学习如何使用用Unity做多人游戏。下面来添加多玩家功能。
总览观察网络模拟工作方式的一种办法是,将场景作为被多位玩家共享的场景。在这种设置下,每个玩家被分配一个独有的GameOject。在本例子中,我们将为各连接上的玩家分配一个Cube。接下来就要试着解决以下问题:
1.怎样在玩家间建立链接?
2.怎样将多个Cube实例化给在线玩家?
3.服务器如何保持所有在线玩家的内容一致?
4.玩家如何告知服务器Cube要移动了?
建立链接
HLAPI遵循CS架构,这意味着机器间不能直接相连,而是将一台机器作为服务器,所以其他机器作为客户端连接到服务器。服务器同时也能作为客户端使用,所以不需要有一个专用服务器(尽管这也可行)。我们将建立工程,它可能运行在单服务器模式下或者同时作为客户端和服务端(也被称作主机模式)。
记住,在Unity中,功能是由GameObject结合它带有的Component决定的。我们遵循这点来实现服务器或者客户端。
1.创建一个空的GameObject。命名为“NetworkManger”。
2.添加NetworkManager 组件。这个组件提供了一个简单控制HLAPI的方式。
3.添加NetworkManagerHUD 组件。这个组件提供了一个基本的控制NetworkManger的UI。
搞定了!用HLAPI很容易将项目作为服务器启动或者作为客户端链接到服务器。
为客户端分配玩家游戏物体
目前为止,尽管连接已经建立,但还没有内容。当一个玩家连接时,我们想要实例化一个Cube并让玩家可以控制这个Cube。使用Player Object来实现:
1.首先,为已经存在的Cube游戏对象并为它添加NetworkIdentity 组件。这会告诉HLAPI要处理这个游戏物体的网络方面。
2.将这个游戏对象转换为预制件。
3.将这个预制件赋给NetworkManger的“Player Prefab”字段。
4.如果Cube还留在场景中,删掉它。一个新玩家链接时会自动创建一个Cube实例。因为Cube带有NetworkIdentity组件,HLAPI也会知道这是一个网络游戏对象,这将使得同样的Cube会被实例化到所有链接的客户端。
跨机器同步MonoBehavior
如果之前没有做过网络游戏,你可能认为给一个GameObject添加NetworkIdentity组件不会自动同步到网络中的所有其它客户端。在我看来,不自动同步真的是一件好事,因为不同游戏有不同的需求,并且控制同步和不允许的内容可以让游戏性能更好,某些情况下甚至可以让游戏设计更灵活。
用HLAPI在网络上同步MonoBehaviour的数据也很简单:
1.子类NetworkBehaviour代替了MonoBehaviour。NetworkBehaviour是基于MonoBehaviour并添加了可以在客户端和服务端传输数据的功能。做一点很简单的改变即可,将:[C#] 纯文本查看 复制代码publicclassCubePlayer : MonoBehaviour变为:
[C#] 纯文本查看 复制代码publicclassCubePlayer : NetworkBehaviour通过使用NetworkBehaviour,就可以在代码里使用HLAPI的数据传输功能。
2.用SyncVar 属性将成员变量标记为要被同步的。这里我们只需要将:[C#] 纯文本查看 复制代码CubeState state;变成:
[C#] 纯文本查看 复制代码[SyncVar] CubeState state;通过标记变量为SyncVar,这个变量值在服务器上的任何更新都会广播到所有已链接的客户端。只要确保SyncVars 的所有改变是由服务端产生即可。
限制输入
到这里,如果运行工程,就会看到当按下方向键,屏幕上的所有的Cube都响应输入,这不是我们希望的,只要自己的Cube能响应输入即可。为了更正这点,只需在Update函数中做一个细微的调整,如下:[C#] 纯文本查看 复制代码12345voidUpdate () {if(isLocalPlayer) {// handle input here...}SyncState();}isLocalPlayer变量告诉我们处理的玩家物体是否是自己的。如果不是,将忽略任何输入;如果是,就移动cube。
控制Cube
“跨机器同步MonoBehaviour”部分的最后一句话留下了十分重要的线索,下一步应该做什么。为了让SyncVars 生效,它们应该从服务器上更新。但现在的代码不是如此:
1.只要有方向键被按下,每个客户端直接更新被标记为SyncVar的变量。
2.只有主机的更新传播到所有链接的客户端,实际上忽略了任何其它人的更新。
记住SyncVar只能被服务器修改,所以我们要做的是:
1.当客户端的方向键按下,客户端应该告诉服务器方向键被按下了。
2.反过来,服务器应该根据收到的输入更新SyncVar。
3.因为SyncVar由服务器更新,所有的变化都被正确的传递到所有链接的客户端上。
HLAPI给我们提供了一个从客户端调用服务器函数的方法,使用Commands。可将已经存在的函数转换为Commands,通过如下方式标记它们(与将变量标记为SyncVar类似):
1.添加Command属性。
2.在函数名前添加Cmd前缀。
例如,这个函数:[C#] 纯文本查看 复制代码12voidMoveOnServer (KeyCode arrowKey) {state = Move(state, arrowKey);}这样就能将函数变成一个Command:
[C#] 纯文本查看 复制代码[Command]voidCmdMoveOnServer (KeyCode arrowKey) {/* ... */}一旦有了Command,就能像调用其它函数一样调用这个函数,但是因为它被标记为Command,所以在客户端调用函数里的代码将运行在服务器上。回到例子,只需将Update函数里的如下行:
[C#] 纯文本查看 复制代码state = Move(state, arrowKey);变成:
[C#] 纯文本查看 复制代码CmdMoveOnServer(arrowKey);只需做些简单的改变,就能在服务器上执行函数了,现在SyncVar现在被正确更新了。
注意,Command只能被你自己的Player Object调用,这防止了一个客户端接管其它客户端的控制。在服务器端确保了是谁在调用函数,这将帮助我们确保多玩家网络游戏的安全。
仅服务器调用的函数
[Server] void InitState () { /* ... */ }
在教程结束前,再看一下Awake 函数,只有一行代码就是调用InitState。为了让Demo理想运行,需要确保这个初始化只在服务器上运行而不能在客户端。方式是标记InitState作为一个仅服务端调用的函数。还好用HLAPI很容易做到这点。我们要做的就是标记函数为Server属性,如下:[C#] 纯文本查看 复制代码[Server]voidInitState () {/* ... */}如果在服务器/主机下调用InitState,它就能正常运行。否则,调用会被忽略。
下一步
运行Demo,你可能会注意到当试着控制Cube的时候,按下按键和到盒子在屏幕上移动之间有延迟。因为从客户端发送按键信息到服务器要花费一些时间,并且从服务端发送Cube的状态信息还要花费更多时间。
Demo 下载地址 链接:http://pan.baidu.com/s/1qXYUQuS 密码:kizt - 原文链接:http://www.gamasutra.com/blogs/C ... ucing_the_HLAPI.php
- 原文作者:Christian Arellano
转载自:http://www.manew.com/forum.php?mod=viewthread&tid=45981&extra=page%3D1&page=1 - 如遇版权问题 请联系我 993056011@qq.com
GJM : Unity3D - NetWork - Hight Level API ( HLAPI) [转载]的更多相关文章
- GJM : Unity3D HIAR 目录导航
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- Unity Networking API文档翻译(二):The High Level API
高级API (HLAPI) 是用来提供给Unity 创建多人在线游戏的组件.它是在底层传输层的基础上构建的, 对多人在线游戏提供了很多通用的功能.当传输层支持各种网络拓扑结构的时候,HLAPI是一个功 ...
- GJM : Unity3D - UI - UI边缘流光特效小技巧 [转载]
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- GJM: Unity3D AssetBundle 手记 [转载]
这篇文章从AssetBundle的打包,使用,管理以及内存占用各个方面进行了比较全面的分析,对AssetBundle使用过程中的一些坑进行填补指引以及喷! AssetBundle是Unity推荐的 ...
- GJM: Unity3D基于Socket通讯例子 [转载]
首先创建一个C# 控制台应用程序, 直接服务器端代码丢进去,然后再到Unity 里面建立一个工程,把客户端代码挂到相机上,运行服务端,再运行客户端. 高手勿喷!~! 完全源码已经奉上,大家开始研究吧! ...
- Appium+python自动化8-Appium Python API【转载】
前言: Appium Python API全集,不知道哪个大神整理的,这里贴出来分享给大家. 1.contexts contexts(self): Returns the contexts withi ...
- GJM : Unity3D HIAR -【 快速入门 】 五、导出 Android 工程、应用
导出 Android 工程.应用 在开始之前,请务必先保存您的工程,同时确认您已经安装 Android SDK 和 JDK.安装操作请参考以下链接: 搭建开发环境 Step 1. 设置 Android ...
- 如何设计一个优秀的API(转载)
最近在整理框架的一些 API,觉得很有必要总结一下 API 兼容性的设计.下图是我自己当下的一些总结,慢慢维护: 网上搜索了一下,一个多月前,“标点符”已经发布了下面这篇文章,觉得写得非常不错,转载于 ...
- GJM:Unity导入百度地图SDK [转载]
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
随机推荐
- HTML5 的 localStorage(本地数据库) 的用法
判断浏览器是否支持localStorage可以使用下面的代码:if(window.localStorage){ alert("支持localStorage") }else{ ...
- 使用python原生的方法实现发送email
使用python原生的方法实现发送email import smtplib from email.mime.text import MIMEText from email.mime.multipart ...
- linker command failed with exit code 1 (use -v to see invocation)
背景:用U盘从另一台电脑考过来后,出现错误 linker command failed with exit code 1 (use -v to see invocation) 出现这种情况很可能是,项 ...
- javascript中可变值与不可变值(原始值)
字符串原始值修改不了1 var str = "abc"; 2 str[0] = "d"; 3 console.log(str[1]="f") ...
- struts2结果(Result)
一.结果(result)类型 result的type属性默认为dispatcher,其他常见的属性有redirect\chain\redirectAction <action name=&quo ...
- 后端码农谈前端(CSS篇)第四课:选择器补充(伪类与伪元素)
一.伪类: 属性 描述 :active 向被激活的元素添加样式. :focus 向拥有键盘输入焦点的元素添加样式. :hover 当鼠标悬浮在元素上方时,向元素添加样式. :link 向未被访问的链接 ...
- JS实现单击按钮后弹出新的窗口页面
点击按钮后,弹出指定大小的页面窗口. 效果图: 源码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&qu ...
- WCF会话(Session)与实例(Instance)管理
一.理解Session 1.Session的作用:保留Client和Service之间交互的状态,确保Client与Service之间交互唯一性(SessionId),即:多个Client同时访问Se ...
- JS魔法堂:被玩坏的innerHTML、innerText、textContent和value属性
一.前言 由于innerText并非W3C标准属性,因此我们无法在FireFox中使用它(修正:FF45+已经支持innerText属性),一般情况下我们可以使用textContent来代替,但它两者 ...
- RegularHelper
private const string m_NumberPattm = @"^[-+]?(0{1}|(([1-9]){1}[0-9]{0,6}))?$"; private con ...