110 lines
3.0 KiB
C#
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);
|
|
}
|
|
}
|
|
|