unity3d 官网多人游戏

流畅的游戏玩法来自流畅的帧率,而我们即将推出的动作平台游戏《Shadow Blade》已经将在标准iPhone和iPad设备上实现每秒60帧视为一个重要目标。
以下是我们在紧凑的优化过程中提升游戏运行性能,并实现目标帧率时需要考虑的事项。
当基本游戏功能到位时,就要确保游戏运行表现能够达标。我们衡量游戏运行表现的一个基本工具是Unity内置分析器以及Xcode分析工具。使用Unity分析器来分析设备上的运行代码真是一项宝贵的功能。
我们总结了这种为将目标设备的帧率控制在60fps而进行衡量、调整、再衡量过程的中相关经验。
shadow blade()
一、遇到麻烦时要调用“垃圾回收器”(Garbage Collector,无用单元收集程序,以下简称GC)
由于具有C/C++游戏编程背景,我们并不习惯无用单元收集程序的特定行为。确保自动清理你不用的内存,这种做法在刚开始时很好,但很快你就公发现 自己的分析器经常显示CPU负荷过大,原因是垃圾回收器正在收集垃圾内存。这对移动设备来说尤其是个大问题。要跟进内存分配,并尽量避免它们成为优先数, 以下是我们应该采取的主要操作:
1.移除代码中的任何字符串连接,因为这会给GC留下大量垃圾。
2.用简单的“for”循环代替“foreach”循环。由于某些原因,每个“foreach”循环的每次迭代会生成24字节的垃圾内存。一个简单的循环迭代10次就可以留下240字节的垃圾内存。
3.更改我们检查游戏对象标签的方法。用“if (go.CompareTag (“Enemy”)”来代替“if (go.tag == “Enemy”)” 。在一个内部循环调用对象分配的标签属性以及拷贝额外内存,这是一个非常糟糕的做法。
4.对象库很棒,我们为所有动态游戏对象制作和使用库,这样在游戏运行时间内不会动态分配任何东西,不需要的时候所有东西反向循环到库中。
5.不使用LINQ命令,因为它们一般会分配中间缓器,而这很容易生成垃圾内存。
二、谨慎处理高级脚本和本地引擎C++代码之间的通信开销。
所有使用Unity3D编写的游戏玩法代码都是脚本代码,在我们的项目中是使用Mono执行时间处理的C#代码。任何与引擎数据的通信需求都要有一个进入高级脚本语言的本地引擎代码的调用。这当然会产生它自己的开销,而尽量减少游戏代码中的这些调用则要排在第二位。
1.在这一情景中四处移动对象要求来自脚本代码的调用进入引擎代码,这样我们就会在游戏玩法代码的一个帧中缓存某一对象的转换需求,并一次仅向引擎发送一个请求,以便减少调用开销。这种模式也适用于其他相似的地方,而不仅局限于移动和旋转对象。
2.将引用本地缓存到元件中会减少每次在一个游戏对象中使用 “GetComponent” 获取一个元件引用的需求,这是调用本地引擎代码的另一个例子。
三、物理效果
1.将物理模拟时间步设置到最小化状态。在我们的项目中就不可以将让它低于16毫秒。
2.减少角色控制器移动命令的调用。移动角色控制器会同步发生,每次调用都会耗损极大的性能。我们的做法是缓存每帧的移动请求,并且仅运用一次。
3.修改代码以免依赖“ControllerColliderHit” 回调函数。这证明这些回调函数处理得并不十分迅速。
4.面对性能更弱的设备,要用skinned mesh代替physics cloth。cloth参数在运行表现中发挥重要作用,如果你肯花些时间找到美学与运行表现之间的平衡点,就可以获得理想的结果。
5.在物理模拟过程中不要使用ragdolls,只有在必要时才让它生效。
6.要谨慎评估触发器的“onInside”回调函数,在我们的项目中,我们尽量在不依赖它们的情况下模拟逻辑。
7.使用层次而不是标签。我们可以轻松为对象分配层次和标签,并查询特定对象,但是涉及碰撞逻辑时,层次至少在运行表现上会更有明显优势。更快的物理计算和更少的无用分配内存是使用层次的基本原因。
8.千万不要使用Mesh对撞机。
9.最小化碰撞检测请求(例如ray casts和sphere checks),尽量从每次检查中获得更多信息。
四、让AI代码更迅速
我们使用AI敌人来阻拦忍者英雄,并同其过招。以下是与AI性能问题有关的一些建议:
1.AI逻辑(例如能见度检查等)会生成大量物理查询。可以让AI更新循环设置低于图像更新循环,以减少CPU负荷。
五、最佳性能表现根本就不是来自代码!
没有发生什么情况的时候,就说明性能良好。这是我们关闭一切不必要之物的基本原则。我们的项目是一个侧边横向卷轴动作游戏,所以如果不具有可视性时,就可以关闭许多动态关卡物体。
1.使用细节层次的定制关卡将远处的敌人AI关闭。
2.移动平台和障碍,当它们远去时其物理碰撞机也会关闭。
3.Unity内置的“动画挑选”系统可以用来关闭未被渲染对象的动画。
4.所有关卡内的粒子系统也可以使用同样的禁用机制。
六、回调函数!那么空白的回调函数呢?
要尽量减少Unity回调函数。即使敌人回调函数存在性能损失。没有必要将空白的回调函数留在代码库中(有时候介于大量代码重写和重构之间)。
七、让美术人员来救场
在程序员抓耳挠腮,绞尽脑汁去想该如何让每秒运行更多帧时,美术人员总能神奇地派上大用场。
1.共享游戏对象材料,令其在Unity中处于静止状态,可以让它们绑定在一起,由此产生的简化绘图调用是呈现良好移动运行性能的重要元素。
2.纹理地图集对UI元素来说尤其有用。
3.方形纹理以及两者功率的合理压缩是必不可少的步骤。
4.我们的美术人员移除了所有远处背景的网格,并将其转化为简单的2D位面。
5.光照图非常有价值。
6.我们的美术人员在一些关口移除了额外顶点。
7.使用合理的纹理mip标准是一个好主意(游戏邦注:要让不同分辨率的设备呈现良好的帧率时尤其如此)。
8.结合网格是美术人员可以发挥作用的另一个操作。
9.我们的动画师尽力让不同角色共享动画。
10.要找到美学/性能之间的平衡,就免不了许多粒子效果的迭代。减少发射器数量并尽量减少透明度需求也是一大挑战。
八、要减少内存使用
使用大内存当然会对性能产生负面影响,但在我们的项目中,我们的iPod由于超过内存上限而遭遇了多次崩溃事件。我们的游戏中最耗内存的是纹理。
1.不同设备要使用不同的纹理大小,尤其是UI和大型背景中的纹理。《Shadow Blade》使用的是通用型模板,但如果在启动时检测到设备大小和分辨率,就会载入不同资产。
2.我们要确保未使用的资产不会载入内存。我们必须迟一点在项目中找到仅被一个预制件实例引用,并且从未完全载入内存中实例化的资产。
3.去除网格中的额外多边形也能实现这一点。
4.我们应该重建一些资产的生周期管理。例如,调整主菜单资产的加载/卸载时间,或者关卡资产、游戏音乐的有效期限。
5.每个关卡都要有根据其动态对象需求而量身定制的特定对象库,并根据最小内存需求来优化。对象库可以灵活一点,在开发过程中包含大量对象,但知道游戏对象需求后就要具体一点。
6.保持声音文件在内存的压缩状态也是必要之举。
加强游戏运行性能是一个漫长而具有挑战性的过程,游戏开发社区所分享的大量知识,以及Unity提供的出色分析工具为《Shadow Blade》实现目标运行性能提供了极大帮助。(本文为游戏邦/编译,拒绝任何不保留版权的转载,如需转载请联系:游戏邦)
阅读(...) 评论() &使用Multiplayer Networking做一个简单的多人游戏例子分析-1/3(Unity3D开发之二十五)
OK,现在可以开始了!
1. 开始创建工程
创建一个空的3D工程保存当前场景为&Main&
2. 使用 Network Manager
主要使用NetworkManager和NetworkManagerHUD(一个简易的UI面板)
创建一个empty GameObject. 修改名称为&Network Manager& 选中Network Manager对象体添加组件:Network & NetworkManager 添加组件:Network & NetworkManagerHUD
NetworkManager组件的属性:
NetworkManagerHUD组件属性:
运行后,此时运行后效果(该UI就是NetworkManagerHUD):
3. 设置Player prefab
本实例中玩家GameObject效果(后面会加上武器):
开始创建Player GameObject:
创建一个Capsule胶囊体修改名称为&Player& 选中&Player& 创建一个Cube作为Player的子物体修改Cube名称为&Visor& 设置Visor Scale (0.95, 0.25, 0.5) 设置Visor Position (0.0, 0.5, 0.24) 创建一个新材质Material 修改材质Material名称为&Black& 选中Black Material 修改其Albedo color 为黑色将Visor的Material修改为Black Material
为了给Player添加uniqueID作为网络中的唯一ID,我们需要给Player添加NetworkIdentity组件
选中Player GameObject 添加组件:Network & NetworkIdentity 设置NetworkIdentity组件属性Local Player Authority为True,勾选上
将Local Player Authority勾选上,是为了后面Client能够控制Player
最后创建Player的Prefab预制体:
将场景中的Player拖拽到Project面板中生成Prefab 删除Scene中原来的Player 保存场景
4. 注册Player prefab
选中Network Manager GameObject 在 Hierarchy 面板中保存Network Manager被选中状态展开Network Manager属性面板中Spawn Info 将Player prefab拖拽到Player Prefab框中
5. 创建Player 移动控制脚本
新建一个C#脚本为&PlayerController&, 并将其绑定到Player prefab上
PlayerController.cs:
using UnityE
public class PlayerController : MonoBehaviour
void Update()
var x = Input.GetAxis(&Horizontal&) * Time.deltaTime * 150.0f;
var z = Input.GetAxis(&Vertical&) * Time.deltaTime * 3.0f;
transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
保存脚本保存场景
6. 测试Player的在线移动
运行Unity进入Play模式
运行模式下,NetworkManagerHUD将会显示默认的UI
点击LAN Host(H),将本机作为主机Host开始游戏
此时NetworkManager将会创建一个Player在场景中,NetworkManagerHUD将会显示为游戏中UI
键盘WASD控制玩家Player移动方向点击UI中的Stop(X) 回到离线模式点击停止运行Unity,退出运行模式
开始测试在客户端中控制玩家Player
为了测试多玩家,所以我们需要两个客户端。在这里我们可以Build一个Mac版本(或者Windows版本)作为一个玩家,然后Unity自己运行作为一个玩家。OK,下面开始Build一个Mac版本.
打开Build Settings面板,并添加当前场景。保存工程 Build一个Mac standalone application 完成之后,点击运行刚才Mac版本,并选择Windows窗口模式运行,不要全屏运行。点击LAN Host(H),作为主机玩家点击WASD按键,移动一下Mac版本中的Player(不然另一个玩家加入的时候,位置在同一个位置,你有可能认为只有一个玩家)
现在回到Unity,将Unity作为另一个玩家加入游戏。
运行Unity,进入Play模式点击LAN Client(C)加入游戏。
此时你应该看到了两个玩家在游戏中。
关闭Mac客户端停止运行Unity 退出Play模式
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'Unity3D多人RPG游戏源码
Unity3D多人RPG游戏源码
作者:空轮回
资源类型:
运行环境:
Unity3D简单手机多人RPG游戏源码,Mageist Basic RPG ,js脚本,代码比较完整,有菜单有屏幕自适应,Unity 3.4.0 以上版本运行.
服务热线:400-678-8266扫一扫,访问微社区
后使用快捷导航没有帐号?
签到成功!您今天第{todayrank}个签到,签到排名竞争激烈,记得每天都来签到哦!已连续签到:{constant}天,累计签到:{days}天
当前位置: &
查看: 2038|回复: 13
[视频教程]Unity3D多人游戏开发:UNET快速入门-第一集
11排名<font color="#FF昨日变化23主题帖子积分
在线时间149 小时
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
才可以下载或查看,没有帐号?
本帖最后由 qihaoyan119 于
10:46 编辑
这期视频简单的介绍了UNET,并通过基本的组件与一行代码实现了基本的同步。
全集!!小伙伴们有什么均可去集合贴讨论,或来贴吧此贴(/p/)。楼主平常在贴吧闲逛的次数更多,因此贴吧可能会得到更快的回复哦。
3d入门视频教程;unity3d 入门教程视频
每日推荐:
72205/5000排名<font color="#FF昨日变化1主题帖子积分
日久生情, 积分 2205, 距离下一级还需 2795 积分
日久生情, 积分 2205, 距离下一级还需 2795 积分
蛮牛币7419
在线时间603 小时
好教程····有心了,谢谢分享···
每日推荐:
2136/150排名<font color="#FF昨日变化7主题帖子积分
初来乍到, 积分 136, 距离下一级还需 14 积分
初来乍到, 积分 136, 距离下一级还需 14 积分
在线时间42 小时
不错的教程,谢谢分享。
每日推荐:
61417/1500排名<font color="#FF昨日变化3主题帖子积分
蛮牛粉丝, 积分 1417, 距离下一级还需 83 积分
蛮牛粉丝, 积分 1417, 距离下一级还需 83 积分
蛮牛币3932
在线时间413 小时
好教程····有心了,谢谢分享··
3295/300排名<font color="#FF昨日变化8主题帖子积分
偶尔光临, 积分 295, 距离下一级还需 5 积分
偶尔光临, 积分 295, 距离下一级还需 5 积分
在线时间102 小时
求更新下集
4465/500排名<font color="#FF昨日变化4主题帖子积分
四处流浪, 积分 465, 距离下一级还需 35 积分
四处流浪, 积分 465, 距离下一级还需 35 积分
在线时间170 小时
unity更新功能真是快的飞起
268/150排名<font color="#FF昨日变化5主题帖子积分
初来乍到, 积分 68, 距离下一级还需 82 积分
初来乍到, 积分 68, 距离下一级还需 82 积分
在线时间43 小时
感谢分享!!!!!!!!!!!
268/150排名<font color="#FF昨日变化5主题帖子积分
初来乍到, 积分 68, 距离下一级还需 82 积分
初来乍到, 积分 68, 距离下一级还需 82 积分
在线时间43 小时
求下一集地址!!!!!!!!!
72911/5000排名51昨日变化主题帖子积分
日久生情, 积分 2911, 距离下一级还需 2089 积分
日久生情, 积分 2911, 距离下一级还需 2089 积分
蛮牛币7367
在线时间717 小时
服务器用啥么写啊,UNET还是鸡肋
72911/5000排名51昨日变化主题帖子积分
日久生情, 积分 2911, 距离下一级还需 2089 积分
日久生情, 积分 2911, 距离下一级还需 2089 积分
蛮牛币7367
在线时间717 小时
要是像 bigworld 有服务器部分就爽
5911/1000排名<font color="#FF昨日变化5主题帖子积分
熟悉之中, 积分 911, 距离下一级还需 89 积分
熟悉之中, 积分 911, 距离下一级还需 89 积分
蛮牛币6103
在线时间195 小时
看一下看。
5605/1000排名<font color="#FF昨日变化2主题帖子积分
熟悉之中, 积分 605, 距离下一级还需 395 积分
熟悉之中, 积分 605, 距离下一级还需 395 积分
蛮牛币1609
在线时间219 小时
谢谢班长哈哈哈
19/50主题帖子积分
注册看看, 积分 9, 距离下一级还需 41 积分
注册看看, 积分 9, 距离下一级还需 41 积分
在线时间6 小时
很好赞一个
3241/300排名<font color="#FF昨日变化84主题帖子积分
偶尔光临, 积分 241, 距离下一级还需 59 积分
偶尔光临, 积分 241, 距离下一级还需 59 积分
在线时间97 小时
好教程····有心了,谢谢分享··
[]: 一个袋子砸在了 xiaoshu 头上,xiaoshu 赚了 1使用 Photon 在 Unity 里快速搭建一个多人联机游戏 - 推酷
使用 Photon 在 Unity 里快速搭建一个多人联机游戏
如何最快的搭建一个 Unity 上的多人游戏?答案也许是自己搭建一个游戏服务器,也许是 LAN 解决方案,但是最快的解决方案还是使用成熟的第三方后端服务,我找到了
,一个看起来不错最后证实也挺靠谱的游戏后端解决方案。
一个游戏服务器,最主要的就是对不同参与者的事件同步和世界状态的同步,所以根本还是在于和服务器的长连接上,至于游戏中的用户体系,积分体系,货币体系这些,就是属于大后端的范畴了,也是可以独立于游戏同步服务器存在的系统。
首先你需要集成 Photon SDK For Unity ,下载地址在
你需要将下载下来的 PhotoAssets 中的所有文件都拖到你的项目的 Assets 文件夹里面,注意在 Plugins 里面有两个 Photon3Unity3D.dll ,需要将 Metro 文件夹删掉,保留一个,否则在 Unity 编译的时候会报错。
拖进去之后只要 Unity 中 Compile 没有问题那第一步就大功告成了。
创建一个你用来维护游戏网络逻辑的脚本,例如命名为 GameNetworkClient.cs ,然后你需要在头部加上这几个引用:
using System.C
using ExitGames.Client.P
using ExitGames.Client.Photon.LoadB
using System.Collections.G
using UnityE
using Hashtable = ExitGames.Client.Photon.H
接着声明一个私有的 LoadBalancingClient 对象,你的脚本中的所有网络逻辑都会通过这个 client 对象来发起和回调。我们这样在 Start 中初始化 client 对象:
client = new LoadBalancingClient();
client.AppId = &{你的 App_id}&;
client.OnStateChangeAction += this.OnStateC
client.OnOpResponseAction += this.OnRespA
client.OnEventAction += this.OnE
client.ConnectToRegionMaster(&asia&);
你的 App_id 可以在 Photon 官网注册完免费账户后在账户详情页获取,免费的账户拥有 20 个同时在线人数的限额,对于小范围好友间的游戏和测试足够了。
其中,最后一行代码就是 client 去连接 MasterServer 的方法,这里面传入的参数要根据你的游戏所在地区来确定, Photon 在全球有很多分散的数据中心,因此支持很多区域的连接,具体支持的地区和代码如下:
Canada, East
South America
Washington
所以在这里我改成了 asia ,事实证明新加坡的服务器是比较稳定的。
client 的状态主要就是根据上面初始化的时候给的三个 Action 来维护的,你需要在你的脚本里为这三个 Action 都加上你自己的 Handler。当然,如果你想按照他的 demo 里示范的那样去继承 client 并且 override 这三个 Action 的回调都是可以的。
OnStateChanged
返回的是一个 ClientState 枚举值,主要就是一些 client 状态的值,例如
connecting , connected , joining 之类的。
OnRespAction
返回的是一个 OperationResponse 对象,它会在每次你用 client 对象调用一些方法并且获得 response 之后调用,分别有下面这些类型的 Operation:
public class OperationCode {
[Obsolete(&Exchanging encrpytion keys is done internally in the lib now. Don't expect this operation-result.&)]
public const byte ExchangeKeysForEncryption = 250;
/// &summary&(255) Code for OpJoin, to get into a room.&/summary&
public const byte Join = 255;
/// &summary&(230) Authenticates this peer and connects to a virtual application&/summary&
public const byte Authenticate = 230;
/// &summary&(229) Joins lobby (on master)&/summary&
public const byte JoinLobby = 229;
/// &summary&(228) Leaves lobby (on master)&/summary&
public const byte LeaveLobby = 228;
/// &summary&(227) Creates a game (or fails if name exists)&/summary&
public const byte CreateGame = 227;
/// &summary&(226) Join game (by name)&/summary&
public const byte JoinGame = 226;
/// &summary&(225) Joins random game (on master)&/summary&
public const byte JoinRandomGame = 225;
// public const byte CancelJoinRandom = 224; // obsolete, cause JoinRandom no longer is a &process&. now provides result immediately
/// &summary&(254) Code for OpLeave, to get out of a room.&/summary&
public const byte Leave = (byte)254;
/// &summary&(253) Raise event (in a room, for other actors/players)&/summary&
public const byte RaiseEvent = (byte)253;
/// &summary&(252) Set Properties (of room or actor/player)&/summary&
public const byte SetProperties = (byte)252;
/// &summary&(251) Get Properties&/summary&
public const byte GetProperties = (byte)251;
/// &summary&(248) Operation code to change interest groups in Rooms (Lite application and extending ones).&/summary&
public const byte ChangeGroups = (byte)248;
/// &summary&(222) Request the rooms and online status for a list of friends (by name, which should be unique).&/summary&
public const byte FindFriends = 222;
/// &summary&(221) Request statistics about a specific list of lobbies (their user and game count).&/summary&
public const byte GetLobbyStats = 221;
/// &summary&(220) Get list of regional servers from a NameServer.&/summary&
public const byte GetRegions = 220;
/// &summary&(219) WebRpc Operation.&/summary&
public const byte WebRpc = 219;
可以看到,例如 rasieEvent , setProperties 或者加入离开游戏这些请求都是会有服务器的 response 的,你可以根据返回对象的 ReturnCode 来判断请求是否成功并且是否执行一些错误后的处理, ReturnCode 为 0 成功,不为 0 则失败,如果需要也可以从 DebugMessage 中获取错误提示信息。
OnEventAction
返回的是一个 EventData 对象,它会在每次 client 接收到新的 Event 的时候调用,具体的 Event 类型根据 EventData 的 EventCode 来确定,分别有下面这些类型的 EventCode :
public class EventCode {
/// &summary&(230) Initial list of RoomInfos (in lobby on Master)&/summary&
public const byte GameList = 230;
/// &summary&(229) Update of RoomInfos to be merged into &initial& list (in lobby on Master)&/summary&
public const byte GameListUpdate = 229;
/// &summary&(228) Currently not used. State of queueing in case of server-full&/summary&
public const byte QueueState = 228;
/// &summary&(227) Currently not used. Event for matchmaking&/summary&
public const byte Match = 227;
/// &summary&(226) Event with stats about this application (players, rooms, etc)&/summary&
public const byte AppStats = 226;
/// &summary&(224) This event provides a list of lobbies with their player and game counts.&/summary&
public const byte LobbyStats = 224;
/// &summary&(210) Internally used in case of hosting by Azure&/summary&
[Obsolete(&TCP routing was removed after becoming obsolete.&)]
public const byte AzureNodeInfo = 210;
/// &summary&(255) Event Join: someone joined the game. The new actorNumber is provided as well as the properties of that actor (if set in OpJoin).&/summary&
public const byte Join = (byte)255;
/// &summary&(254) Event Leave: The player who left the game can be identified by the actorNumber.&/summary&
public const byte Leave = (byte)254;
/// &summary&(253) When you call OpSetProperties with the broadcast option &on&, this event is fired. It contains the properties being set.&/summary&
public const byte PropertiesChanged = (byte)253;
/// &summary&(253) When you call OpSetProperties with the broadcast option &on&, this event is fired. It contains the properties being set.&/summary&
[Obsolete(&Use PropertiesChanged now.&)]
public const byte SetProperties = (byte)253;
/// &summary&(252) When player left game unexpected and the room has a playerTtl & 0, this event is fired to let everyone know about the timeout.&/summary&
/// Obsolete. Replaced by Leave. public const byte Disconnect = LiteEventCode.D
/// &summary&(251) Sent by Photon Cloud when a plugin-call or webhook-call failed. Usually, the execution on the server continues, despite the issue. Contains: .&/summary&
/// &seealso cref=&/en/realtime/current/reference/webhooks&/&
public const byte ErrorInfo = 251;
/// &summary&(250) Sent by Photon whent he event cache slice was changed. Done by OpRaiseEvent.&/summary&
public const byte CacheSliceChanged = 250;
这里的 EventCode 你是可以自己定义的,这个 code 是个 byte 类型的整数 ,因此不能大于255,Photon 将从 0 开始的一大段值域都留给开发者用来自定义事件了。Photon 默认提供了 GameList ,或者说 RoomList 的功能,你可以创建 Room 并且加入, Room 也有他自己的 Option,可以作为 Lobby,也就是所有人默认进入的 Room ,当然也可以根据各种条件来查找 Room 。
这里的 253 PropertiesChanged 是一个非常重要的 Event,在上面我提到过,联机游戏的后端最重要的部分之一就是世界状态的同步,在这里也就是 房间的状态 Room Properties ,因此在 Photon SDK 中,当你调用 client 对当前加入的 Room 的某个属性做出了改变,这就会产生一个事件通知到整个 Room 里的所有玩家,这通常用来同步一些全局的属性,例如光线,地形,怪物的血量之类的。
当然,你还可以自定义 Event,在我实现的 demo 中我就是用到了自定义 Event 来告知其他玩家我的状态。比如,整个地图 (可以看做就是一个 Room )中的玩家列表和位置是可以用全局状态来同步的,但是例如单个玩家的一些事件(使用物品,使用技能之类的)可能就需要由发起的用户向全 Room 的其他玩家发送一个同步事件。
byte eventCode = 1;
Hashtable evData = new Hashtable ();
evData.Add (&player_id&, random_playerid);
evData.Add (&pos_x&, position.x);
evData.Add (&pos_y&, position.y);
bool sendReliable =
if (isConnected) {
client.OpRaiseEvent (eventCode, evData, sendReliable, RaiseEventOptions.Default);
然后这个事件就会在除了发送者自己的其他玩家的客户端被回调。
这个时候收到的数据包怎么解出来呢?
最后再说说坑了我半天的 EventData 中的数据抽取,在 EventData 中的数据格式十分蛋疼,例如上面这段代码里发送的数据,当你在其他客户端收到的时候,它的数据其实是存在 EventData 的 Parameters 这个属性变量里面,这是一个 Dictionary&byte,object& 类型的对象,通过 ParameterCode.Data 这个 key 将 data 取出来之后,里面才是我们传入的 Hashtable ,然而现在已经变成了一个 Dictionary&object,object& 对象了。在没有仔细查看源码的情况下,它的官方 demo 和文档并没有提及如何解包 EventData ,因此我是通过 Debug 的方式才最终摸清了里面的数据格式。当然后来又看了下它的头文件,才看到 ParameterCode.Data :joy:。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

更多关于 蛮牛unity3d 的文章

 

随机推荐