2025-08-14 20:29:09 +05:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
using DG.Tweening;
|
|
|
|
|
|
2025-09-09 16:46:17 +05:00
|
|
|
|
[RequireComponent(typeof(Collider))]
|
2025-08-14 20:29:09 +05:00
|
|
|
|
public class SmoothChildRotation : MonoBehaviour
|
|
|
|
|
{
|
2025-09-09 16:46:17 +05:00
|
|
|
|
[Header("Door Parts")]
|
|
|
|
|
public Transform targetChild; // door mesh child to rotate
|
|
|
|
|
public string playerTag = "Player";
|
2025-08-14 20:29:09 +05:00
|
|
|
|
|
2025-09-09 16:46:17 +05:00
|
|
|
|
[Header("Door Rotation")]
|
|
|
|
|
public float rotationDuration = 0.5f;
|
|
|
|
|
public Ease rotationEase = Ease.OutQuad;
|
2025-08-14 20:29:09 +05:00
|
|
|
|
public Vector3 targetRotationOnEnter = new Vector3(0, 0, -90);
|
|
|
|
|
public Vector3 targetRotationOnExit = new Vector3(0, 0, 0);
|
|
|
|
|
|
2025-09-09 16:46:17 +05:00
|
|
|
|
[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
|
2025-08-14 20:29:09 +05:00
|
|
|
|
|
2025-09-09 16:46:17 +05:00
|
|
|
|
[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()
|
2025-08-14 20:29:09 +05:00
|
|
|
|
{
|
2025-09-09 16:46:17 +05:00
|
|
|
|
var col = GetComponent<Collider>();
|
|
|
|
|
if (col) col.isTrigger = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Start()
|
|
|
|
|
{
|
|
|
|
|
if (!targetChild)
|
2025-08-14 20:29:09 +05:00
|
|
|
|
{
|
2025-09-09 16:46:17 +05:00
|
|
|
|
Debug.LogError("[SmoothChildRotation] Target child not assigned!", this);
|
2025-08-14 20:29:09 +05:00
|
|
|
|
enabled = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-09 16:46:17 +05:00
|
|
|
|
void OnTriggerEnter(Collider other)
|
2025-08-14 20:29:09 +05:00
|
|
|
|
{
|
2025-09-09 16:46:17 +05:00
|
|
|
|
if (_cutsceneRunning) return;
|
|
|
|
|
if (!other.CompareTag(playerTag)) return;
|
|
|
|
|
|
|
|
|
|
// Open the door
|
|
|
|
|
RotateTo(targetRotationOnEnter);
|
|
|
|
|
|
|
|
|
|
// Start the cutscene
|
|
|
|
|
StartCoroutine(RunDoorCutscene(other));
|
2025-08-14 20:29:09 +05:00
|
|
|
|
}
|
|
|
|
|
|
2025-09-09 16:46:17 +05:00
|
|
|
|
void OnTriggerExit(Collider other)
|
2025-08-14 20:29:09 +05:00
|
|
|
|
{
|
2025-09-09 16:46:17 +05:00
|
|
|
|
if (!other.CompareTag(playerTag)) return;
|
|
|
|
|
if (_cutsceneRunning) return; // don<6F>t close while cutscene is ongoing
|
|
|
|
|
RotateTo(targetRotationOnExit);
|
2025-08-14 20:29:09 +05:00
|
|
|
|
}
|
|
|
|
|
|
2025-09-09 16:46:17 +05:00
|
|
|
|
void RotateTo(Vector3 targetRot)
|
2025-08-14 20:29:09 +05:00
|
|
|
|
{
|
2025-09-09 16:46:17 +05:00
|
|
|
|
_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);
|
2025-08-14 20:29:09 +05:00
|
|
|
|
|
2025-09-09 16:46:17 +05:00
|
|
|
|
_cutsceneRunning = false;
|
2025-08-14 20:29:09 +05:00
|
|
|
|
}
|
|
|
|
|
}
|