En Unity, crear nuevos objetos con Instantiate() es a veces llamado “spawning” (generación). En el HLAPI de la red, la palabra “spawn” es utilizado para significar algo más especifico. En el modelo autoritario del servidor del HLAPI de la red, para “spawn” un objeto en el servidor significa que el objeto debería ser creado en clientes conectados al servidor, y el objeto será manejado por el sistema de generación (“spawning”). Una vez en el sistema de generación (“spwaning”)las actualizaciones de estado son enviadas a los clientes cuando el objeto cambia en el servidor, y el objeto será destruido en clientes cuando sea destruido en el servidor. Los objetos generados (spawned) también son agregados para configurar los objetos en red que el servidor está manejando, por lo que si otro cliente se une al juego después, los objetos también serán generados en ese cliente. Estos objetos tienen una instancia ID de red única llamada “netId” que es la misma en el servidor y los clientes para cada objeto. Esto es utilizado para el enrutamiento de mensajes a objetos y para identificar objetos.
Cuando los objetos NetworkIdentity son generados en clientes, estos son creados con el estado actual del objeto en el servidor. Esto aplica al estado de movimiento del transform del objeto y variables sincronizadas. Por lo que los objetos cliente siempre están actualizados cuando son creados. Esto evita problemas como objetos siendo generados en una ubicación inicial equivocada, luego apareciendo en su posición correcta cuando un paquete de actualización de estado llega.
Esto suena genial, pero hay algunas preguntas inmediatas que surgen a partir de esto. Cómo es el objeto creado en los clienteS? Y, qué si los objetos cambian entre el tiempo cuando son generados y otro cliente los conecta? Qué versión del objeto es generada para el nuevo cliente entonces?
La generación de objetos en clientes instancia el objeto Cliente del prefab del objeto que fue pasado a NetworkServer.Spawn en el servidor. El panel de pre-visualización del inspector NetworkIdentity muestra el ID del Asset del NetworkIdentity, es este valor que identifica el prefab para que el cliente pueda crear los objetos. Para que esto funcione eficientemente, hay un paso de registración que los clientes deben realizar; estos deben llamar ClientScene.RegisterPrefab para decirle al sistema acerca del asset el cual el objeto cliente será creado.
El registro de prefabs de generación se hace más conveniente por el NetworkManager en el editor. La sección “Spawn Info” del NetworkManager le permite a usted registrar prefabs sin escribir código. Estoy también se puede hacer a través de código cuando un NetworkClient es creado. Para hacerlo en código:
using UnityEngine;
using UnityEngine.Networking;
public class MyNetworkManager : MonoBehaviour
{
public GameObject alienPrefab;
NetworkClient myClient;
// Create a client and connect to the server port
public void SetupClient()
{
ClientScene.RegisterPrefab(alienPrefab);
myClient = new NetworkClient();
myClient.RegisterHandler(MsgType.Connect, OnConnected);
myClient.Connect("127.0.0.1", 4444);
}
}
En este ejemplo, el usuario arrastraría el asset prefab a la ranura alienPrefab en el script MyNetworkManager. Para que entonces cuando un objeto alien sea generado en el servidor, el mismo tipo de objeto será creado en el del cliente. Este registro de assets asegura que el asset sea cargado a la escena, para que no hay una espera para cargar el asset cuando sea creado. Para casos de uso más avanzado tal como object pools (agrupamiento de objetos) o la creación dinámica de asset, está ClientScene.RegisterSpawnHandler que le permite a funciones callback en ser registradas para la generación por el lado del cliente.
Abajo hay un ejemplo simple de un generado que crea un árbol con un número aleatorio de hojas.
class Tree : NetworkBehaviour
{
[SyncVar]
public int numLeaves;
}
class MySpawner : NetworkBehaviour
{
public GameObject treePrefab;
public void Spawn()
{
GameObject tree = (GameObject)Instantiate(treePrefab, transform.position, transform.rotation);
tree.GetComponent<Tree>().numLeaves = Random.Range(10,200);
NetworkServer.Spawn(tree);
}
}
Para completar este ejemplo, el proyecto tendría un asset prefab para el árbol que tiene un script Tree y un componente NetworkIdentity. Luego en la instancia MySpawner en la escena, la ranura treePrefab sería llenada por el asset prefab árbol. También, el árbol prefab debe estar registrado como un objeto que se puede generar - ya sea utilizando el UI del NetworkManager, o utilizando ClientScene.RegisterPrefab() en el código.
Cuando este código corre, los objetos árbol creados en clientes tendrán el valor correcto de numLeaves (número de hojas) del servidor.
Las operaciones actuales de flujo que toman lugar para la generación son:
Los Objetos jugadores en el HLAPI de la red son especiales en algunas maneras. El flujo para la generación de objetos jugador con el NetworkManager es:
Tenga en cuenta que OnStartLocalPlayer() es llamado después de OnStartClient(), ya que solo sucede cuando llega el mensaje de propiedad del servidor después de que el objeto jugador es generado. Por lo que isLocalPlayer no estará configurado en OnStartClient().
Debido a que OnStartLocalPlayer es solamente llamado para SU jugador, es un buen lugar realizar la inicialización que debería ser solo hecha para el jugador local. Esto puede incluir activar el procesamiento de input, y activar el seguimiento de cámara para el objeto jugador. Típicamente solamente el jugador local tiene una cámara activa.
Es posible generar objetos y asignar autoridad a los objetos de un cliente en particular. Esto es hecho con NetworkServer.SpawnWithClientAuthority, que toma la NetworkConnection del cliente que será la autoridad como un argumento.
Para estos objetos, la propiedad hasAuthority será true en el cliente con autoridad y OnStartAuthority() será llamado en el cliente con autoridad. Este cliente será capaz de establecer comandos para ese objeto. En otros clientes (y en el anfitrión), hasAuthority será falso.
Los objetos generados con una autoridad de cliente deben tener LocalPlayerAuthority configurados en su NetworkIdentity.
Por ejemplo, para permitirle a un jugador generarse y controlar un objeto:
[Command]
void CmdSpawn()
{
var go = (GameObject)Instantiate(
otherPrefab,
transform.position + new Vector3(0,1,0),
Quaternion.identity);
NetworkServer.SpawnWithClientAuthority(go, connectionToClient);
}