回答我自己的问题,对于任何为此苦苦挣扎的人:
实际上,您将为每个玩家获得一个。(一旦你说出来似乎很明显。)到处都是这些。
所以在这里:
-client
server -client
-client
事实上,你会看到三个生成的预制件。
(除此之外:在我的示例中,我将服务器用作“服务器”,而不是“主机”..
如果您使用的是“主机”概念,那么那里还会有另一个生成的播放器预制件。)
因此,当您启动应用程序时,只有一台 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
始终找到“您的”。
棘手!
重复一遍 - Unity doco 示例倾向于强调“在那个脚本上”做事。在任何大型现实世界项目的实践中,情况并非如此,您正在“联系”该脚本作为中央通信资源。