我有一个带有服务器的简单LAN拓扑,并说了三个客户端,
-client
server -client
-client
(他们并不是字面上的“玩家”)
这三个客户端向服务器传达各种信息。当然,只使用[Command]
调用。
但是它们“都是一样的”。拨打了相同的电话。
(服务器从ID知道哪个人发送了信息。)
首先,我只是生成了一个“玩家”对象,上面带有一个脚本,其中包含各种[Command]
调用。
但是。
事实证明,服务器仅“相信”连接的最后一个。
在Unity网络中似乎只能有一个“玩家”。
真的,您如何在Unity网络中做到这一点?
答案 0 :(得分:2)
对于任何为此感到困惑的人,回答我自己的问题:
实际上,您将为每个玩家获得 一位 。 (一旦您说了一遍,似乎就很明显了。)到处都是一大堆。
所以在这里:
-client
server -client
-client
实际上,您将看到三个衍生的预制件。
(此外:在我的示例中,我将服务器用作“服务器”,而不是“主机”。
如果您使用的是“主机”概念,那儿还会有另一个衍生的播放器预制件。)
因此,当您启动该应用程序时,只有一台PC成为服务器,尚无连接..
然后您启动第二台PC,第一个客户端,它们就连接起来了……现在看起来像这样
然后启动第三台PC,第二台客户端,它们连接起来……现在看起来像这样
..依此类推。
因此,每个客户端都有一个克隆的播放器项。 (同样,如果对服务器使用“主机”概念,则仅意味着在与服务器相同的物理位置上还有另一个客户端。)
每个“玩家”都有自己的自动生成的玩家对象-,并且在所有设备上。五个客户端,每个设备(在所有六个设备上)将有五个自动生成的播放器对象。
那是什么引起了提到的特定错误?
Unet中隐藏的令人惊讶的困难是.isLocalPlayer
概念。
假设在播放器预制件上的示例中确实有一个类似Comms
的脚本,这似乎很自然。说游戏的其他部分必须与Comms联络(例如,向服务器发送消息)。
事实上,您必须找到自己的播放器预制件...。
您可能会希望拥有类似这样的代码。
// laser blows up
// tell Comms to send a message to the server about that
// find Comms ..
Comms co = FindObjectOfType<Comms>();
// tell it to send the message
co.TellServerLaserBlewUp();
但是,这是错误的,调试将非常不稳定。
实际上您的代码如下:
// laser blows up
// tell Comms to send a message to the server about that
// find >> OUR << Comms ..
foreach (Comms co in FindObjectsOfType<Comms>() ) {
string ilp = co.isLocalPlayer ? "YY" : "NN";
Debug.Log("I tried one of the many Comms! .. " + ilp);
if (co.isLocalPlayer) {
Debug.Log("Found it!");
co.TellServerLaserBlewUp();
}
}
(注意-显然,每次生产时您都不会找到类似的东西,您将使用单身人士或您所喝的任何茶。)
请考虑您的脚本在播放器预制件上。在我们的示例中为“ Comms.cs”。
在大多数统一示例中,他们设想您“在该脚本中”进行操作。
在这种情况下,它更直观:如果您不是.isLocalPlayer
,您就离开了。
但是,这非常幼稚,实际上,您周围的无数脚本希望/需要与您的“ Comms.cs”联系并进行处理(因为这是唯一连接到网络的脚本。
>事实上,
.isLocalPlayer
。整rick!
要重复-Unity doco示例倾向于强调“在该脚本上”做事。实际上,在任何大型现实项目中,事实并非如此,您是在“联系”该脚本作为中央通信资源。
答案 1 :(得分:1)
不是一个完整的答案,因为您已经自己弄清楚了。
(您没有一个最小的代码示例,所以说实话我不完全遵循您的工作...但是)
无论如何,我想分享我通常的做法。
在播放器预制件上(在连接上生成),我放置了一个特殊的组件,例如
<span> {{ users && users.length ? users[0].event : '' }} </span>
,如果需要的话,其他using UnityEngine;
using UnityEngine.Networking;
[DisallowMultipleComponent]
[RequireComponent(typeof(NetworkIdentity))]
public class PlayerInformation : NetworkBehaviour
{
// simply a public accessor for isLocalPlayer
public bool IsLocalPlayer
{
get {return isLocalPlayer;}
}
}
等其他NetworkBehaviour布尔也要这样做。
比每次必须从另一个组件调用方法时,我还要将其传递给isServer
->我可以直接检查它是否是本地播放器,例如
PlayerInformation
现在,仅向玩家传达某些东西的部分称为
:不幸的是,您无法将public void DoSomething(PlayerInformation player)
{
// don't even go any further if not local player
if(!player.IsLocalPlayer) return;
// ... do your stuff
}
传递给命令和Rpc ..,但是您可以传递Component
(具有NetworkIdentity)。 NetworkIdentity确保可以在所有连接的实例上识别GameObject。
GameObjects
现在,只有调用命令的播放器才应执行Rpc方法的其余部分(通常由所有播放器执行)
这样做至少使事情变得轻松而整洁-至少对我来说。
希望有帮助