using _PROJECT.NewHandPresence; using System.Collections; using System.Collections.Generic; using Unity.XR.CoreUtils; using UnityEditor; using UnityEngine; public enum ElevatorState { Stationary, OpeningDoors, AwaitingPassengers, ClosingDoors, Moving } public class ElevatorBox : MonoBehaviour { public List callers = new List(); public GameObject leftDoor; public Transform leftDoorOpenPos; public Transform leftDoorClosedPos; public GameObject rightDoor; public Transform rightDoorOpenPos; public Transform rightDoorClosedPos; public float doorOpenTime = 4f; public float doorCloseTime = 5.6f; public float floorMoveTime = 5f; public float doorStayOpenTime = 2f; [System.Serializable] public struct FloorData { public int floorNumber; // can be -1, 0, 1, 2 ... public Transform floorPoint; // reference to the transform in scene } // Unity can display arrays/lists of this struct in Inspector public FloorData[] floors; // Runtime dictionary for quick lookup private Dictionary floorDict = new Dictionary(); [System.Serializable] public struct FloorNumbers { public int floorNumber; public GameObject floorNumberSprite; } public List floorDisplayNumbers; public AudioSource audioSource; public AudioClip[] openDoorsClips; public AudioClip[] closeDoorsClips; public AudioClip[] moveElevatorClips; private int currentFloor = 2; private int targetFloor = 2; private ElevatorState state = ElevatorState.Stationary; void Awake() { foreach (var f in floors) { if (!floorDict.ContainsKey(f.floorNumber)) floorDict.Add(f.floorNumber, f.floorPoint); } } private void Start() { updateDisplayFloorNumber(currentFloor); foreach (ElevatorOuter caller in callers) caller.statusPlate.UpdateDisplayFloorNumber(currentFloor); } public IEnumerator callElevator(int floor) { //Debug.Log("Calling Elevator"); Debug.Log(state); if (state == ElevatorState.Stationary || state == ElevatorState.ClosingDoors) { Debug.Log(floor); if (floor != currentFloor) { //Debug.Log("Started moving lift"); yield return StartCoroutine(CloseDoors()); targetFloor = floor; yield return StartCoroutine(MoveToFloor(targetFloor)); } else StartCoroutine(OpenDoors()); SetState(ElevatorState.AwaitingPassengers); } } public void interestExpired() { if (state == ElevatorState.AwaitingPassengers) { if (IsElevatorEmpty()) { StartCoroutine(CloseAndStationary()); } } } private bool IsElevatorEmpty() { return this.GetComponentInChildren() == null; } private void SetState(ElevatorState newstate) { Debug.Log("Setting new state of " + newstate); this.state = newstate; } private void OnTriggerEnter(Collider other) { XROrigin enteredPlayerVR = other.GetComponent(); KbmController enteredPlayerKbm = other.GetComponent(); Debug.Log("Player Entered box"); if (enteredPlayerVR != null) { addChild(enteredPlayerVR); } else if (enteredPlayerKbm != null) { enteredPlayerKbm.transform.SetParent(this.transform); } else return; switch (targetFloor) { case int f when f == floors[0].floorNumber: targetFloor = floors[1].floorNumber; break; case int f when f == floors[1].floorNumber: targetFloor = floors[0].floorNumber; break; default: break; } StartCoroutine(LiftTransferSequence()); } private void OnTriggerExit(Collider other) { // Was it a player, that exited? XROrigin exitedPlayerVR = other.GetComponent(); KbmController exitedPlayerKbm = other.GetComponent(); if (exitedPlayerVR != null) { removeChild(exitedPlayerVR); } else if (exitedPlayerKbm != null) { exitedPlayerKbm.transform.SetParent(null); } else return; Debug.Log("Player exited box, state is: " + this.state); if (this.state == ElevatorState.AwaitingPassengers) { if (IsElevatorEmpty()) { //Debug.Log("Elevator is empty"); StartCoroutine(CloseAndStationary()); } } } private ElevatorOuter findTargetCaller() { //Debug.Log("finding target caller"); foreach (ElevatorOuter caller in this.callers) { //Debug.Log(caller.floor); //Debug.Log(targetFloor); if (caller.floor == targetFloor) { //Debug.Log("found caller"); return caller; } } return null; } private ElevatorOuter findCurrentCaller() { //Debug.Log("finding target caller"); foreach (ElevatorOuter caller in this.callers) { //Debug.Log(caller.floor); //Debug.Log(targetFloor); if (caller.floor == this.currentFloor) { //Debug.Log("found caller"); return caller; } } return null; } private void SetCurrentFloor(int floor) { this.currentFloor = floor; updateDisplayFloorNumber(floor); foreach (ElevatorOuter caller in callers) caller.statusPlate.UpdateDisplayFloorNumber(floor); } private void updateDisplayFloorNumber(int newValue) { foreach (var f in floorDisplayNumbers) { if (f.floorNumber != newValue) f.floorNumberSprite.SetActive(false); else f.floorNumberSprite.SetActive(true); } } public void addChild(XROrigin player) { player.transform.SetParent(this.transform); } public void removeChild(XROrigin player) { player.transform.SetParent(null); } private void playRandomAudioClipFrom(AudioClip[] list) { if (list.Length == 0) return; int index = Random.Range(0, list.Length); audioSource.clip = list[index]; audioSource.Play(); } private IEnumerator LiftTransferSequence() { yield return StartCoroutine(CloseDoors()); yield return StartCoroutine(MoveToFloor(targetFloor)); } public IEnumerator MoveToFloor(int floorNumber) { Debug.Log("Moving to floor " + floorNumber); if (floorDict.TryGetValue(floorNumber, out Transform target)) { yield return StartCoroutine(MoveElevator(target.position)); SetCurrentFloor(targetFloor); } else { Debug.LogWarning($"No floor defined for number {floorNumber}"); } yield return StartCoroutine(OpenDoors()); } private IEnumerator CloseAndStationary() { Debug.Log("Close and set stationary"); // Wait for CloseDoors() to finish yield return StartCoroutine(CloseDoors()); // After doors have closed, set state SetState(ElevatorState.Stationary); } private IEnumerator CloseDoors() { //if (state == ElevatorState.AwaitingPassengers) { //Debug.Log("Closing doors"); if (Vector3.Distance(leftDoor.transform.position, leftDoorClosedPos.position) < 0.01f) yield break; SetState(ElevatorState.ClosingDoors); playRandomAudioClipFrom(closeDoorsClips); ElevatorOuter currentCaller = findCurrentCaller(); if (currentCaller != null) currentCaller.CloseDoors(); yield return StartCoroutine(MoveDoors(leftDoor, leftDoorClosedPos, rightDoor, rightDoorClosedPos, doorCloseTime)); //} } private IEnumerator OpenDoors() { if (state != ElevatorState.AwaitingPassengers) { //Debug.Log("Opening doors"); SetState(ElevatorState.OpeningDoors); playRandomAudioClipFrom(openDoorsClips); ElevatorOuter targetCaller = findTargetCaller(); //Debug.Log("Target caller is: " + targetCaller); if (targetCaller != null) targetCaller.OpenDoors(); yield return StartCoroutine(MoveDoors(leftDoor, leftDoorOpenPos, rightDoor, rightDoorOpenPos, doorOpenTime)); SetState(ElevatorState.AwaitingPassengers); yield return new WaitForSeconds(doorStayOpenTime); // wait for passengers } } private IEnumerator MoveDoors(GameObject left, Transform targetLeft, GameObject right, Transform targetRight, float moveTime) { Debug.Log("Moving doors"); Vector3 startL = left.transform.position; Vector3 startR = right.transform.position; float t = 0; while (t < 1f) { t += Time.deltaTime / moveTime; float easedT = Mathf.SmoothStep(0f, 1f, t); // ease in/out left.transform.position = Vector3.Lerp(startL, targetLeft.position, easedT); right.transform.position = Vector3.Lerp(startR, targetRight.position, easedT); yield return null; } //Debug.Log("Inner Doors moved"); } private IEnumerator MoveElevator(Vector3 targetPos) { if (targetFloor > currentFloor) foreach (ElevatorOuter caller in callers) caller.statusPlate.SetMoveState(ElevatorMoveState.Ascending); else foreach (ElevatorOuter caller in callers) caller.statusPlate.SetMoveState(ElevatorMoveState.Decending); Vector3 startPos = transform.position; float t = 0; SetState(ElevatorState.Moving); playRandomAudioClipFrom(moveElevatorClips); while (t < 1f) { t += Time.deltaTime / floorMoveTime; float easedT = Mathf.SmoothStep(0f, 1f, t); // ease in/out transform.position = Vector3.Lerp(startPos, targetPos, easedT); yield return null; } foreach (ElevatorOuter caller in callers) caller.statusPlate.SetMoveState(ElevatorMoveState.NotMoving); } }