summaryrefslogtreecommitdiff
path: root/Assets/Samples/XR Interaction Toolkit/3.1.2/Starter Assets/Scripts/ObjectSpawner.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Assets/Samples/XR Interaction Toolkit/3.1.2/Starter Assets/Scripts/ObjectSpawner.cs')
-rw-r--r--Assets/Samples/XR Interaction Toolkit/3.1.2/Starter Assets/Scripts/ObjectSpawner.cs237
1 files changed, 237 insertions, 0 deletions
diff --git a/Assets/Samples/XR Interaction Toolkit/3.1.2/Starter Assets/Scripts/ObjectSpawner.cs b/Assets/Samples/XR Interaction Toolkit/3.1.2/Starter Assets/Scripts/ObjectSpawner.cs
new file mode 100644
index 0000000..3b278e0
--- /dev/null
+++ b/Assets/Samples/XR Interaction Toolkit/3.1.2/Starter Assets/Scripts/ObjectSpawner.cs
@@ -0,0 +1,237 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine.XR.Interaction.Toolkit.Utilities;
+
+namespace UnityEngine.XR.Interaction.Toolkit.Samples.StarterAssets
+{
+ /// <summary>
+ /// Behavior with an API for spawning objects from a given set of prefabs.
+ /// </summary>
+ public class ObjectSpawner : MonoBehaviour
+ {
+ [SerializeField]
+ [Tooltip("The camera that objects will face when spawned. If not set, defaults to the main camera.")]
+ Camera m_CameraToFace;
+
+ /// <summary>
+ /// The camera that objects will face when spawned. If not set, defaults to the <see cref="Camera.main"/> camera.
+ /// </summary>
+ public Camera cameraToFace
+ {
+ get
+ {
+ EnsureFacingCamera();
+ return m_CameraToFace;
+ }
+ set => m_CameraToFace = value;
+ }
+
+ [SerializeField]
+ [Tooltip("The list of prefabs available to spawn.")]
+ List<GameObject> m_ObjectPrefabs = new List<GameObject>();
+
+ /// <summary>
+ /// The list of prefabs available to spawn.
+ /// </summary>
+ public List<GameObject> objectPrefabs
+ {
+ get => m_ObjectPrefabs;
+ set => m_ObjectPrefabs = value;
+ }
+
+ [SerializeField]
+ [Tooltip("Optional prefab to spawn for each spawned object. Use a prefab with the Destroy Self component to make " +
+ "sure the visualization only lives temporarily.")]
+ GameObject m_SpawnVisualizationPrefab;
+
+ /// <summary>
+ /// Optional prefab to spawn for each spawned object.
+ /// </summary>
+ /// <remarks>Use a prefab with <see cref="DestroySelf"/> to make sure the visualization only lives temporarily.</remarks>
+ public GameObject spawnVisualizationPrefab
+ {
+ get => m_SpawnVisualizationPrefab;
+ set => m_SpawnVisualizationPrefab = value;
+ }
+
+ [SerializeField]
+ [Tooltip("The index of the prefab to spawn. If outside the range of the list, this behavior will select " +
+ "a random object each time it spawns.")]
+ int m_SpawnOptionIndex = -1;
+
+ /// <summary>
+ /// The index of the prefab to spawn. If outside the range of <see cref="objectPrefabs"/>, this behavior will
+ /// select a random object each time it spawns.
+ /// </summary>
+ /// <seealso cref="isSpawnOptionRandomized"/>
+ public int spawnOptionIndex
+ {
+ get => m_SpawnOptionIndex;
+ set => m_SpawnOptionIndex = value;
+ }
+
+ /// <summary>
+ /// Whether this behavior will select a random object from <see cref="objectPrefabs"/> each time it spawns.
+ /// </summary>
+ /// <seealso cref="spawnOptionIndex"/>
+ /// <seealso cref="RandomizeSpawnOption"/>
+ public bool isSpawnOptionRandomized => m_SpawnOptionIndex < 0 || m_SpawnOptionIndex >= m_ObjectPrefabs.Count;
+
+ [SerializeField]
+ [Tooltip("Whether to only spawn an object if the spawn point is within view of the camera.")]
+ bool m_OnlySpawnInView = true;
+
+ /// <summary>
+ /// Whether to only spawn an object if the spawn point is within view of the <see cref="cameraToFace"/>.
+ /// </summary>
+ public bool onlySpawnInView
+ {
+ get => m_OnlySpawnInView;
+ set => m_OnlySpawnInView = value;
+ }
+
+ [SerializeField]
+ [Tooltip("The size, in viewport units, of the periphery inside the viewport that will not be considered in view.")]
+ float m_ViewportPeriphery = 0.15f;
+
+ /// <summary>
+ /// The size, in viewport units, of the periphery inside the viewport that will not be considered in view.
+ /// </summary>
+ public float viewportPeriphery
+ {
+ get => m_ViewportPeriphery;
+ set => m_ViewportPeriphery = value;
+ }
+
+ [SerializeField]
+ [Tooltip("When enabled, the object will be rotated about the y-axis when spawned by Spawn Angle Range, " +
+ "in relation to the direction of the spawn point to the camera.")]
+ bool m_ApplyRandomAngleAtSpawn = true;
+
+ /// <summary>
+ /// When enabled, the object will be rotated about the y-axis when spawned by <see cref="spawnAngleRange"/>
+ /// in relation to the direction of the spawn point to the camera.
+ /// </summary>
+ public bool applyRandomAngleAtSpawn
+ {
+ get => m_ApplyRandomAngleAtSpawn;
+ set => m_ApplyRandomAngleAtSpawn = value;
+ }
+
+ [SerializeField]
+ [Tooltip("The range in degrees that the object will randomly be rotated about the y axis when spawned, " +
+ "in relation to the direction of the spawn point to the camera.")]
+ float m_SpawnAngleRange = 45f;
+
+ /// <summary>
+ /// The range in degrees that the object will randomly be rotated about the y axis when spawned, in relation
+ /// to the direction of the spawn point to the camera.
+ /// </summary>
+ public float spawnAngleRange
+ {
+ get => m_SpawnAngleRange;
+ set => m_SpawnAngleRange = value;
+ }
+
+ [SerializeField]
+ [Tooltip("Whether to spawn each object as a child of this object.")]
+ bool m_SpawnAsChildren;
+
+ /// <summary>
+ /// Whether to spawn each object as a child of this object.
+ /// </summary>
+ public bool spawnAsChildren
+ {
+ get => m_SpawnAsChildren;
+ set => m_SpawnAsChildren = value;
+ }
+
+ /// <summary>
+ /// Event invoked after an object is spawned.
+ /// </summary>
+ /// <seealso cref="TrySpawnObject"/>
+ public event Action<GameObject> objectSpawned;
+
+ /// <summary>
+ /// See <see cref="MonoBehaviour"/>.
+ /// </summary>
+ void Awake()
+ {
+ EnsureFacingCamera();
+ }
+
+ void EnsureFacingCamera()
+ {
+ if (m_CameraToFace == null)
+ m_CameraToFace = Camera.main;
+ }
+
+ /// <summary>
+ /// Sets this behavior to select a random object from <see cref="objectPrefabs"/> each time it spawns.
+ /// </summary>
+ /// <seealso cref="spawnOptionIndex"/>
+ /// <seealso cref="isSpawnOptionRandomized"/>
+ public void RandomizeSpawnOption()
+ {
+ m_SpawnOptionIndex = -1;
+ }
+
+ /// <summary>
+ /// Attempts to spawn an object from <see cref="objectPrefabs"/> at the given position. The object will have a
+ /// yaw rotation that faces <see cref="cameraToFace"/>, plus or minus a random angle within <see cref="spawnAngleRange"/>.
+ /// </summary>
+ /// <param name="spawnPoint">The world space position at which to spawn the object.</param>
+ /// <param name="spawnNormal">The world space normal of the spawn surface.</param>
+ /// <returns>Returns <see langword="true"/> if the spawner successfully spawned an object. Otherwise returns
+ /// <see langword="false"/>, for instance if the spawn point is out of view of the camera.</returns>
+ /// <remarks>
+ /// The object selected to spawn is based on <see cref="spawnOptionIndex"/>. If the index is outside
+ /// the range of <see cref="objectPrefabs"/>, this method will select a random prefab from the list to spawn.
+ /// Otherwise, it will spawn the prefab at the index.
+ /// </remarks>
+ /// <seealso cref="objectSpawned"/>
+ public bool TrySpawnObject(Vector3 spawnPoint, Vector3 spawnNormal)
+ {
+ if (m_OnlySpawnInView)
+ {
+ var inViewMin = m_ViewportPeriphery;
+ var inViewMax = 1f - m_ViewportPeriphery;
+ var pointInViewportSpace = cameraToFace.WorldToViewportPoint(spawnPoint);
+ if (pointInViewportSpace.z < 0f || pointInViewportSpace.x > inViewMax || pointInViewportSpace.x < inViewMin ||
+ pointInViewportSpace.y > inViewMax || pointInViewportSpace.y < inViewMin)
+ {
+ return false;
+ }
+ }
+
+ var objectIndex = isSpawnOptionRandomized ? Random.Range(0, m_ObjectPrefabs.Count) : m_SpawnOptionIndex;
+ var newObject = Instantiate(m_ObjectPrefabs[objectIndex]);
+ if (m_SpawnAsChildren)
+ newObject.transform.parent = transform;
+
+ newObject.transform.position = spawnPoint;
+ EnsureFacingCamera();
+
+ var facePosition = m_CameraToFace.transform.position;
+ var forward = facePosition - spawnPoint;
+ BurstMathUtility.ProjectOnPlane(forward, spawnNormal, out var projectedForward);
+ newObject.transform.rotation = Quaternion.LookRotation(projectedForward, spawnNormal);
+
+ if (m_ApplyRandomAngleAtSpawn)
+ {
+ var randomRotation = Random.Range(-m_SpawnAngleRange, m_SpawnAngleRange);
+ newObject.transform.Rotate(Vector3.up, randomRotation);
+ }
+
+ if (m_SpawnVisualizationPrefab != null)
+ {
+ var visualizationTrans = Instantiate(m_SpawnVisualizationPrefab).transform;
+ visualizationTrans.position = spawnPoint;
+ visualizationTrans.rotation = newObject.transform.rotation;
+ }
+
+ objectSpawned?.Invoke(newObject);
+ return true;
+ }
+ }
+}