KUTE BONAPARTE
KUTE BONAPARTE2mo ago

Spawning 1 zombie per 5 seconds

How do I instantiating 1 zombie/object per 5 seconds? I know that sounds easy. But the problem is : when i put the script on the blank gameObject, its work. But all players will instantiating it too. So if there's 2 players, 2 zombies were spawned per 5 seconds. That means the more player, the more zombies, I don't want that. I want instantiating only 1 zombie per 5 seconds, even if the players are 5, 10, etc. How did i fix this issue?
12 Replies
kapa.ai
kapa.ai2mo ago
Hi @Ykute Games. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To address your issue with spawning zombies in a multiplayer environment using Normcore, we need to consider ownership and server authority. Here's how you can approach this: 1. Use a single authoritative object to handle spawning: Create a dedicated "ZombieSpawner" object that will be responsible for spawning zombies. This object should have a RealtimeView component and be owned by a single client (preferably the first player to join the room). 2. Implement the spawning logic on this authoritative object: The spawning logic should only run on the client that owns the ZombieSpawner. Here's a basic implementation:
using UnityEngine;
using Normal.Realtime;

public class ZombieSpawner : RealtimeComponent
{
[SerializeField] private string _zombiePrefabName;
[SerializeField] private float _spawnInterval = 5f;

private float _nextSpawnTime;

private void Update()
{
// Only run the spawning logic if this client owns the spawner
if (realtimeView.isOwnedLocally)
{
if (Time.time >= _nextSpawnTime)
{
SpawnZombie();
_nextSpawnTime = Time.time + _spawnInterval;
}
}
}

private void SpawnZombie()
{
Realtime.Instantiate(_zombiePrefabName, ownedByClient: false);
}
}
using UnityEngine;
using Normal.Realtime;

public class ZombieSpawner : RealtimeComponent
{
[SerializeField] private string _zombiePrefabName;
[SerializeField] private float _spawnInterval = 5f;

private float _nextSpawnTime;

private void Update()
{
// Only run the spawning logic if this client owns the spawner
if (realtimeView.isOwnedLocally)
{
if (Time.time >= _nextSpawnTime)
{
SpawnZombie();
_nextSpawnTime = Time.time + _spawnInterval;
}
}
}

private void SpawnZombie()
{
Realtime.Instantiate(_zombiePrefabName, ownedByClient: false);
}
}
3. Set up the ZombieSpawner: - Create an empty GameObject in your scene and add the ZombieSpawner script to it. - Add a RealtimeView component to this GameObject. - Set the _zombiePrefabName to match the name of your zombie prefab in the Realtime Prefabs list. 4. Ensure the first player to join takes ownership: You can do this by modifying the ZombieSpawner script to request ownership if it's not owned:
private void Start()
{
if (!realtimeView.isOwnedLocally && Realtime.connected)
{
realtimeView.RequestOwnership();
}
}

public override void OnRealtimeModelReplaced(RealtimeModel previousModel, RealtimeModel currentModel)
{
base.OnRealtimeModelReplaced(previousModel, currentModel);

if (!realtimeView.isOwnedLocally && Realtime.connected)
{
realtimeView.RequestOwnership();
}
}
private void Start()
{
if (!realtimeView.isOwnedLocally && Realtime.connected)
{
realtimeView.RequestOwnership();
}
}

