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

@@ -24,33 +24,53 @@ public class PlayerComponent : NetworkBehaviour
[SerializeField]
private CharacterController characterController;
[SerializeField]
private AudioListener audioListener;
[ReadOnly]
[SerializeField]
private float fadeDuration = 2f;
public Vector3 Position
{
get { return controller.transform.position; }
}
private GameObject[] dependencies => new GameObject[] {
controller.RightHand.ForceGrabber._anchor.gameObject,
controller.LeftHand.ForceGrabber._anchor.gameObject,
controller.LeftHand._anchor,
controller.RightHand._anchor
};
public Vector3 Rotation
{
get { return controller.transform.eulerAngles; }
}
public Vector3 Position => controller.transform.position;
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()
{
base.OnNetworkSpawn();
name = $"Player - {networkObject.OwnerClientId}"
+ (networkObject.IsLocalPlayer ? " (local)" : "");
if (!isSoloRig)
{
name = $"Player - {networkObject.OwnerClientId}"
+ (networkObject.IsLocalPlayer ? " (local)" : "");
}
if (!networkObject.IsOwner)
if (isMultiplayerRemoteRig)
{
StartCoroutine(DestroyMultiplayerComponents());
}
}
private void Start()
{
if (!isSoloRig) return;
audioListener.enabled = true;
StartCoroutine(DestroySoloComponents());
}
private IEnumerator DestroyMultiplayerComponents()
{
yield return new WaitForEndOfFrame();
@@ -71,18 +91,52 @@ public class PlayerComponent : NetworkBehaviour
controller.RemoveMultiplayerComponents();
}
public void DestroyDependencies()
private IEnumerator DestroySoloComponents()
{
Destroy(controller.RightHand.ForceGrabber._anchor.gameObject);
Destroy(controller.LeftHand.ForceGrabber._anchor.gameObject);
Destroy(controller.LeftHand._anchor);
Destroy(controller.RightHand._anchor);
yield return new WaitForEndOfFrame();
foreach (var t in new[]
{
typeof(NetworkObject),
typeof(NetworkTransform)
})
{
foreach (var component in GetComponentsInChildren(t))
{
Destroy(component);
}
}
}
public void DestroyWithDependencies()
public override void OnDestroy()
{
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)

View File

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