Implement switching between solo and multiplayer rig seamlessly

This commit is contained in:
2024-08-26 16:57:11 +02:00
parent c71f2023df
commit 1edc7850bd
4 changed files with 130 additions and 42 deletions

View File

@@ -44,5 +44,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d357a0b6e2db94a4aadef95ef4fff758, type: 3} m_Script: {fileID: 11500000, guid: d357a0b6e2db94a4aadef95ef4fff758, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
playerPrefab: {fileID: 75161255762383020, guid: 1ef3259331ddc1f4d94b628323ec45f3, soloRig: {fileID: 0}
type: 3} multiplayerRig: {fileID: 0}
networkManager: {fileID: 0}
autoConnectOrHost: 0

View File

@@ -23,6 +23,11 @@ PrefabInstance:
propertyPath: SocketContainer propertyPath: SocketContainer
value: value:
objectReference: {fileID: 2827553962429515486} objectReference: {fileID: 2827553962429515486}
- target: {fileID: 3822188217954140599, guid: 6974999791dc8804fafee05e319aa932,
type: 3}
propertyPath: m_Enabled
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3924027509722682562, guid: 6974999791dc8804fafee05e319aa932, - target: {fileID: 3924027509722682562, guid: 6974999791dc8804fafee05e319aa932,
type: 3} type: 3}
propertyPath: m_Name propertyPath: m_Name
@@ -335,8 +340,8 @@ MonoBehaviour:
teleporter: {fileID: 1079194777950654091} teleporter: {fileID: 1079194777950654091}
controller: {fileID: 75161257133195801} controller: {fileID: 75161257133195801}
characterController: {fileID: 75161257133195802} characterController: {fileID: 75161257133195802}
audioListener: {fileID: 177002782121805273}
fadeDuration: 2 fadeDuration: 2
gameManager: {fileID: 0}
--- !u!1 &75161257133195781 stripped --- !u!1 &75161257133195781 stripped
GameObject: GameObject:
m_CorrespondingSourceObject: {fileID: 3924027509007222379, guid: 6974999791dc8804fafee05e319aa932, m_CorrespondingSourceObject: {fileID: 3924027509007222379, guid: 6974999791dc8804fafee05e319aa932,
@@ -442,6 +447,12 @@ MonoBehaviour:
m_MipBias: 0 m_MipBias: 0
m_VarianceClampScale: 0.9 m_VarianceClampScale: 0.9
m_ContrastAdaptiveSharpening: 0 m_ContrastAdaptiveSharpening: 0
--- !u!81 &177002782121805273 stripped
AudioListener:
m_CorrespondingSourceObject: {fileID: 3822188217954140599, guid: 6974999791dc8804fafee05e319aa932,
type: 3}
m_PrefabInstance: {fileID: 3999184345544213614}
m_PrefabAsset: {fileID: 0}
--- !u!114 &514016263233289054 stripped --- !u!114 &514016263233289054 stripped
MonoBehaviour: MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 3485174680740724528, guid: 6974999791dc8804fafee05e319aa932, m_CorrespondingSourceObject: {fileID: 3485174680740724528, guid: 6974999791dc8804fafee05e319aa932,

View File

@@ -24,33 +24,53 @@ public class PlayerComponent : NetworkBehaviour
[SerializeField] [SerializeField]
private CharacterController characterController; private CharacterController characterController;
[SerializeField]
private AudioListener audioListener;
[ReadOnly] [ReadOnly]
[SerializeField] [SerializeField]
private float fadeDuration = 2f; private float fadeDuration = 2f;
public Vector3 Position private GameObject[] dependencies => new GameObject[] {
{ controller.RightHand.ForceGrabber._anchor.gameObject,
get { return controller.transform.position; } controller.LeftHand.ForceGrabber._anchor.gameObject,
} controller.LeftHand._anchor,
controller.RightHand._anchor
};
public Vector3 Rotation public Vector3 Position => controller.transform.position;
{
get { return controller.transform.eulerAngles; } public Vector3 Rotation => controller.transform.eulerAngles;
}
private bool isSoloRig => !networkObject.IsPlayerObject;
private bool isMultiplayerLocalRig => networkObject.IsLocalPlayer;
private bool isMultiplayerRemoteRig => !networkObject.IsOwner && networkObject.IsPlayerObject;
public override void OnNetworkSpawn() public override void OnNetworkSpawn()
{ {
base.OnNetworkSpawn(); base.OnNetworkSpawn();
name = $"Player - {networkObject.OwnerClientId}" if (!isSoloRig)
+ (networkObject.IsLocalPlayer ? " (local)" : ""); {
name = $"Player - {networkObject.OwnerClientId}"
+ (networkObject.IsLocalPlayer ? " (local)" : "");
}
if (!networkObject.IsOwner) if (isMultiplayerRemoteRig)
{ {
StartCoroutine(DestroyMultiplayerComponents()); StartCoroutine(DestroyMultiplayerComponents());
} }
} }
private void Start()
{
if (!isSoloRig) return;
audioListener.enabled = true;
StartCoroutine(DestroySoloComponents());
}
private IEnumerator DestroyMultiplayerComponents() private IEnumerator DestroyMultiplayerComponents()
{ {
yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame();
@@ -71,18 +91,52 @@ public class PlayerComponent : NetworkBehaviour
controller.RemoveMultiplayerComponents(); controller.RemoveMultiplayerComponents();
} }
public void DestroyDependencies() private IEnumerator DestroySoloComponents()
{ {
Destroy(controller.RightHand.ForceGrabber._anchor.gameObject); yield return new WaitForEndOfFrame();
Destroy(controller.LeftHand.ForceGrabber._anchor.gameObject);
Destroy(controller.LeftHand._anchor); foreach (var t in new[]
Destroy(controller.RightHand._anchor); {
typeof(NetworkObject),
typeof(NetworkTransform)
})
{
foreach (var component in GetComponentsInChildren(t))
{
Destroy(component);
}
}
} }
public void DestroyWithDependencies() public override void OnDestroy()
{ {
DestroyDependencies(); DestroyDependencies();
Destroy(gameObject); base.OnDestroy();
}
public void DestroyDependencies()
{
foreach (var d in dependencies)
{
Destroy(d);
}
}
public void ToggleAudioListener(bool enabled) => audioListener.enabled = enabled;
public void Toggle(bool active)
{
// Only toggle solo rig components, not multiplayer one
if (isSoloRig)
{
foreach (var d in dependencies)
{
d.SetActive(active);
}
audioListener.enabled = active;
gameObject.SetActive(active);
}
} }
public void Teleport(Vector3 position, Vector3 direction) public void Teleport(Vector3 position, Vector3 direction)

View File

@@ -1,6 +1,5 @@
using Sirenix.OdinInspector; using Sirenix.OdinInspector;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using Unity.Netcode; using Unity.Netcode;
using UnityEngine; using UnityEngine;
using Zenject; using Zenject;
@@ -11,28 +10,37 @@ public class GameManager : NetworkBehaviour
[SerializeField] [SerializeField]
[ReadOnly] [ReadOnly]
[Inject] [Inject]
private PlayerComponent localPlayer; private PlayerComponent soloRig;
public PlayerComponent LocalPlayer {
get { return localPlayer; } [SerializeField]
} [ReadOnly]
private PlayerComponent multiplayerRig;
public PlayerComponent LocalPlayer => multiplayerRig ?? soloRig;
[SerializeField] [SerializeField]
[ReadOnly] [ReadOnly]
[Inject] [Inject]
private NetworkManager networkManager; private NetworkManager networkManager;
[SerializeField]
private bool autoConnectOrHost = true;
private void Start() private void Start()
{ {
networkManager.OnClientConnectedCallback += OnClientConnectedCallback; networkManager.OnClientConnectedCallback += OnClientConnectedCallback;
networkManager.OnClientDisconnectCallback += OnClientDisconnectCallback; networkManager.OnClientDisconnectCallback += OnClientDisconnectCallback;
if (ClonesManager.IsClone()) if (autoConnectOrHost)
{ {
networkManager.StartClient(); if (ClonesManager.IsClone())
} {
else networkManager.StartClient();
{ }
networkManager.StartHost(); else
{
networkManager.StartHost();
}
} }
} }
@@ -42,27 +50,40 @@ public class GameManager : NetworkBehaviour
if (networkManager.LocalClientId == clientId) if (networkManager.LocalClientId == clientId)
{ {
StartCoroutine(SpawnLocalPlayer()); StartCoroutine(SwitchSoloMultiplayerRig(false));
} }
} }
private IEnumerator SpawnLocalPlayer() private IEnumerator SwitchSoloMultiplayerRig(bool toSolo)
{ {
yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame();
var position = localPlayer.Position; if (toSolo)
var rotation = localPlayer.Rotation; {
localPlayer.DestroyWithDependencies();
var playerObject = networkManager.LocalClient.PlayerObject; soloRig.Toggle(toSolo);
var player = playerObject.GetComponent<PlayerComponent>(); soloRig.Teleport(multiplayerRig.Position, multiplayerRig.Position);
player.Teleport(position, rotation); multiplayerRig = null;
localPlayer = player; }
yield return null; else
{
soloRig.Toggle(toSolo);
var playerObject = networkManager.LocalClient.PlayerObject;
multiplayerRig = playerObject.GetComponent<PlayerComponent>();
multiplayerRig.Teleport(soloRig.Position, soloRig.Position);
multiplayerRig.ToggleAudioListener(true);
}
} }
private void OnClientDisconnectCallback(ulong clientId) private void OnClientDisconnectCallback(ulong clientId)
{ {
Debug.Log($"Client-{clientId} is disconnected"); Debug.Log($"Client-{clientId} is disconnected");
if (networkManager.LocalClientId == clientId)
{
StartCoroutine(SwitchSoloMultiplayerRig(true));
}
} }
} }