public override void OnRealtimeModelReplaced(RealtimeModel previousModel, RealtimeModel currentModel)
{
base.OnRealtimeModelReplaced(previousModel, currentModel);

if (!realtimeView.isOwnedLocally && Realtime.connected)
{
realtimeView.RequestOwnership();
}
}
This approach ensures that only one client (the owner of the ZombieSpawner) is responsible for spawning zombies, regardless of how many players are in the room. The spawned zombies themselves are not owned by any specific client, allowing all clients to see and interact with them. For more information on ownership and instantiation in Normcore, you can refer to the following documentation: - Ownership (https://normcore.io/documentation/room/ownership-and-lifetime-flags) - Realtime.Instantiate (https://normcore.io/documentation/realtime/realtime) Remember to add your zombie prefab to the Realtime Prefabs list in your Realtime component settings for this to work correctly. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@785692603684225025> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Mechabit
Mechabit2mo ago
do a check for lowest client id before spawning or add a realtime view to the spawner and request ownership of it that way only 1 person will do the spawning
KUTE BONAPARTE
KUTE BONAPARTEOP2mo ago
@kapa.ai can i ask again? how do I make condition if realtimeview does not owned by anyone? ("None" status)
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Certainly! To check if a RealtimeView is not owned by anyone (has a "None" ownership status), you can use the isUnownedSelf property. Here's how you can create a condition to check for this:
if (realtimeView.isUnownedSelf)
{
// The RealtimeView is not owned by anyone
// Your code here
}
if (realtimeView.isUnownedSelf)
{
// The RealtimeView is not owned by anyone
// Your code here
}
This property is available on both RealtimeView and RealtimeComponent classes RealtimeView documentation (https://normcore.io/documentation/reference/classes/Normal.Realtime.RealtimeView). Here's a brief explanation of what isUnownedSelf means: - When isUnownedSelf is true, it indicates that the RealtimeView (or RealtimeComponent) is not owned by any client. - This is equivalent to the "None" status you mentioned. If you want to check this condition and then potentially take ownership if it's unowned, you could do something like this:
if (realtimeView.isUnownedSelf)
{
// The RealtimeView is not owned by anyone
realtimeView.RequestOwnership();
}
if (realtimeView.isUnownedSelf)
{
// The RealtimeView is not owned by anyone
realtimeView.RequestOwnership();
}
Remember that RequestOwnership() is an asynchronous operation. The ownership change won't be immediate, but Normcore will assume it succeeds and allow you to make changes right away. If the server rejects the ownership request for any reason, those changes will be rolled back Requesting ownership documentation (https://normcore.io/documentation/room/ownership-and-lifetime-flags#requesting-ownership-of-a-realtimeview). I hope this helps clarify how to check for and handle unowned RealtimeViews in Normcore! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@785692603684225025> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
KUTE BONAPARTE
KUTE BONAPARTEOP6d ago
thankyou dude 🙂 This was very helpfull! THANKYOUUUUUU 🥰 @kapa.ai how to check the lowest clientID? without any avatarmanager
kapa.ai
kapa.ai6d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- To check for the lowest clientID in Normcore without using an avatar manager, you can leverage the Room class. Here's how you can approach this: 1. First, you need to get access to the Room instance. This is typically available through the Realtime component. 2. The Room class has a clients property which is a dictionary of all connected clients. 3. You can iterate through this dictionary to find the lowest clientID. Here's a code snippet that demonstrates how to do this:
using Normal.Realtime;
using System.Linq;

public class LowestClientIDChecker : RealtimeComponent
{
private void CheckLowestClientID()
{
if (realtime.room != null && realtime.room.connected)
{
int lowestClientID = realtime.room.clients.Keys.Min();
Debug.Log($"The lowest client ID is: {lowestClientID}");

// Check if this client has the lowest ID
if (realtime.clientID == lowestClientID)
{
Debug.Log("This client has the lowest ID!");
}
}
else
{
Debug.Log("Not connected to a room yet.");
}
}
}
using Normal.Realtime;
using System.Linq;

public class LowestClientIDChecker : RealtimeComponent
{
private void CheckLowestClientID()
{
if (realtime.room != null && realtime.room.connected)
{
int lowestClientID = realtime.room.clients.Keys.Min();
Debug.Log($"The lowest client ID is: {lowestClientID}");

// Check if this client has the lowest ID
if (realtime.clientID == lowestClientID)
{
Debug.Log("This client has the lowest ID!");
}
}
else
{
Debug.Log("Not connected to a room yet.");
}
}
}
In this code: 1. We first check if we're connected to a room. 2. We use LINQ's Min() method to find the lowest key (clientID) in the clients dictionary. 3. We then compare it with the local client's ID to see if this client has the lowest ID. You can call the CheckLowestClientID() method whenever you need to perform this check, for example in Start(), Update(), or in response to specific events. Remember that client IDs are assigned by the server when clients connect, so the lowest ID typically (but not always) corresponds to the client that connected first. For more information on the Room class and its properties, you can refer to the Room documentation (https://normcore.io/documentation/reference/classes/Normal.Realtime.Room). This approach allows you to check for the lowest clientID without relying on an avatar manager or any other specific component. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai6d ago
<@785692603684225025> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
KUTE BONAPARTE
KUTE BONAPARTEOP6d ago
@kapa.ai i cant find clients id, theres an error that say 'Room' does not contain a definition for 'clients' and no accessible extension method 'clients' accepting a first argument of type 'Room' could be found (are you missing a using directive or an assembly reference?)
kapa.ai
kapa.ai6d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I apologize for the confusion in my previous answer. It seems that the clients property is not directly accessible on the Room class in the current version of Normcore. Let me provide you with a correct method to find the lowest client ID using the available API. To get the client IDs connected to a room, we can use the GetConnectedClients() method of the Room class. Here's an updated approach:
using Normal.Realtime;
using System.Linq;
using UnityEngine;

public class LowestClientIDChecker : RealtimeComponent
{
private void CheckLowestClientID()
{
if (realtime.room != null && realtime.room.connected)
{
int[] connectedClients = realtime.room.GetConnectedClients();

if (connectedClients.Length > 0)
{
int lowestClientID = connectedClients.Min();
Debug.Log($"The lowest client ID is: {lowestClientID}");

// Check if this client has the lowest ID
if (realtime.clientID == lowestClientID)
{
Debug.Log("This client has the lowest ID!");
}
}
else
{
Debug.Log("No clients connected.");
}
}
else
{
Debug.Log("Not connected to a room yet.");
}
}
}
using Normal.Realtime;
using System.Linq;
using UnityEngine;

public class LowestClientIDChecker : RealtimeComponent
{
private void CheckLowestClientID()
{
if (realtime.room != null && realtime.room.connected)
{
int[] connectedClients = realtime.room.GetConnectedClients();

if (connectedClients.Length > 0)
{
int lowestClientID = connectedClients.Min();
Debug.Log($"The lowest client ID is: {lowestClientID}");

// Check if this client has the lowest ID
if (realtime.clientID == lowestClientID)
{
Debug.Log("This client has the lowest ID!");
}
}
else
{
Debug.Log("No clients connected.");
}
}
else
{
Debug.Log("Not connected to a room yet.");
}
}
}
This corrected version uses the GetConnectedClients() method, which is documented in the Room class reference (https://normcore.io/documentation/reference/classes/Normal.Realtime.Room). This method returns an array of integers representing the client IDs of all connected clients. The rest of the logic remains similar: 1. We check if we're connected to a room. 2. We get the array of connected client IDs. 3. If there are any connected clients, we use LINQ's Min() method to find the lowest ID. 4. We then compare it with the local client's ID to see if this client has the lowest ID. I apologize again for the earlier mistake, and thank you for bringing this to my attention. This updated method should work correctly with the current Normcore API. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai6d ago
<@785692603684225025> Kapa.ai is still learning and improving, please let me know how I did by reacting below.