135 lines
4.7 KiB
C#
135 lines
4.7 KiB
C#
using UnityEngine;
|
||
using DG.Tweening;
|
||
|
||
[RequireComponent(typeof(Collider))]
|
||
public class SmoothChildRotation : MonoBehaviour
|
||
{
|
||
[Header("Door Parts")]
|
||
public Transform targetChild; // door mesh child to rotate
|
||
public string playerTag = "Player";
|
||
|
||
[Header("Door Rotation")]
|
||
public float rotationDuration = 0.5f;
|
||
public Ease rotationEase = Ease.OutQuad;
|
||
public Vector3 targetRotationOnEnter = new Vector3(0, 0, -90);
|
||
public Vector3 targetRotationOnExit = new Vector3(0, 0, 0);
|
||
|
||
[Header("Cutscene: Exit Path")]
|
||
[Tooltip("If not set, we use (this.transform.position + this.transform.forward * exitForwardDistance).")]
|
||
public Transform exitPoint;
|
||
public float exitForwardDistance = 3f; // used when exitPoint is null
|
||
public float faceDuration = 0.2f; // how quickly the player faces exit
|
||
|
||
[Header("Cutscene: Anim States")]
|
||
public string celebrationStateName = "Celebration";
|
||
public string walkStateName = "Run"; // or your locomotion state/BT name
|
||
|
||
[Header("Cutscene: Timing")]
|
||
public float celebrationDuration = 1.2f; // seconds to hold Celebration
|
||
public float walkMoveDuration = 1.5f; // seconds to walk to exit
|
||
public Ease walkMoveEase = Ease.Linear;
|
||
|
||
[Header("Behavior")]
|
||
public bool disableTriggerAfterUse = true; // prevents re-entrant triggers
|
||
|
||
private Tween _doorTween;
|
||
private bool _cutsceneRunning;
|
||
|
||
void Reset()
|
||
{
|
||
var col = GetComponent<Collider>();
|
||
if (col) col.isTrigger = true;
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
if (!targetChild)
|
||
{
|
||
Debug.LogError("[SmoothChildRotation] Target child not assigned!", this);
|
||
enabled = false;
|
||
}
|
||
}
|
||
|
||
void OnTriggerEnter(Collider other)
|
||
{
|
||
if (_cutsceneRunning) return;
|
||
if (!other.CompareTag(playerTag)) return;
|
||
|
||
// Open the door
|
||
RotateTo(targetRotationOnEnter);
|
||
|
||
// Start the cutscene
|
||
StartCoroutine(RunDoorCutscene(other));
|
||
}
|
||
|
||
void OnTriggerExit(Collider other)
|
||
{
|
||
if (!other.CompareTag(playerTag)) return;
|
||
if (_cutsceneRunning) return; // don<6F>t close while cutscene is ongoing
|
||
RotateTo(targetRotationOnExit);
|
||
}
|
||
|
||
void RotateTo(Vector3 targetRot)
|
||
{
|
||
_doorTween?.Kill();
|
||
_doorTween = targetChild
|
||
.DOLocalRotate(targetRot, rotationDuration)
|
||
.SetEase(rotationEase);
|
||
}
|
||
|
||
System.Collections.IEnumerator RunDoorCutscene(Collider hit)
|
||
{
|
||
_cutsceneRunning = true;
|
||
if (disableTriggerAfterUse) { var c = GetComponent<Collider>(); if (c) c.enabled = false; }
|
||
|
||
// Find player components
|
||
Transform root = hit.attachedRigidbody ? hit.attachedRigidbody.transform : hit.transform.root;
|
||
var controller = root.GetComponentInChildren<CrateEscapePlayerControllerJoystick>();
|
||
var anim = root.GetComponentInChildren<ZibuAnimDriver>();
|
||
var rb = root.GetComponentInChildren<Rigidbody>();
|
||
|
||
// 1) Freeze player control & velocity
|
||
if (controller) controller.LockControls(true);
|
||
if (rb) { rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; }
|
||
|
||
// 2) Work out exit position / facing
|
||
Vector3 dst = exitPoint ? exitPoint.position : (transform.position + transform.forward * exitForwardDistance);
|
||
if (rb) dst.y = rb.position.y; else dst.y = root.position.y;
|
||
|
||
Vector3 faceDir = dst - root.position; faceDir.y = 0f;
|
||
if (faceDir.sqrMagnitude > 0.0001f)
|
||
{
|
||
Quaternion look = Quaternion.LookRotation(faceDir.normalized, Vector3.up);
|
||
// quick face toward the door exit
|
||
root.DORotateQuaternion(look, faceDuration).SetEase(Ease.OutQuad);
|
||
}
|
||
|
||
// 3) Celebration anim
|
||
if (anim && !string.IsNullOrEmpty(celebrationStateName))
|
||
anim.PlayState(celebrationStateName, 0.1f);
|
||
|
||
yield return new WaitForSeconds(celebrationDuration);
|
||
|
||
// 4) Walk/Run anim
|
||
if (anim && !string.IsNullOrEmpty(walkStateName))
|
||
anim.PlayState(walkStateName, 0.1f);
|
||
|
||
// 5) Move player outside the door
|
||
Tween moveT;
|
||
if (rb != null)
|
||
moveT = rb.DOMove(dst, walkMoveDuration).SetEase(walkMoveEase).SetUpdate(UpdateType.Fixed);
|
||
else
|
||
moveT = root.DOMove(dst, walkMoveDuration).SetEase(walkMoveEase);
|
||
|
||
yield return moveT.WaitForCompletion();
|
||
|
||
// 6) Level complete signal
|
||
CrateEscapeGameManager.Instance?.OnLevelCompleteTriggered();
|
||
|
||
// (Optional) keep controls locked while level completes. Remove next line if you want to give control back:
|
||
// if (controller) controller.LockControls(false);
|
||
|
||
_cutsceneRunning = false;
|
||
}
|
||
}
|