Enemy Duplicates for Each Player That Joins

Hi, I’m working on a multiplayer game using Unity and Coherence. I’ve run into a problem where my enemy prefab duplicates every time a new player joins the game. I’m not spawning the enemy through code — it’s already placed in the scene manually. But when multiple players join, each one seems to get their own copy of the enemy.

I only want one enemy in the scene, shared across all players. But right now, it looks like the enemy is being instantiated or loaded again for each player that enters the scene. (Images included for the enemy sync)

Here’s the script I’m using on the enemy object (called tinky winky). It’s placed directly in the scene, not spawned at runtime or something similar: using UnityEngine;
using UnityEngine.SceneManagement;

[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(AudioSource))]
public class TinkyWinky : MonoBehaviour
{
public float followSpeed = 5f;
public GameObject indicatorObject;
public float indicatorDetectionAngle = 30f;
public float indicatorRange = 25f;
public float nearSoundRange = 15f;
public AudioClip nearSound;
public float lookDurationThreshold = 3f;
public string sceneToLoad;

private Rigidbody rb;
private AudioSource audioSource;
private Transform currentNearest;
private bool isInsidePlayer = false;
private bool hasTriggeredSceneChange = false;
private float totalGazeTime = 0f;
private bool hasStartedPlayingSound = false;

void Start()
{
    rb = GetComponent<Rigidbody>();
    rb.constraints = RigidbodyConstraints.FreezeRotation;
    rb.useGravity = true;

    audioSource = GetComponent<AudioSource>();
    if (nearSound != null)
    {
        audioSource.clip = nearSound;
        audioSource.loop = false;
    }
}

void UpdateNearestPlayer()
{
    GameObject[] players = GameObject.FindGameObjectsWithTag("Player");
    Transform best = null;
    float minDistSqr = Mathf.Infinity;

    foreach (var go in players)
    {
        float dSqr = (go.transform.position - transform.position).sqrMagnitude;
        if (dSqr < minDistSqr)
        {
            minDistSqr = dSqr;
            best = go.transform;
        }
    }

    currentNearest = best;
}

void FixedUpdate()
{
    if (currentNearest == null)
        return;

    if (!isInsidePlayer)
    {
        Vector3 dir = currentNearest.position - transform.position;
        dir.y = 0;
        if (dir.sqrMagnitude > 0.001f)
            dir.Normalize();

        rb.velocity = dir * followSpeed + Vector3.up * rb.velocity.y;
    }
    else
    {
        rb.velocity = new Vector3(0, rb.velocity.y, 0);
    }
}

void Update()
{
    UpdateNearestPlayer();

    if (currentNearest == null)
        return;

    float dist = Vector3.Distance(transform.position, currentNearest.position);
    bool isLookedAt = false;

    if (Camera.main != null && indicatorObject != null && dist <= indicatorRange)
    {
        Vector3 toObj = transform.position - Camera.main.transform.position;
        float angle = Vector3.Angle(Camera.main.transform.forward, toObj);
        isLookedAt = angle <= indicatorDetectionAngle;
        indicatorObject.SetActive(isLookedAt);
    }
    else if (indicatorObject != null)
    {
        indicatorObject.SetActive(false);
    }

    if (isLookedAt && !hasTriggeredSceneChange)
    {
        totalGazeTime += Time.deltaTime;
        if (totalGazeTime >= lookDurationThreshold)
        {
            hasTriggeredSceneChange = true;
            SceneManager.LoadScene(sceneToLoad);
        }
    }

    if (nearSound != null)
    {
        if (dist <= nearSoundRange && !audioSource.isPlaying)
        {
            audioSource.loop = true;
            audioSource.Play();
            hasStartedPlayingSound = true;
        }
        else if (dist > nearSoundRange && hasStartedPlayingSound)
        {
            audioSource.loop = false;
        }
    }
}

void LateUpdate()
{
    if (currentNearest == null)
        return;

    Vector3 flatDir = currentNearest.position - transform.position;
    flatDir.y = 0;

    if (flatDir.sqrMagnitude > 0.001f)
    {
        Quaternion targetRot = Quaternion.LookRotation(flatDir);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, 5f * Time.deltaTime);
    }
}

private void OnTriggerEnter(Collider other)
{
    if (other.CompareTag("Player"))
    {
        isInsidePlayer = true;
        SceneManager.LoadScene(sceneToLoad);
    }
}

private void OnTriggerExit(Collider other)
{
    if (other.CompareTag("Player"))
        isInsidePlayer = false;
}

}

Hey, since it’s in your scene at build time and also networked, this is expected behaviour. If this enemy is something you want to spawn many of you should refactor your approach to have one player (chosen however you like) do the spawning per enemy. It doesn’t have to be the same player every time. This ensure there’s only one instance of that enemy - it’ll still appear on all connected clients.

If you are not “spawning” multiples of things and this really is a gameplay unique entity, check out our uniqueness options: Uniqueness | coherence Documentation