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;
}
}