Files
FORT-BO/Assets/CONTENT/Game/Scripts/Interaction/NetworkDoorController.cs
T

110 lines
3.0 KiB
C#

using DG.Tweening;
using Unity.Netcode;
using UnityEngine;
[RequireComponent(typeof(NetworkObject))]
public sealed class NetworkDoorController : NetworkBehaviour
{
[Header("Visual")]
[SerializeField] private Transform doorVisual;
[SerializeField] private Vector3 openLocalPositionOffset = new(0f, 2.5f, 0f);
[SerializeField] private Vector3 openLocalRotationOffset;
[SerializeField, Min(0.01f)] private float animationDuration = 0.65f;
[SerializeField] private Ease animationEase = Ease.OutCubic;
private readonly NetworkVariable<bool> isOpen = new(
false,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server);
private Vector3 closedLocalPosition;
private Vector3 closedLocalEulerAngles;
private Tween doorTween;
public bool IsOpen => isOpen.Value;
private void Awake()
{
if (doorVisual == null)
doorVisual = transform;
closedLocalPosition = doorVisual.localPosition;
closedLocalEulerAngles = doorVisual.localEulerAngles;
}
public override void OnNetworkSpawn()
{
isOpen.OnValueChanged += HandleOpenStateChanged;
ApplyVisualState(isOpen.Value, true);
}
public override void OnNetworkDespawn()
{
isOpen.OnValueChanged -= HandleOpenStateChanged;
}
private void OnDisable()
{
doorTween?.Kill();
}
public void SetOpen(bool shouldOpen)
{
if (!IsServer)
return;
isOpen.Value = shouldOpen;
ApplyVisualState(shouldOpen, false);
}
public void Toggle()
{
SetOpen(!isOpen.Value);
}
[ContextMenu("Preview/Open")]
private void PreviewOpen() => PreviewVisual(true);
[ContextMenu("Preview/Close")]
private void PreviewClose() => PreviewVisual(false);
[ContextMenu("Preview/Toggle")]
private void PreviewToggle() =>
PreviewVisual(doorVisual != null && doorVisual.localPosition == closedLocalPosition);
private void PreviewVisual(bool shouldOpen)
{
ApplyVisualState(shouldOpen, !Application.isPlaying);
}
private void HandleOpenStateChanged(bool _, bool currentValue) =>
ApplyVisualState(currentValue, false);
private void ApplyVisualState(bool shouldOpen, bool immediately)
{
if (doorVisual == null)
return;
doorTween?.Kill();
Vector3 targetPosition = closedLocalPosition +
(shouldOpen ? openLocalPositionOffset : Vector3.zero);
Vector3 targetRotation = closedLocalEulerAngles +
(shouldOpen ? openLocalRotationOffset : Vector3.zero);
if (immediately)
{
doorVisual.localPosition = targetPosition;
doorVisual.localEulerAngles = targetRotation;
return;
}
doorTween = DOTween.Sequence()
.Join(doorVisual.DOLocalMove(targetPosition, animationDuration))
.Join(doorVisual.DOLocalRotate(targetRotation, animationDuration))
.SetEase(animationEase)
.SetLink(gameObject);
}
}