paradox
paradox2w ago

Maintaining PlayerID upon scene switching (i.e Player 1 stays Player 1)

I am trying to switch the scene to a new level in my minigolf game but Player 1 is assigned to whoever connects to the new scene the fastest. What should I do to maintain the player order?
6 Replies
kapa.ai
kapa.ai2w ago
Hi @paradox. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To maintain player order (ensuring Player 1 stays Player 1) when switching scenes in your Normcore multiplayer minigolf game, you'll need to use ownership and proper player management. Here's how you can approach this: Use Ownership to Maintain Player Identity Normcore uses an ownership system that can help maintain player identity across scene changes. When you instantiate player prefabs, you can set them to be owned by specific clients, and this ownership persists even when switching scenes. 1. Use a Persistent Player Manager Create a PlayerManager object that uses DontDestroyOnLoad to persist between scenes. This manager can keep track of player IDs and handle player instantiation in new scenes.
using UnityEngine;
using Normal.Realtime;

public class PlayerManager : MonoBehaviour {
[SerializeField] private GameObject _camera = default;
private Realtime _realtime;

private void Awake() {
// Make this object persist between scene loads
DontDestroyOnLoad(gameObject);

// Get the Realtime component on this game object
_realtime = GetComponent<Realtime>();

// Notify us when Realtime successfully connects to the room
_realtime.didConnectToRoom += DidConnectToRoom;
}

private void DidConnectToRoom(Realtime realtime) {
// Instantiate the Player for this client with ownership
GameObject playerGameObject = Realtime.Instantiate(
prefabName: "Player",
ownedByClient: true,
preventOwnershipTakeover: true,
useInstance: realtime);

// Additional setup code...
}
}
using UnityEngine;
using Normal.Realtime;

public class PlayerManager : MonoBehaviour {
[SerializeField] private GameObject _camera = default;
private Realtime _realtime;

private void Awake() {
// Make this object persist between scene loads
DontDestroyOnLoad(gameObject);

// Get the Realtime component on this game object
_realtime = GetComponent<Realtime>();

// Notify us when Realtime successfully connects to the room
_realtime.didConnectToRoom += DidConnectToRoom;
}

private void DidConnectToRoom(Realtime realtime) {
// Instantiate the Player for this client with ownership
GameObject playerGameObject = Realtime.Instantiate(
prefabName: "Player",
ownedByClient: true,
preventOwnershipTakeover: true,
useInstance: realtime);

// Additional setup code...
}
}
2. Use RealtimeView Ownership When instantiating player prefabs, make sure to set ownedByClient: true and preventOwnershipTakeover: true as shown in the example above. This ensures that each client maintains ownership of their player object Creating a Player Controller. 3. Track Player Order with RealtimeAvatarManager You can use the RealtimeAvatarManager to keep track of all players in the room. This manager maintains a dictionary of all avatars indexed by clientID, which you can use to determine player order consistently:
using UnityEngine;
using Normal.Realtime;

public class PlayerOrderManager : MonoBehaviour {
private RealtimeAvatarManager _avatarManager;

private void Awake() {
_avatarManager = GetComponent<RealtimeAvatarManager>();
_avatarManager.avatarCreated += AvatarCreated;
}

private void AvatarCreated(RealtimeAvatarManager avatarManager, RealtimeAvatar avatar, bool isLocalAvatar) {
// You can use avatar.ownerIDInHierarchy to determine consistent player order
// Lower client IDs connected first, so they can be used to maintain order
}
}
using UnityEngine;
using Normal.Realtime;

