英文原文:
https://mirror-networking.gitbook.io/docs/guides/gameobjects/custom-character-spawning
许多游戏需要角色定制。您可能想要选择头发、眼睛、皮肤、身高、种族等的颜色。
默认情况下,Mirror 将为您实例化Player。虽然这很方便,但它可能会阻止您对其进行自定义。 Mirror 提供了覆盖Player创建并对其进行自定义的选项。
- 如果您还没有这样做,请创建一个扩展 NetworkManager 的类。例如:
public class MMONetworkManager : NetworkManager
{
...
}
并将其用作您的网络管理员。
- 在 inspector 中打开您的网络管理器并禁用“自动创建Player”布尔值。
- 创建一条描述您的Player的消息。例如:
public struct CreateMMOCharacterMessage : NetworkMessage
{
public Race race;
public string name;
public Color hairColor;
public Color eyeColor;
}
public enum Race
{
None,
Elvish,
Dwarvish,
Human
}
- 创建您的Player预制件(根据需要创建多个)并将它们添加到网络管理器中的“Register Spawnable Prefabs”中,或者将单个预制件添加到检查器中的Player预制件字段中。
- 发送您的消息并注册玩家:
public class MMONetworkManager : NetworkManager
{
public override void OnStartServer()
{
base.OnStartServer();
NetworkServer.RegisterHandler<CreateMMOCharacterMessage>(OnCreateCharacter);
}
public override void OnClientConnect()
{
base.OnClientConnect();
// 你可以在这里发送消息,或者你想要的任何其他地方
CreateMMOCharacterMessage characterMessage = new CreateMMOCharacterMessage
{
race = Race.Elvish,
name = "Joe Gaba Gaba",
hairColor = Color.red,
eyeColor = Color.green
};
NetworkClient.Send(characterMessage);
}
void OnCreateCharacter(NetworkConnection conn, CreateMMOCharacterMessage message)
{
// PlayerPrefab是在Network Manager的 inspector 中指定的,
// 但您可以在每个比赛中使用不同的预制件,例如
GameObject gameobject = Instantiate(playerPrefab);
// 应用消息中的数据,但要适合您的游戏。
// 通常,Player是您使用同步变量或属性编写的组件
Player player = gameobject.GetComponent();
player.hairColor = message.hairColor;
player.eyeColor = message.eyeColor;
player.name = message.name;
player.race = message.race;
// 调用它以将此游戏对象用作主控制器
NetworkServer.AddPlayerForConnection(conn, gameobject);
}
}
准备状态
除了Player,客户端连接也有“就绪”状态。主机向客户端发送有关生成的游戏对象和状态同步更新的就绪信息;未准备好的客户端不会发送这些更新。当客户端最初连接到服务器时,它还没有准备好。在这种非就绪状态下,客户端可以做一些不需要与服务器上的游戏状态进行实时交互的事情,例如加载场景、允许玩家选择头像或填写登录框.一旦客户端完成了所有的游戏前工作,并加载了所有资产,它可以调用 NetworkClient.Ready 进入“就绪”状态。上面的简单示例演示了就绪状态的实现;因为使用 NetworkServer.AddPlayerForConnection 添加player也会使客户端进入就绪状态(如果它尚未处于该状态)。
客户端可以在没有准备好的情况下发送和接收网络消息,这也意味着他们可以在没有活动玩家游戏对象的情况下这样做。因此,即使没有玩家游戏对象,菜单或选择屏幕上的客户端也可以连接到游戏并与之交互。有关在不使用命令和 RPC 调用的情况下发送消息的更多详细信息,请参阅有关网络消息的文档。
切换Player
要替换连接的玩家游戏对象,请使用 NetworkServer.ReplacePlayerForConnection。这对于限制玩家在特定时间可以发出的命令很有用,例如在赛前房间屏幕中。此函数采用与 AddPlayerForConnection 相同的参数,但允许该连接已经存在播放器。老玩家游戏对象不必被销毁。当房间中的所有玩家都准备好时,NetworkRoomManager 使用此技术从 NetworkRoomPlayer 游戏对象切换到游戏玩家游戏对象。
您还可以使用 ReplacePlayerForConnection 重生玩家或更改代表玩家的对象。在某些情况下,最好禁用游戏对象并在重生时重置其游戏属性。以下代码示例演示了如何用新的游戏对象实际替换玩家游戏对象:
public class MyNetworkManager : NetworkManager
{
public void ReplacePlayer(NetworkConnection conn, GameObject newPrefab)
{
// 缓存对当前player对象的引用
GameObject oldPlayer = conn.identity.gameObject;
// 实例化新的player对象并广播给客户端
// 为 keepAuthority 参数包含 true 以防止所有权更改
NetworkServer.ReplacePlayerForConnection(conn, Instantiate(newPrefab), true);
// 移除之前已被替换的玩家对象
NetworkServer.Destroy(oldPlayer);
}
}
如果连接的玩家游戏对象被销毁,则该客户端无法执行命令。但是,它们仍然可以发送网络消息。
要使用 ReplacePlayerForConnection,您必须拥有 NetworkConnection 游戏对象供玩家客户端建立游戏对象和客户端之间的关系。这通常是 NetworkBehaviour 类的 connectionToClient 属性,但如果旧player已被销毁,则可能无法立即使用。
要查找连接,可以使用一些列表。如果使用 NetworkRoomManager,则房间播放器在 roomSlots 中可用。 NetworkServer 也有连接列表。