Implement switching between solo and multiplayer rig seamlessly
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
if (!isSoloRig)
|
||||||
|
{
|
||||||
name = $"Player - {networkObject.OwnerClientId}"
|
name = $"Player - {networkObject.OwnerClientId}"
|
||||||
+ (networkObject.IsLocalPlayer ? " (local)" : "");
|
+ (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)
|
||||||
|
|||||||
@@ -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,21 +10,29 @@ 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 (autoConnectOrHost)
|
||||||
|
{
|
||||||
if (ClonesManager.IsClone())
|
if (ClonesManager.IsClone())
|
||||||
{
|
{
|
||||||
networkManager.StartClient();
|
networkManager.StartClient();
|
||||||
@@ -35,6 +42,7 @@ public class GameManager : NetworkBehaviour
|
|||||||
networkManager.StartHost();
|
networkManager.StartHost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnClientConnectedCallback(ulong clientId)
|
private void OnClientConnectedCallback(ulong clientId)
|
||||||
{
|
{
|
||||||
@@ -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();
|
|
||||||
|
soloRig.Toggle(toSolo);
|
||||||
|
soloRig.Teleport(multiplayerRig.Position, multiplayerRig.Position);
|
||||||
|
multiplayerRig = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
soloRig.Toggle(toSolo);
|
||||||
|
|
||||||
var playerObject = networkManager.LocalClient.PlayerObject;
|
var playerObject = networkManager.LocalClient.PlayerObject;
|
||||||
var player = playerObject.GetComponent<PlayerComponent>();
|
multiplayerRig = playerObject.GetComponent<PlayerComponent>();
|
||||||
player.Teleport(position, rotation);
|
multiplayerRig.Teleport(soloRig.Position, soloRig.Position);
|
||||||
localPlayer = player;
|
multiplayerRig.ToggleAudioListener(true);
|
||||||
yield return null;
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user