public class PlayerOrderManager : MonoBehaviour {
private RealtimeAvatarManager _avatarManager;

private void Awake() {
_avatarManager = GetComponent<RealtimeAvatarManager>();
_avatarManager.avatarCreated += AvatarCreated;
}

private void AvatarCreated(RealtimeAvatarManager avatarManager, RealtimeAvatar avatar, bool isLocalAvatar) {
// You can use avatar.ownerIDInHierarchy to determine consistent player order
// Lower client IDs connected first, so they can be used to maintain order
}
}
The RealtimeAvatarManager keeps track of avatars via the avatars property, which is a dictionary of all RealtimeAvatar components stored under the clientID Avatars. 4. Use Persistent Data Between Scenes If you need to maintain specific player data between scenes (like scores or player numbers), you can use a RealtimeComponent with a custom model that persists between scenes:
// Set destroyWhenOwnerOrLastClientLeaves to false to persist between sessions
GameObject persistentData = Realtime.Instantiate("PlayerOrderData", destroyWhenOwnerOrLastClientLeaves: false);
// Set destroyWhenOwnerOrLastClientLeaves to false to persist between sessions
GameObject persistentData = Realtime.Instantiate("PlayerOrderData", destroyWhenOwnerOrLastClientLeaves: false);
This approach uses Normcore's lifetime flags to ensure your player order data persists Lifetime Flags. By combining these approaches, you can ensure that Player 1 remains Player 1 regardless of connection order when switching scenes in your minigolf game. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@219230512298852352> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
paradox
paradoxOP2w ago
@kapa.ai is there any way I can keep the player objects persist through scene changes?
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Yes, you can make player objects persist through scene changes in Normcore. Based on your previous question about maintaining player order, here are two approaches to keep player objects persistent: 1. Use DontDestroyOnLoad The simplest approach is to use Unity's DontDestroyOnLoad on your player objects. This prevents Unity from destroying the objects when loading a new scene:
using UnityEngine;
using Normal.Realtime;

public class PlayerPersistence : MonoBehaviour {
private void Awake() {
// Make this player object persist between scene loads
DontDestroyOnLoad(gameObject);
}
}
using UnityEngine;
using Normal.Realtime;

public class PlayerPersistence : MonoBehaviour {
private void Awake() {
// Make this player object persist between scene loads
DontDestroyOnLoad(gameObject);
}
}
Add this script to your player prefab or call DontDestroyOnLoad from another script when the player is instantiated. 2. Use a Persistent Player Manager For more control, create a manager that handles player instantiation and persistence:
using UnityEngine;
using Normal.Realtime;

public class PersistentPlayerManager : MonoBehaviour {
private Realtime _realtime;
private GameObject _localPlayerObject;

private void Awake() {
// Make the manager persist between scenes
DontDestroyOnLoad(gameObject);
_realtime = GetComponent<Realtime>();
}

private void Start() {
// Subscribe to connection events
_realtime.didConnectToRoom += DidConnectToRoom;
}

private void DidConnectToRoom(Realtime realtime) {
// Create the player if it doesn't exist yet
if (_localPlayerObject == null) {
_localPlayerObject = Realtime.Instantiate(
"PlayerPrefab",
ownedByClient: true,
preventOwnershipTakeover: true,
useInstance: _realtime);

// Make the player object persist
DontDestroyOnLoad(_localPlayerObject);
}
}
}
using UnityEngine;
using Normal.Realtime;

public class PersistentPlayerManager : MonoBehaviour {
private Realtime _realtime;
private GameObject _localPlayerObject;

private void Awake() {
// Make the manager persist between scenes
DontDestroyOnLoad(gameObject);
_realtime = GetComponent<Realtime>();
}

private void Start() {
// Subscribe to connection events
_realtime.didConnectToRoom += DidConnectToRoom;
}

private void DidConnectToRoom(Realtime realtime) {
// Create the player if it doesn't exist yet
if (_localPlayerObject == null) {
_localPlayerObject = Realtime.Instantiate(
"PlayerPrefab",
ownedByClient: true,
preventOwnershipTakeover: true,
useInstance: _realtime);

// Make the player object persist
DontDestroyOnLoad(_localPlayerObject);
}
}
}
Important Considerations 1. Scene Setup: Your new scenes must be designed to work with persistent player objects. Make sure there are no conflicts with scene-specific player spawning. 2. Ownership: As mentioned in your previous question, use ownership settings to maintain player identity. The ownedByClient: true parameter ensures each player maintains control of their character Creating a Player Controller. 3. RealtimeView Connections: When using DontDestroyOnLoad, be aware that RealtimeViews in the scene won't automatically connect to the persistent player objects. You may need to handle this manually. 4. Position Reset: You'll likely want to reset player positions when changing scenes. Consider adding a teleport function to move players to appropriate spawn points in the new scene. 5. Scene Loading: For multiplayer games, you'll need to coordinate scene changes across all clients. One approach is to have a host client trigger the scene change and have other clients follow. This approach should help you maintain player persistence across scene changes in your Normcore-based minigolf game. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@219230512298852352> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Mechabit
Mechabit2w ago
you can use 2 realtimes in your scene, 1 for avatars and one for scene models, which is what I do the avatar realtime persists between scenes as does the avatars or you can store the player number in a static variable or other persistent data and sync it in a model instead of the client id

Did you find this page helpful?