注意:已弃用 UNet,未来会将其从 Unity 中删除。一个新系统正在开发中。如需了解更多信息和后续步骤,请参阅此博客文章以及常见问题解答 (FAQ)。 |
Network Manager 提供了内置的简单玩家生成功能,但您可能希望自定义玩家生成过程,例如为每个生成的新玩家分配颜色。
为此,需要使用自定义的脚本重写 Network Manager 的默认行为。
When the Network Manager adds a player, it also instantiates a GameObject from the Player Prefab and associates it with the connection. To do this, the Network Manager calls NetworkServer.AddPlayerForConnection. You can modify this behaviour by overriding NetworkManager.OnServerAddPlayer. The default implementation of OnServerAddPlayer
instantiates a new player instance from the player Prefab and calls NetworkServer.AddPlayerForConnection to spawn the new player instance. Your custom implementation of OnServerAddPlayer
must also call NetworkServer.AddPlayerForConnection
, but you are free to perform any other initialization you require in that method too.
下面的示例自定义了玩家的颜色。首先,将颜色脚本添加到玩家预制件:
using UnityEngine;
using UnityEngine.Networking;
class Player : NetworkBehaviour
{
[SyncVar]
public Color color;
}
Next, create a NetworkManager to handle spawning.
using UnityEngine;
using UnityEngine.Networking;
public class MyNetworkManager : NetworkManager
{
public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
GameObject player = (GameObject)Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
player.GetComponent<Player>().color = Color.red;
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}
}
不必从 OnServerAddPlayer
中调用 NetworkServer.AddPlayerForConnection
函数。只要传入正确的连接对象和 playerControllerId
,就可以在 OnServerAddPlayer
返回后调用该函数。因此可在两者之间执行异步步骤,例如从远程数据源加载玩家数据。
虽然在大多数多人游戏中,通常需要为每个客户端分配一个玩家,但 HLAPI 将玩家和客户端视为单独的概念。这是因为,在某些情况下(例如,如果有多个控制器连接到游戏主机系统),对于单个连接可能需要多个玩家游戏对象。当一个连接上有多个玩家时,应使用 playerControllerId
属性来区分它们。这是一个仅用于连接作用的标识符,因此可以映射到与该客户端上的玩家相关联的控制器 ID。
The system automatically spawns the player GameObject passed to NetworkServer.AddPlayerForConnection
on the server, so you don’t need to call NetworkServer.Spawn for the player. Once a player is ready, the active networked GameObjects (that is, GameObjects with an associated NetworkIdentity) in the Scene spawn on the player’s client. All networked GameObjects in the game are created on that client with their latest state, so they are in sync with the other participants of the game.
You don’t need to use playerPrefab on the NetworkManager
to create player GameObjects. You could use different methods of creating different players.
In addition to players, client connections also have a “ready” state. The host sends clients that are ready information about spawned GameObjects and state synchronization updates; clients which are not ready are not sent these updates. When a client initially connects to a server, it is not ready. While in this non-ready state, the client can do things that don’t require real-time interactions with the game state on the server, such as loading Scenes, allowing the player to choose an avatar, or fill in log-in boxes. Once a client has completed all its pre-game work, and all its Assets are loaded, it can call ClientScene.Ready to enter the “ready” state. The simple example above demonstrates implementation of ready states; because adding a player with NetworkServer.AddPlayerForConnection
also puts the client into the ready state if it is not already in that state.
客户端可尚未就绪的情况下发送和接收网络消息,这也意味着它们可以在没有活动玩家游戏对象的情况下执行此操作。因此,处于菜单或选择屏幕的客户端可以连接到游戏并与之交互,即使它们没有玩家游戏对象也是如此。如需了解在不使用命令和 RPC 调用的情况下发送消息的更多详细信息,请参阅网络消息文档。
To replace the player GameObject for a connection, use NetworkServer.ReplacePlayerForConnection. This is useful for restricting the commands that players can issue at certain times, such as in a pre-game lobby screen. This function takes the same arguments as AddPlayerForConnection
, but allows there to already be a player for that connection. The old player GameObject does not have to be destroyed. The NetworkLobbyManager uses this technique to switch from the NetworkLobbyPlayer GameObject to a gameplay player GameObject when all the players in the lobby are ready.
还可以使用 ReplacePlayerForConnection
在游戏对象被销毁后重新生成一个玩家。在某些情况下,最好直接禁用游戏对象并在重新生成时重置其游戏属性。以下代码示例演示了如何使用新的游戏对象实际替换已销毁的游戏对象:
class GameManager
{
public void PlayerWasKilled(Player player)
{
var conn = player.connectionToClient;
var newPlayer = Instantiate<GameObject>(playerPrefab);
Destroy(player.gameObject);
NetworkServer.ReplacePlayerForConnection(conn, newPlayer, 0);
}
}
如果用于连接的玩家游戏对象被销毁,则该客户端无法执行命令。但是,客户端仍然可以发送网络消息。
To use ReplacePlayerForConnection
you must have the NetworkConnection GameObject for the player’s client to establish the relationship between the GameObject and the client. This is usually the property connectionToClient on the NetworkBehaviour class, but if the old player has already been destroyed, then that might not be readily available.
To find the connection, there are some lists available. If using the NetworkLobbyManager
, then the lobby players are available in lobbySlots. The NetworkServer also has lists of connections and localConnections.