李成笔记网

专注域名、站长SEO知识分享与实战技巧

使用Unity开发多场景多人游戏 unity 多人游戏

我将在本文中讲述我是如何使用unity创造一个多人多场景的3D应用的。我之所以没有把它称为“游戏”是因为我不想把这个应用变成一个射击、毁坏、赚钱或者是有其他游戏元素的地方。

那么这个应用的功能是:在有街道和建筑的3D场景中你可以直接与别人交流或者是在他们的家里留下信息。现在这很简单,但是将来我想加入语音、个性定制还有像学校、公司、组织或者会议大楼的不同类型的建筑。

开发须知

Unity是一个很棒的工具,你可以直接在3D场景中添加物体,还可以操作地形。每一个物体都可以加上不同的组件,这些组件可以是Unity本身已经存在的或是你自己实现的。在Unity中还有资源商店,你可以从资源商店中找到很多的3D物体和脚本。调试的部分也很有意思,运行程序时可以切换到场景视窗然后作出调整,结果会直接呈现在游戏窗口中。

我把Unity纳入考虑是因为我用.Net已经6年了,因此我很习惯用它。Unity也可以用Javascript开发,但是对我来说使用C#开发更容易。

网络

有许多关于Unity网络的文章,我不想对此太过深入,但是基本上总会有一个服务器负责处理应用之间的通信。可以选择应用中的一个作为服务器来处理服务器的操作,所有的客户端通过(RPC)远程程序调用与服务器通信。

Unity中的多场景多玩家

应用中现在有不同的街道,不同的建筑。因此用户可以到一条街道上与其他用户见面。因此我只需要把此用户的位置推送给在那条街道上的用户即可。那么,如何实现呢?Unity有NetworkView.group和SetLevelPrefix(),但是这没有帮我实现一个多场景多玩家的应用。这是最难实现的部分,因为我没有在任何地方找到如何在Unity中实现它。当然,你可以找到一些第三方插件。

Unity有NetworkView组件用来同步一个观察的组件。当所有玩家都在同一个场景中时这个组件可以用。但是当有很多的场景可以供玩家自由出入时,带有需要同步观察组件的NetworkView就不是一个好的选择了。因为NetworkView会把消息送给所有的场景。因此,第一件需要做的事情就是禁止NetworkView同步,用户只向处于相同场景中的用户发送同步消息。对于这个需求,服务器需要知道每一个玩家所处的场景。因此客户端的调用像下面的代码:

在客户端(将状态发送给服务器):

void Update()

{

if (lastLocalPlayerPosition != localPlayerObject.transform.position || lastLocalPlayerRotation != localPlayerObject.transform.rotation)

{

networkView.RPC("ServerUpdatePlayerPosition", RPCMode.Server, lastLocalPlayerPosition, lastLocalPlayerRotation, level);

}

}

在服务器端(过滤玩家,只向在同一场景的玩家发送更新)

[RPC]

void ServerUpdatePlayerPosition(Vector3 pos, Quaternion rot, string level)

{

foreach (PlayerProperties player in server_OnlinePlayers.Values)

{

if (player.Level == level && player.NetworkPlayer != Network.Player)

networkView.RPC("ClientUpdatePlayerPosition", player.NetworkPlayer, p, pos, rot);

}

}

在其他客户端:

[RPC]

void ClientUpdatePlayerPosition(NetworkPlayer p, Vector3 pos, Quaternion rot)

{

var thePlayer = FindPlayer(p);

if ( thePlayer != null && thePlayer.GameObject != null)

{

var controller = thePlayer.GameObject.GetComponent<ThirdPersonControllerC>();

controller.position = pos;

controller.rotation = rot;

}

}

一些技巧

如何通过RPC调用发送定制物体

Unity不允许通过RPC发送定制物体,只有int/string/float/NetworkPlayer/NetworkViewID/Vector/Quaternation类型的物体才可以被传送。为了发送不同种类的物体,你需要把此物体序列化和反序列化。首先,我使用strings来存储,但是存在一个string中存储大于4096个char的问题。然后我发现Unity也接受bytes数组,因此我使用了这个特性。

比如我通过RPC调用发送了一个UserMessage类型的物体,此物的属性有:Date,UserId,Message,Type等等。这个是不可能实现的,因为这个物体是不会被接受的,因此我用下面的方法把它序列化:

public static byte[] Byte_ConvertObjectToBinary(object obj)

{

MemoryStream o = new MemoryStream();

BinaryFormatter bf = new BinaryFormatter();

bf.Serialize(o, obj);

return o.GetBuffer();

}

然后通过RPC调用发送:

networkView.RPC("Server_NewMessageAdded", networkPlayer, Utils.Byte_ConvertObjectToBinary(userMessage ));

然后在客户端反序列化:

public static object Byte_ReadFromBinary(byte[] data)

{

if (data == null || data.Length == 0)

return null;

var ins = new MemoryStream(data);

BinaryFormatter bf = new BinaryFormatter();

return bf.Deserialize(ins);

}

如何把一个定制的物体附着到一个游戏物体上

(如果那个物体不是MonoBehaviour的子类):

我把一个空物体加到一个有TextMesh的物体上,因此我把有文字数字能够的物体序列化为一个string,当我需要物体时,我把这个物体反序列化然后再使用。

免费的3D模型

这个应用我需要一些3D模型,但是我不是一个3D建模师,因此我需要一些免费的模型。Sketchup是一个很好的工具,你可以找到和创造很多3D模型。在Unity资源商店中有许多的免费模型。

结论

Windows/Linux//BlackBerry/iOS/WindowsPhone 8/unity /XBOX/Wii.使用Unity工作很好,对我来说这是一个制作3D游戏的新体验。Unity另外一个很好的地方是Unity可以被发布到如下平台:

Windows/Linux/Android/BlackBerry/iOS/WindowsPhone 8/unity WebPlayer/XBOX/Wii。

原文链接:https://www.gamedev.net/resources/_/technical/multiplayer-and-network-programming/multilevel-multiplayer-with-unity-r3580

原文作者:Sorin Albu

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言