using UnityEngine;
namespace Passer {
using Humanoid;
///
/// The Menu Manager uses two Interaction Pointers for each hand:
/// - An (straight) interaction pointer to interact with the menu when it is active
/// - An (curved) interaction pointer to do teleporting when the menu is not active.
/// Both pairs of interaction pointers needs to be set in the Inspector to work correctly.
///
/// The Menu Manager uses a Trigger Sphere Collider to detect if the user has moved too
/// far the the menu to interact with it.
///
[RequireComponent(typeof(SphereCollider))]
public class MenuManager : MonoBehaviour {
public HumanoidControl humanoid;
public float menuDistance = 0.5F;
public InteractionPointer leftMenuPointer;
public InteractionPointer rightMenuPointer;
public InteractionPointer leftTeleporter;
public InteractionPointer rightTeleporter;
///
/// Initialization
///
protected virtual void Awake() {
// If the humanoid is not set, try to detect the local humanoid player
if (humanoid == null)
humanoid = FindHumanoid();
if (humanoid != null) {
InitInteractionPointers(humanoid);
SetControllerInput(humanoid);
}
// Sphere collider needs to be a trigger collider
SphereCollider collider = GetComponent();
if (collider != null)
collider.isTrigger = true;
// We start with the menu disabled
SetMenuActive(false);
}
///
/// Tries to find the local Humanoid
///
/// The found humanoid, null if no local humanoid has been found
protected HumanoidControl FindHumanoid() {
HumanoidControl[] humanoids = FindObjectsOfType();
for (int i = 0; i < humanoids.Length; i++) {
if (humanoids[i].isRemote == false)
return humanoids[i];
}
return null;
}
///
/// Detects the Teleporter and Menu Interaction pointer on the humanoid
///
/// The humanoid for which the interaction pointers need to be found
protected void InitInteractionPointers(HumanoidControl humanoid) {
leftTeleporter = humanoid.leftHandTarget.GetComponentInChildren();
rightTeleporter = humanoid.rightHandTarget.GetComponentInChildren();
leftMenuPointer = GetInteractionPointer(humanoid.leftHandTarget, leftTeleporter);
rightMenuPointer = GetInteractionPointer(humanoid.rightHandTarget, rightTeleporter);
}
///
/// Find interaction pointer on the hand
///
/// The hand to which the Interaction Pointer should be attached
/// (optional) when give, the interaction pointer should be not euqual to the invalidPointer
/// The found interaction pointer
protected InteractionPointer GetInteractionPointer(HandTarget handTarget, InteractionPointer invalidPointer = null) {
InteractionPointer[] interactionPointers = handTarget.GetComponentsInChildren();
foreach (InteractionPointer interactionPointer in interactionPointers) {
if (interactionPointer != invalidPointer)
return interactionPointer;
}
return null;
}
protected void SetControllerInput(HumanoidControl humanoid) {
ControllerInput controllerInput = humanoid.GetComponent();
if (controllerInput != null) {
//controllerInput.leftOptionInput.SetMethod(SetMenuActive, InputEvent.EventType.Start);
//controllerInput.rightOptionInput.SetMethod(SetMenuActive, InputEvent.EventType.Start);
controllerInput.SetEventHandler(true, ControllerInput.SideButton.Option, SetMenuActive);
controllerInput.SetEventHandler(false, ControllerInput.SideButton.Option, SetMenuActive);
}
}
///
/// Activates or deactivates the menu and updates the interaction pointer behaviour
///
/// Indication whether the menu has to be active
public void SetMenuActive(bool active) {
if (humanoid == null)
return;
ControllerInput controllerInput = humanoid.GetComponent();
// Hide the menu when it is visble (toggle function) or
// when it is set to be inactive explicitly
if (MenuActive() || active == false) {
HideMenu();
DisableMenuPointer(controllerInput);
EnableTeleporter(controllerInput);
}
else {
ShowMenu();
DisableTeleporter(controllerInput);
EnableMenuPointer(controllerInput);
AdjustOutOfRangeDistance();
}
}
///
/// Trigger handler for when an object moves out of the sphere collider
///
protected void OnTriggerExit(Collider other) {
if (MenuActive()) {
// Is it the humanoid exiting the range sphere?
HumanoidControl triggeringHumanoid = other.GetComponentInParent();
if (triggeringHumanoid == humanoid)
SetMenuActive(false);
}
}
///
/// Show the menu at 'distance' from the players' head.
/// But take core it is not placed inside objects.
/// If this happens, the menu is places closer to the humanoid.
///
protected void ShowMenu() {
float distance = menuDistance;
// check if the menu will intersect with an object
RaycastHit hit;
Vector3 direction = humanoid.headTarget.transform.forward;
Vector3 origin = humanoid.headTarget.transform.position + direction * 0.1F;
if (Physics.Raycast(origin, direction, out hit, menuDistance))
distance = hit.distance;
// Position the menu at 'distance' from the player's head
this.transform.position = humanoid.headTarget.transform.TransformPoint(0, 0, distance);
this.transform.rotation = Quaternion.LookRotation(humanoid.headTarget.transform.forward, Vector3.up);
this.gameObject.SetActive(true);
}
///
/// Hide the menu
///
protected void HideMenu() {
this.gameObject.SetActive(false);
}
///
/// Is the menu currently visible?
///
/// boolean indicating whether the menu is visible
protected bool MenuActive() {
return this.gameObject.activeInHierarchy;
}
///
/// Enable the Menu Pointer. This will also set the controller input.
///
/// The ControllerInput to update
protected void EnableMenuPointer(ControllerInput controllerInput) {
// activate the interaction pointer
if (leftMenuPointer != null)
leftMenuPointer.Activation(true);
if (rightMenuPointer != null)
rightMenuPointer.Activation(true);
// enable the button click
if (controllerInput != null) {
if (leftMenuPointer != null)
controllerInput.SetEventHandler(true, ControllerInput.SideButton.Trigger1, leftMenuPointer.Click);
if (rightMenuPointer != null)
controllerInput.SetEventHandler(false, ControllerInput.SideButton.Trigger1, rightMenuPointer.Click);
}
}
///
/// Disable the Menu Pointer. This will also disable the controller input.
///
/// The ControllerInput to update
protected void DisableMenuPointer(ControllerInput controllerInput) {
// deactivate the interaction pointer
if (leftMenuPointer != null)
leftMenuPointer.Activation(false);
if (rightMenuPointer != null)
rightMenuPointer.Activation(false);
// disable the button click
if (controllerInput != null) {
controllerInput.SetEventHandler(true, ControllerInput.SideButton.Trigger1, null);
controllerInput.SetEventHandler(false, ControllerInput.SideButton.Trigger1, null);
}
}
///
/// Enable the teleporter. This will also set the controller input.
///
/// The ControllerInput to update
protected void EnableTeleporter(ControllerInput controllerInput) {
// enable the button activation and click
if (controllerInput != null) {
if (leftTeleporter != null) {
controllerInput.SetEventHandler(true, ControllerInput.SideButton.StickButton, leftTeleporter.Activation);
controllerInput.SetEventHandler(true, ControllerInput.SideButton.Trigger1, leftTeleporter.Click);
}
if (rightTeleporter != null) {
controllerInput.SetEventHandler(false, ControllerInput.SideButton.StickButton, rightTeleporter.Activation);
controllerInput.SetEventHandler(false, ControllerInput.SideButton.Trigger1, rightTeleporter.Click);
}
}
}
///
/// Disable the Teleporter. This will also disable the controller input
///
/// The ControllerInput to update
protected void DisableTeleporter(ControllerInput controllerInput) {
// deactivate the interaction pointer
if (leftTeleporter != null)
leftTeleporter.Activation(false);
if (rightTeleporter != null)
rightTeleporter.Activation(false);
// disable the button activation
if (controllerInput != null) {
controllerInput.SetEventHandler(true, ControllerInput.SideButton.StickButton, null);
controllerInput.SetEventHandler(false, ControllerInput.SideButton.StickButton, null);
}
}
///
/// Adjust trigger sphere collider radius for out-of-range
///
protected void AdjustOutOfRangeDistance() {
SphereCollider collider = GetComponent();
if (collider != null) {
float radius = collider.radius;
if (leftMenuPointer != null)
radius = Mathf.Max(radius, leftMenuPointer.maxDistance);
if (rightMenuPointer != null)
radius = Mathf.Max(radius, rightMenuPointer.maxDistance);
collider.radius = radius;
}
}
}
}