301 lines
9.8 KiB
C#
301 lines
9.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.XR.Interaction.Toolkit;
|
|
|
|
namespace _PROJECT.NewHandPresence
|
|
{
|
|
public class TutorialController : MonoBehaviour
|
|
{
|
|
private enum State
|
|
{
|
|
Initializing,
|
|
Turn,
|
|
Move,
|
|
Teleport,
|
|
WaitForGrip,
|
|
Grip,
|
|
Done
|
|
}
|
|
|
|
public ActionBasedController leftHand;
|
|
public ActionBasedController rightHand;
|
|
|
|
public ActionBasedContinuousMoveProvider moveProvider;
|
|
public ActionBasedSnapTurnProvider turnProvider;
|
|
public TeleportationProvider teleportProvider;
|
|
|
|
public GameObject billboardTemplate;
|
|
|
|
private XRControllerHintController _leftHintController;
|
|
private XRControllerHintController _rightHintController;
|
|
|
|
private SmartHandPresence _leftSmartHandPresence;
|
|
private SmartHandPresence _rightSmartHandPresence;
|
|
|
|
private State _state = State.Initializing;
|
|
|
|
private Camera _camera;
|
|
|
|
private List<XRGrabInteractable> _grabInteractables = new List<XRGrabInteractable>();
|
|
private XRGrabInteractable _grabInteractable;
|
|
|
|
private GameObject _billboard;
|
|
|
|
private void Update()
|
|
{
|
|
if (_state == State.Initializing)
|
|
{
|
|
TryInitialize();
|
|
}
|
|
|
|
if (_state == State.WaitForGrip)
|
|
{
|
|
TryFindXRGrabInteractable();
|
|
}
|
|
}
|
|
|
|
private void TryFindXRGrabInteractable()
|
|
{
|
|
// Find closest interactable in list
|
|
XRGrabInteractable closestInteractable = null;
|
|
var closestDistance = float.MaxValue;
|
|
foreach (var grabInteractable in _grabInteractables)
|
|
{
|
|
var distance = Vector3.Distance(grabInteractable.transform.position, _camera.transform.position);
|
|
if (!(distance < closestDistance)) continue;
|
|
if (grabInteractable.CompareTag("Door")) continue;
|
|
closestDistance = distance;
|
|
closestInteractable = grabInteractable;
|
|
}
|
|
|
|
if (closestInteractable == null) return;
|
|
|
|
_grabInteractable = closestInteractable;
|
|
UpdateState(_state.Next());
|
|
}
|
|
|
|
private void UpdateState(State newState)
|
|
{
|
|
_state = newState;
|
|
Debug.Log($"Tutorial state: {_state}");
|
|
|
|
if (_state == State.Initializing) return;
|
|
SetHandsVisibility(true);
|
|
|
|
_rightHintController.HideHint();
|
|
_leftHintController.HideHint();
|
|
|
|
switch (_state)
|
|
{
|
|
case State.Initializing:
|
|
break;
|
|
case State.Turn:
|
|
ShowTurnHint();
|
|
break;
|
|
case State.Move:
|
|
ShowLocomotionHint();
|
|
break;
|
|
case State.Teleport:
|
|
ShowTeleportHint();
|
|
break;
|
|
case State.WaitForGrip:
|
|
SetHandsVisibility(true);
|
|
break;
|
|
case State.Grip:
|
|
SetHandsVisibility(false);
|
|
CreateBillboard(_grabInteractable.gameObject, "Grab me!");
|
|
ShowGripHint();
|
|
break;
|
|
case State.Done:
|
|
SetHandsVisibility(true);
|
|
DestroyBillboard();
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
private void CreateBillboard(GameObject gmeObject, string gripMe)
|
|
{
|
|
var number = 1 / gmeObject.transform.localScale.x;
|
|
// Create billboard as a child on grab interactable
|
|
_billboard = Instantiate(billboardTemplate, gmeObject.transform);
|
|
// Set local position above grab interactable
|
|
_billboard.transform.localPosition = new Vector3(0, 1, 0);
|
|
// Unscale billboard relative to parent
|
|
_billboard.transform.localScale = Vector3.one * number;
|
|
// Get ControllerTextHint on billboard
|
|
var controllerTextHint = _billboard.GetComponentInChildren<Billboard>();
|
|
// Set text
|
|
controllerTextHint.defaultText = gripMe;
|
|
controllerTextHint.ShowHint(gripMe);
|
|
// Set interactable to outlined layer
|
|
//gmeObject.layer = LayerMask.NameToLayer("Outlined Objects");
|
|
}
|
|
|
|
private void DestroyBillboard()
|
|
{
|
|
Destroy(_billboard);
|
|
}
|
|
|
|
private bool CanInitialize()
|
|
{
|
|
if (leftHand == null || rightHand == null)
|
|
{
|
|
Debug.Log("Left or right hand is null");
|
|
return false;
|
|
}
|
|
|
|
if (turnProvider.rightHandSnapTurnAction.action == null)
|
|
{
|
|
Debug.Log("Right hand snap turn action is null");
|
|
return false;
|
|
}
|
|
|
|
if (moveProvider.leftHandMoveAction.action == null)
|
|
{
|
|
Debug.Log("Left hand move action is null");
|
|
return false;
|
|
}
|
|
|
|
if (teleportProvider == null)
|
|
{
|
|
Debug.Log("Teleport provider is null");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void TryInitialize()
|
|
{
|
|
if (!CanInitialize()) return;
|
|
|
|
_camera = Camera.main;
|
|
|
|
Debug.Log("Initializing tutorial");
|
|
|
|
_leftHintController = leftHand.GetComponentInChildren<XRControllerHintController>();
|
|
_rightHintController = rightHand.GetComponentInChildren<XRControllerHintController>();
|
|
|
|
Debug.Log($"Left hint controller: {_leftHintController}");
|
|
Debug.Log($"Right hint controller: {_rightHintController}");
|
|
|
|
_leftSmartHandPresence = leftHand.GetComponentInChildren<SmartHandPresence>();
|
|
_rightSmartHandPresence = rightHand.GetComponentInChildren<SmartHandPresence>();
|
|
|
|
Debug.Log($"Left smart hand presence: {_leftSmartHandPresence}");
|
|
Debug.Log($"Right smart hand presence: {_rightSmartHandPresence}");
|
|
|
|
if (_leftHintController == null ||
|
|
_rightHintController == null ||
|
|
_leftSmartHandPresence == null ||
|
|
_rightSmartHandPresence == null)
|
|
{
|
|
Debug.Log("Hint controller or smart hand presence is null");
|
|
return;
|
|
}
|
|
|
|
_leftHintController.xrBaseController = leftHand;
|
|
_rightHintController.xrBaseController = rightHand;
|
|
|
|
// Setup action listeners
|
|
turnProvider.rightHandSnapTurnAction.action.performed += OnTurnPerformed;
|
|
moveProvider.leftHandMoveAction.action.performed += OnMovePerformed;
|
|
teleportProvider.endLocomotion += OnTeleportPerformed;
|
|
|
|
leftHand.GetComponent<XRDirectInteractor>().selectEntered.AddListener(OnGripPerformed);
|
|
rightHand.GetComponent<XRDirectInteractor>().selectEntered.AddListener(OnGripPerformed);
|
|
|
|
UpdateState(_state.Next());
|
|
Debug.Log("Tutorial initialized");
|
|
}
|
|
|
|
private void OnGripPerformed(SelectEnterEventArgs arg0)
|
|
{
|
|
if (_state != State.Grip) return;
|
|
Debug.Log("Grip performed");
|
|
UpdateState(_state.Next());
|
|
}
|
|
|
|
private void OnTeleportPerformed(LocomotionSystem obj)
|
|
{
|
|
if (_state != State.Teleport) return;
|
|
Debug.Log("Teleport performed");
|
|
UpdateState(_state.Next());
|
|
}
|
|
|
|
private void OnMovePerformed(InputAction.CallbackContext obj)
|
|
{
|
|
if (_state != State.Move) return;
|
|
Debug.Log("Move performed");
|
|
UpdateState(_state.Next());
|
|
}
|
|
|
|
private void OnTurnPerformed(InputAction.CallbackContext obj)
|
|
{
|
|
if (_state != State.Turn) return;
|
|
Debug.Log("Turn performed");
|
|
UpdateState(_state.Next());
|
|
}
|
|
|
|
private void ShowTeleportHint()
|
|
{
|
|
_rightHintController.ShowTeleportHint();
|
|
_leftHintController.ShowTeleportHint();
|
|
}
|
|
|
|
private void ShowTurnHint()
|
|
{
|
|
_rightHintController.ShowTurnHint();
|
|
_leftHintController.ShowTurnHint();
|
|
}
|
|
|
|
private void ShowLocomotionHint()
|
|
{
|
|
_rightHintController.ShowSmoothLocomotionHint();
|
|
_leftHintController.ShowSmoothLocomotionHint();
|
|
}
|
|
|
|
private void ShowGripHint()
|
|
{
|
|
_rightHintController.ShowGripHint();
|
|
_leftHintController.ShowGripHint();
|
|
}
|
|
|
|
private void SetControllerVisibility(bool visible)
|
|
{
|
|
_leftSmartHandPresence.showController = visible;
|
|
_rightSmartHandPresence.showController = visible;
|
|
}
|
|
|
|
private void SetHandsVisibility(bool visible)
|
|
{
|
|
_leftSmartHandPresence.showHand = visible;
|
|
_rightSmartHandPresence.showHand = visible;
|
|
}
|
|
|
|
private void OnTriggerEnter(Collider other)
|
|
{
|
|
// If has component add to list
|
|
var grabInteractable = other.GetComponent<XRGrabInteractable>();
|
|
if (grabInteractable != null)
|
|
{
|
|
_grabInteractables.Add(grabInteractable);
|
|
}
|
|
}
|
|
|
|
private void OnTriggerExit(Collider other)
|
|
{
|
|
// If has component remove from list
|
|
var grabInteractable = other.GetComponent<XRGrabInteractable>();
|
|
if (grabInteractable != null)
|
|
{
|
|
_grabInteractables.Remove(grabInteractable);
|
|
}
|
|
}
|
|
|
|
}
|
|
} |