Unity Netcode Spawnpoints

Hi, does someone know how to customize the spawn point for players using Netcode's NetworkManager? I mean, there are 2 spawnpoints and 2 players. And the players should spawn on a random one.

Hi @elliotbra You should create manually PlayerPrefab. Only Server/Host should run this method.
You can listen "NetworkManager.Singleton.OnClientStarted" event then run the "SpawnPlayerObject" method.
I hope this little code helps you.

public void SpawnPlayerObject(ulong joinedClientId)
{
            Transform newGameObject = Instantiate(m_PlayerPrefab, GetAvaiablePosition(), Quaternion.identity);
            NetworkObject newNetworkObject = newGameObject.GetComponent<NetworkObject>();
            newNetworkObject.SpawnAsPlayerObject(joinedClientId, true);
}
2 Likes

Hi @elliotbra , you need to use ConnectionApprovalCallback. There's an example in this experimental sample called API Diorama (EDIT: it's now Multiplayer Use Cases)

using UnityEngine;

namespace Unity.Netcode.Samples.APIDiorama.RPC
{
    /// <summary>
    /// Manages how a player will be spawned
    /// </summary>
    class PlayerSpawnManager : NetworkBehaviour
    {
        void Start()
        {
            NetworkManager.ConnectionApprovalCallback = ConnectionApprovalCallback;
        }

        void ConnectionApprovalCallback(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
        {
            /* you can use this method in your project to customize one of more aspects of the player
             * (I.E: its start position, its character) and to perform additional validation checks. */
            response.Approved = true;
            response.CreatePlayerObject = true;
            response.Position = GetPlayerSpawnPosition();
        }

        Vector3 GetPlayerSpawnPosition()
        {
            /*
             * this is just an example, and you change this implementation to make players spawn on specific spawn points
             * depending on other factors (I.E: player's team)
             */
            return new Vector3(Random.Range(-3, 3), 0, Random.Range(-3, 3));
        }
    }
}

@PaoloAbela This appears to only set the position for clients, not the host. The first object that spawns always ends up a Vector3.zero, and the second object that spawns gets the position set as intended.

Do you know why this is?

Im having the same issue, where the host always spawns at zero. And for me the clients will get spawn at the new position but get interpolated back to the origin (zero) as soon as they spawn.

Edit: My issue with clients interpolating back to the origin was caused by the character controller not syncing its transform with the physics system. If youve got the same issue, turn on auto sync transforms in the physics settings or call Physics.SyncTransforms() after moving your player.

There is another example you can look at for solving this issue: the 2D Space Shooter Sample.
In this sample the spawn position change works for both host and clients, you can have a look at the project itself for further details.
The script for the spawning looks the following:

using System;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;
using Random = UnityEngine.Random;

[RequireComponent(typeof(NetworkManager))]
public class RandomPositionPlayerSpawner : MonoBehaviour
{
    NetworkManager m_NetworkManager;

    int m_RoundRobinIndex = 0;

    [SerializeField]
    SpawnMethod m_SpawnMethod;

    [SerializeField]
    List<Vector3> m_SpawnPositions = new List<Vector3>() { Vector3.zero };

    /// <summary>
    /// Get a spawn position for a spawned object based on the spawn method.
    /// </summary>
    /// <returns>?The spawn position.</returns>
    /// <exception cref="NotImplementedException"></exception>
    public Vector3 GetNextSpawnPosition()
    {
        switch (m_SpawnMethod)
        {
            case SpawnMethod.Random:
                var index = Random.Range(0, m_SpawnPositions.Count);
                return m_SpawnPositions[index];
            case SpawnMethod.RoundRobin:
                m_RoundRobinIndex = (m_RoundRobinIndex + 1) % m_SpawnPositions.Count;
                return m_SpawnPositions[m_RoundRobinIndex];
            default:
                throw new NotImplementedException();
        }
    }

    private void Awake()
    {
        var networkManager = gameObject.GetComponent<NetworkManager>();
        networkManager.ConnectionApprovalCallback += ConnectionApprovalWithRandomSpawnPos;
    }

    void ConnectionApprovalWithRandomSpawnPos(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
    {
        // Here we are only using ConnectionApproval to set the player's spawn position. Connections are always approved.
        response.CreatePlayerObject = true;
        response.Position = GetNextSpawnPosition();
        response.Rotation = Quaternion.identity;
        response.Approved = true;
    }
}

enum SpawnMethod
{
    Random = 0,
    RoundRobin = 1,
}