Files
dungeons/Assets/ThirdParty/UltimateXR/Runtime/Scripts/Locomotion/UxrTeleportSpawnCollider.cs

209 lines
8.8 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrTeleportSpawnCollider.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Avatar;
using UltimateXR.Core.Components;
using UnityEngine;
namespace UltimateXR.Locomotion
{
/// <summary>
/// Component that, added to an object with colliders, allows to define volumes that force a fixed teleportation
/// destination when they are hit with teleporting pointers (arc, ray, etc.).
/// </summary>
public class UxrTeleportSpawnCollider : UxrComponent<UxrTeleportSpawnCollider>
{
#region Inspector Properties/Serialized Fields
[SerializeField] private GameObject _enableWhenSelected;
[SerializeField] private Transform _spawnPosOneSide;
[SerializeField] private Transform _spawnPosOptionalOtherSide;
[SerializeField] private Transform _altTargetPosOneSide;
[SerializeField] private Transform _altTargetPosOtherSide;
[SerializeField] private float _heightDistanceFactor = 1.0f;
#endregion
#region Public Types & Data
/// <summary>
/// Event raised when the user was teleported by using the spawn collider.
/// </summary>
public event EventHandler<UxrTeleportSpawnUsedEventArgs> Teleported;
/// <summary>
/// Gets or sets the <see cref="GameObject" /> that will be enabled while the component is being pointed at. This can
/// be used to enable graphics that help identifying the interactivity and destination.
/// </summary>
public GameObject EnableWhenSelected
{
get => _enableWhenSelected;
set => _enableWhenSelected = value;
}
/// <summary>
/// Gets or sets the spawn point the avatar will be teleported to when using the component.
/// In two-sided spawn setups -a ladder that will allow to climb up or down, for example- it represents one of the
/// sides. In the ladder example, it will be either the ground or the top.
/// </summary>
public Transform SpawnPosOneSide
{
get => _spawnPosOneSide;
set => _spawnPosOneSide = value;
}
/// <summary>
/// Gets or sets the other spawn point the avatar can be teleported to when using the component.
/// In single point spawn setups this should be left null. In two-sided spawn setups -a ladder that will allow to climb
/// up or down, for example- it represents the other side where the avatar can be teleported to.
/// In the ladder example it will be either the ground or the top.
/// </summary>
public Transform SpawnPosOptionalOtherSide
{
get => _spawnPosOptionalOtherSide;
set => _spawnPosOptionalOtherSide = value;
}
/// <summary>
/// Gets or sets the alternate target position for <see cref="SpawnPosOneSide" />.
/// When non-null it will override the preview teleport target position for <see cref="SpawnPosOneSide" />.
/// Overriding can be useful to draw the target position on top of a seat, even though the actual spawn position will
/// be at the bottom of the seat.
/// </summary>
public Transform AltTargetPosOneSide
{
get => _altTargetPosOneSide;
set => _altTargetPosOneSide = value;
}
/// <summary>
/// Gets or sets the alternate target position for <see cref="SpawnPosOptionalOtherSide" />.
/// Same as <see cref="AltTargetPosOneSide" /> but for <see cref="SpawnPosOptionalOtherSide" />.
/// </summary>
public Transform AltTargetPosOtherSide
{
get => _altTargetPosOtherSide;
set => _altTargetPosOtherSide = value;
}
/// <summary>
/// Gets or sets the additional factor that the height difference between <see cref="SpawnPosOneSide" /> and
/// <see cref="SpawnPosOptionalOtherSide" /> will play in computing which spawn point is closer.
/// In two-sided spawn setups, the collider will teleport the avatar to the farthest spawn point of the two. This
/// factor helps give more weight to the spawn point that is at a farther ground level.
/// </summary>
public float HeightDistanceFactor
{
get => _heightDistanceFactor;
set => _heightDistanceFactor = value;
}
#endregion
#region Public Methods
/// <summary>
/// If there are two spawn positions (one side and other side) it will return the farthest one to the avatar.
/// This is useful to simulate ladders and other spawn elements that will allow to go from one side to the other.
/// Otherwise it will just return the single spawn position.
/// </summary>
/// <param name="avatar">Avatar</param>
/// <param name="targetPosition">
/// Where the target position should be rendered. This is useful when you want
/// a user to teleport to a chair, where the spawn position would be the base of the chair, but the target
/// should be rendered on top of the seat instead.
/// </param>
/// <returns>Farthest spawn position to the player available</returns>
public Transform GetSpawnPos(UxrAvatar avatar, out Vector3 targetPosition)
{
if (SpawnPosOneSide != null && SpawnPosOptionalOtherSide != null)
{
Vector3 avatarPos = avatar.CameraFloorPosition;
bool isToOtherSide = Distance(avatarPos, SpawnPosOneSide.position) < Distance(avatarPos, SpawnPosOptionalOtherSide.position);
if (isToOtherSide)
{
targetPosition = AltTargetPosOtherSide != null ? AltTargetPosOtherSide.position : SpawnPosOptionalOtherSide.position;
}
else
{
targetPosition = AltTargetPosOneSide != null ? AltTargetPosOneSide.position : SpawnPosOneSide.position;
}
return isToOtherSide ? SpawnPosOptionalOtherSide : SpawnPosOneSide;
}
if (SpawnPosOneSide != null)
{
targetPosition = AltTargetPosOneSide != null ? AltTargetPosOneSide.position : SpawnPosOneSide.position;
return SpawnPosOneSide;
}
if (SpawnPosOptionalOtherSide != null)
{
targetPosition = AltTargetPosOtherSide != null ? AltTargetPosOtherSide.position : SpawnPosOptionalOtherSide.position;
return SpawnPosOptionalOtherSide;
}
targetPosition = transform.position;
return transform;
}
#endregion
#region Unity
/// <summary>
/// Initializes the _enableWhenSelected GameObject if there is one.
/// </summary>
protected override void Start()
{
base.Start();
if (_enableWhenSelected != null)
{
_enableWhenSelected.gameObject.SetActive(false);
}
}
#endregion
#region Event Trigger Methods
/// <summary>
/// Raises the <see cref="Teleported" /> event.
/// </summary>
/// <param name="e">Event parameters</param>
internal void RaiseTeleported(UxrAvatar avatar, UxrAvatarMoveEventArgs e)
{
Teleported?.Invoke(this, new UxrTeleportSpawnUsedEventArgs(avatar, e));
}
#endregion
#region Private Methods
/// <summary>
/// Computes a distance value between the avatar and a spawn position by adding up the linear distance at floor level
/// and the vertical distance. The distance is used to check which spawn position is closer to the user when two spawn
/// positions are available.
/// </summary>
/// <param name="avatarPosition">Avatar position</param>
/// <param name="spawnPosition">Spawn position</param>
/// <returns>Distance (horizontal + vertical).</returns>
private float Distance(Vector3 avatarPosition, Vector3 spawnPosition)
{
float verticalDistance = Mathf.Abs(avatarPosition.y - spawnPosition.y) * HeightDistanceFactor;
Vector3 a = avatarPosition;
Vector3 b = spawnPosition;
a.y = 0.0f;
b.y = 0.0f;
return Vector3.Distance(a, b) + verticalDistance;
}
#endregion
}
}