382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 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<ElevatorOuter> callers = new List<ElevatorOuter>();
 | |
| 
 | |
|     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<int, Transform> floorDict = new Dictionary<int, Transform>();
 | |
|     [System.Serializable]
 | |
|     public struct FloorNumbers
 | |
|     {
 | |
|         public int floorNumber;
 | |
|         public GameObject floorNumberSprite;
 | |
|     }
 | |
| 
 | |
|     public List<FloorNumbers> 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<XROrigin>() == 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<XROrigin>();
 | |
|         KbmController enteredPlayerKbm = other.GetComponent<KbmController>();
 | |
| 
 | |
|         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<XROrigin>();
 | |
|         KbmController exitedPlayerKbm = other.GetComponent<KbmController>();
 | |
|         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);
 | |
|     }
 | |
| }
 |