This commit is contained in:
2026-06-09 09:18:17 +07:00
parent 3578a2750c
commit 71a096556a
5777 changed files with 6675 additions and 13 deletions

View File

@@ -1,36 +0,0 @@
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Game
{
using UnityEngine;
/// <summary>
/// Interface for any kinematic object that can be moved with no parameters.
/// </summary>
public interface IKinematicObject
{
/// <summary>
/// Specifies the location that the object should be updated.
/// </summary>
KinematicObjectManager.UpdateLocation UpdateLocation { get; }
/// <summary>
/// A reference to the object's transform component.
/// </summary>
Transform transform { get; }
/// <summary>
/// Sets the index of the kinematic object.
/// </summary>
int KinematicObjectIndex { set; }
/// <summary>
/// Moves the object.
/// </summary>
void Move();
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 82e30ca7ab725e24fa5b2362030da093
timeCreated: 1519599876
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,70 +0,0 @@
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Game
{
using UnityEngine;
/// <summary>
/// The Kinematic Object component allows an object to be moved outside of the Kinematic Object Manager loop while still being tracked by the Kinematic Object Manager.
/// This component should be used with the Move With Object ability:
/// https://opsive.com/support/documentation/ultimate-character-controller/character/abilities/included-abilities/move-with-object/
/// </summary>
public class KinematicObject : MonoBehaviour, IKinematicObject
{
private Transform m_Transform;
private Vector3 m_LastPosition;
private Quaternion m_LastRotation;
private int m_KinematicObjectIndex;
public int KinematicObjectIndex { set { m_KinematicObjectIndex = value; } }
public KinematicObjectManager.UpdateLocation UpdateLocation { get { return KinematicObjectManager.UpdateLocation.FixedUpdate; } }
/// <summary>
/// Initialize the default values.
/// </summary>
private void Awake()
{
m_Transform = transform;
}
/// <summary>
/// Registers the object with the Kinematic Object Manager.
/// </summary>
public void OnEnable()
{
m_KinematicObjectIndex = KinematicObjectManager.RegisterKinematicObject(this);
m_LastPosition = m_Transform.position;
m_LastRotation = m_Transform.rotation;
}
/// <summary>
/// Updates the position/rotation of the object. The Kinematic Object component should execute after the object has been moved.
/// </summary>
public void FixedUpdate()
{
m_LastPosition = m_Transform.position;
m_LastRotation = m_Transform.rotation;
}
/// <summary>
/// Sets up the object to be moved by the Kinematic Object Manager.
/// </summary>
public void Move()
{
m_Transform.position = m_LastPosition;
m_Transform.rotation = m_LastRotation;
}
/// <summary>
/// Unregisters the object with the Kinematic Object Manager.
/// </summary>
public void OnDisable()
{
KinematicObjectManager.UnregisterKinematicObject(m_KinematicObjectIndex);
}
}
}

View File

@@ -1,13 +0,0 @@
fileFormatVersion: 2
guid: d9ccb9cb210fb444f8daaac8d2c2f133
timeCreated: 1554267520
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 9000
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,13 +0,0 @@
fileFormatVersion: 2
guid: ec179f9473f7f9849bab9aac78619ca9
timeCreated: 1554812395
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -5
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,184 +0,0 @@
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Game
{
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
/// <summary>
/// Singleton object which manages the index values of the Unity layers.
/// </summary>
public class LayerManager : MonoBehaviour
{
private static LayerManager s_Instance;
private static bool s_Initialized;
// Built-in Unity layers.
private const int DefaultLayer = 0;
private const int TransparentFXLayer = 1;
private const int IgnoreRaycastLayer = 2;
private const int WaterLayer = 4;
private const int UILayer = 5;
public static int Default { get { return DefaultLayer; } }
public static int TransparentFX { get { return TransparentFXLayer; } }
public static int IgnoreRaycast { get { return IgnoreRaycastLayer; } }
public static int Water { get { return WaterLayer; } }
public static int UI { get { return UILayer; } }
// Custom layers.
private const int EnemyLayer = 26;
private const int MovingPlatformLayer = 27;
private const int VisualEffectLayer = 28;
private const int OverlayLayer = 29;
private const int SubCharacterLayer = 30;
private const int CharacterLayer = 31;
public static int Enemy { get { return EnemyLayer; } }
public static int MovingPlatform { get { return MovingPlatformLayer; } }
public static int VisualEffect { get { return VisualEffectLayer; } }
public static int Overlay { get { return OverlayLayer; } }
public static int SubCharacter { get { return SubCharacterLayer; } }
public static int Character{ get { return CharacterLayer; } }
private static Dictionary<Collider, List<Collider>> s_IgnoreCollisionMap;
/// <summary>
/// The LayerManager may not have been added to the Game GameObject.
/// </summary>
public static void Initialize()
{
if (!s_Initialized) {
s_Instance = new GameObject("Layer Manager").AddComponent<LayerManager>();
s_Initialized = true;
}
}
/// <summary>
/// The object has been enabled.
/// </summary>
private void OnEnable()
{
// The object may have been enabled outside of the scene unloading.
if (s_Instance == null) {
s_Instance = this;
s_Initialized = true;
SceneManager.sceneUnloaded -= SceneUnloaded;
}
}
/// <summary>
/// Setup the layer collisions.
/// </summary>
private void Awake()
{
Physics.IgnoreLayerCollision(IgnoreRaycast, VisualEffect);
Physics.IgnoreLayerCollision(SubCharacter, Default);
Physics.IgnoreLayerCollision(SubCharacter, VisualEffect);
Physics.IgnoreLayerCollision(VisualEffect, VisualEffect);
Physics.IgnoreLayerCollision(Overlay, Default);
Physics.IgnoreLayerCollision(Overlay, VisualEffect);
Physics.IgnoreLayerCollision(Overlay, Enemy);
Physics.IgnoreLayerCollision(Overlay, SubCharacter);
Physics.IgnoreLayerCollision(Overlay, Character);
}
/// <summary>
/// Ignore the collision between the main collider and the other collider.
/// </summary>
/// <param name="mainCollider">The main collider collision to ignore.</param>
/// <param name="otherCollider">The collider to ignore.</param>
public static void IgnoreCollision(Collider mainCollider, Collider otherCollider)
{
// Keep a mapping of the colliders that mainCollider is ignorning so the collision can easily be reverted.
if (s_IgnoreCollisionMap == null) {
s_IgnoreCollisionMap = new Dictionary<Collider, List<Collider>>();
}
// Add the collider to the list so it can be reverted.
List<Collider> colliderList;
if (!s_IgnoreCollisionMap.TryGetValue(mainCollider, out colliderList)) {
colliderList = new List<Collider>();
s_IgnoreCollisionMap.Add(mainCollider, colliderList);
}
colliderList.Add(otherCollider);
// The otherCollider must also keep track of the mainCollder. This allows otherCollider to be removed before mainCollider.
if (!s_IgnoreCollisionMap.TryGetValue(otherCollider, out colliderList)) {
colliderList = new List<Collider>();
s_IgnoreCollisionMap.Add(otherCollider, colliderList);
}
colliderList.Add(mainCollider);
// Do the actual ignore.
Physics.IgnoreCollision(mainCollider, otherCollider);
}
/// <summary>
/// The main collider should no longer ignore any collisions.
/// </summary>
/// <param name="mainCollider">The collider to revert the collisions on.</param>
public static void RevertCollision(Collider mainCollider)
{
List<Collider> colliderList;
List<Collider> otherColliderList;
// Revert the IgnoreCollision setting on all of the colliders that the object is currently ignoring.
if (s_IgnoreCollisionMap != null && s_IgnoreCollisionMap.TryGetValue(mainCollider, out colliderList)) {
for (int i = 0; i < colliderList.Count; ++i) {
if (!mainCollider.enabled || !mainCollider.gameObject.activeInHierarchy || !colliderList[i].enabled || !colliderList[i].gameObject.activeInHierarchy) {
continue;
}
Physics.IgnoreCollision(mainCollider, colliderList[i], false);
// A two way map was added when the initial IgnoreCollision was added. Remove that second map because the IgnoreCollision has been removed.
if (s_IgnoreCollisionMap.TryGetValue(colliderList[i], out otherColliderList)) {
for (int j = 0; j < otherColliderList.Count; ++j) {
if (otherColliderList[j].Equals(mainCollider)) {
otherColliderList.RemoveAt(j);
break;
}
}
}
}
colliderList.Clear();
}
}
/// <summary>
/// Reset the initialized variable when the scene is no longer loaded.
/// </summary>
/// <param name="scene">The scene that was unloaded.</param>
private void SceneUnloaded(Scene scene)
{
s_Initialized = false;
s_Instance = null;
SceneManager.sceneUnloaded -= SceneUnloaded;
}
/// <summary>
/// The object has been disabled.
/// </summary>
private void OnDisable()
{
SceneManager.sceneUnloaded += SceneUnloaded;
}
#if UNITY_2019_3_OR_NEWER
/// <summary>
/// Reset the static variables for domain reloading.
/// </summary>
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void DomainReset()
{
s_Initialized = false;
s_Instance = null;
}
#endif
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 0f5d94b1cdb36f44e9edf5f60afb90de
timeCreated: 1543541086
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: -600
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,213 +0,0 @@
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Game
{
using UnityEngine;
/// <summary>
/// Specifies a location that the object can spawn.
/// </summary>
public class SpawnPoint : MonoBehaviour
{
/// <summary>
/// Specifies the shape in which the spawn point should randomly be determined.
/// </summary>
public enum SpawnShape
{
Point, // The spawn point will be determined at the transform position.
Sphere, // The spawn point will be determined within a random sphere.
Box // The spawn point will be determined within a box.
}
[Tooltip("An index value used to group multiple sets of spawn points. A value of -1 will ignore the grouping.")]
[SerializeField] protected int m_Grouping = -1;
[Tooltip("Specifies the shape in which the spawn point should randomly be determined.")]
[SerializeField] protected SpawnShape m_Shape;
[Tooltip("The size of the spawn shape.")]
[SerializeField] protected float m_Size;
[Tooltip("Should the object be spawned randomly within the shape?")]
[SerializeField] protected bool m_RandomShapeSpawn = true;
[Tooltip("Specifies the height of the ground check.")]
[SerializeField] protected float m_GroundSnapHeight;
[Tooltip("Should the character spawn with a random y direction?")]
[SerializeField] protected bool m_RandomDirection;
[Tooltip("Should a check be performed to determine if there are any objects obstructing the spawn point?")]
[SerializeField] protected bool m_CheckForObstruction;
[Tooltip("The maximum number of collision points which the spawn points should check against.")]
[SerializeField] protected int m_MaxCollisionCount = 20;
[Tooltip("The layers which can obstruct the spawn point.")]
[SerializeField] protected LayerMask m_ObstructionLayers = ~(1 << LayerManager.Default | 1 << LayerManager.IgnoreRaycast | 1 << LayerManager.TransparentFX |
1 << LayerManager.SubCharacter | 1 << LayerManager.Overlay | 1 << LayerManager.VisualEffect);
[Tooltip("If checking for obstruction, specifies how many times the location should be determined before it is decided that there are no valid spawn locations.")]
[SerializeField] protected int m_PlacementAttempts = 10;
#if UNITY_EDITOR
[Tooltip("The color to draw the editor gizmo in (editor only).")]
[SerializeField] protected Color m_GizmoColor = new Color(1, 0, 0, 0.3f);
#endif
public int Grouping
{
get { return m_Grouping; }
set
{
if (m_Grouping != value) {
// The SpawnPointManager needs to be aware of the change so it can update its internal mapping.
if (Application.isPlaying) {
SpawnPointManager.UpdateSpawnPointGrouping(this, value);
}
m_Grouping = value;
}
}
}
public SpawnShape Shape { get { return m_Shape; } set { m_Shape = value; } }
public float Size { get { return m_Size; } set { m_Size = value; } }
public float GroundSnapHeight { get { return m_GroundSnapHeight; } set { m_GroundSnapHeight = value; } }
public bool RandomDirection { get { return m_RandomDirection; } set { m_RandomDirection = value; } }
public bool CheckForObstruction { get { return m_CheckForObstruction; } set { m_CheckForObstruction = value; } }
public int PlacementAttempts { get { return m_PlacementAttempts; } set { m_PlacementAttempts = value; } }
#if UNITY_EDITOR
public Color GizmoColor { get { return m_GizmoColor; } set { m_GizmoColor = value; } }
#endif
private Transform m_Transform;
private Collider[] m_ObstructionColliders;
/// <summary>
/// Initialize the default values.
/// </summary>
private void Awake()
{
m_Transform = transform;
if (m_CheckForObstruction) {
m_ObstructionColliders = new Collider[m_MaxCollisionCount];
}
}
/// <summary>
/// Adds the spawn point to the manager.
/// </summary>
private void OnEnable()
{
SpawnPointManager.AddSpawnPoint(this);
}
/// <summary>
/// Gets the position and rotation of the spawn point. If false is returned then the point wasn't successfully retrieved.
/// </summary>
/// <param name="spawningObject">The object that is spawning.</param>
/// <param name="position">The position of the spawn point.</param>
/// <param name="rotation">The rotation of the spawn point.</param>
/// <returns>True if the spawn point was successfully retrieved.</returns>
public virtual bool GetPlacement(GameObject spawningObject, ref Vector3 position, ref Quaternion rotation)
{
position = RandomPosition(0);
// Ensure the spawn point is clear of any obstructing objects.
if (m_CheckForObstruction) {
var attempt = 0;
var success = false;
while (attempt < m_PlacementAttempts) {
if (m_Shape == SpawnShape.Point) {
// A point will always succeed.
success = true;
} else if (m_Shape == SpawnShape.Sphere) {
// Ignore any collisions with itself.
var overlapCount = Physics.OverlapSphereNonAlloc(position, m_Size / 2, m_ObstructionColliders, m_ObstructionLayers, QueryTriggerInteraction.Ignore);
if (spawningObject != null) {
for (int i = overlapCount - 1; i > -1; --i) {
if (!m_ObstructionColliders[i].transform.IsChildOf(spawningObject.transform)) {
break;
}
overlapCount--;
}
}
success = overlapCount == 0;
if (success) {
break;
}
} else { // Box.
var extents = Vector3.zero;
extents.x = extents.z = m_Size / 2;
extents.y = m_GroundSnapHeight / 2;
var boxPosition = m_Transform.TransformPoint(extents);
// Ignore any collisions with itself.
var overlapCount = Physics.OverlapBoxNonAlloc(boxPosition, extents, m_ObstructionColliders, m_Transform.rotation, m_ObstructionLayers, QueryTriggerInteraction.Ignore);
for (int i = overlapCount - 1; i > -1; --i) {
if (!m_ObstructionColliders[i].transform.IsChildOf(spawningObject.transform)) {
break;
}
overlapCount--;
}
success = overlapCount == 0;
if (success) {
break;
}
}
++attempt;
position = RandomPosition(attempt);
}
// No valid position was found - return false.
if (!success) {
return false;
}
}
// If the ground snap height is positive then the position should be located on the ground.
if (m_GroundSnapHeight > 0) {
RaycastHit raycastHit;
if (Physics.Raycast(position + m_Transform.up * m_GroundSnapHeight, -m_Transform.up, out raycastHit, m_GroundSnapHeight + 0.2f, m_ObstructionLayers, QueryTriggerInteraction.Ignore)) {
position = raycastHit.point + m_Transform.up * 0.01f;
}
}
// Optionally rotate a random spawn direction.
if (m_RandomDirection) {
rotation = Quaternion.Euler(m_Transform.up * Random.Range(0, 360));
} else {
rotation = m_Transform.rotation;
}
return true;
}
/// <summary>
/// Retruns a position based on the spawn shape.
/// </summary>
/// <param name="attempt">The attempt to position the object.</param>
/// <returns>A position within the spawn spape.</returns>
private Vector3 RandomPosition(int attempt)
{
// Always first try to position in the center.
if (attempt == 0 || !m_RandomShapeSpawn) {
return m_Transform.position;
}
var localPosition = Vector3.zero;
if (m_Shape == SpawnShape.Sphere) {
localPosition = Random.insideUnitSphere * m_Size;
localPosition.y = 0;
} else if (m_Shape == SpawnShape.Box) {
var halfSize = m_Size / 2;
localPosition.x = Random.Range(-halfSize, halfSize);
localPosition.z = Random.Range(-halfSize, halfSize);
}
return m_Transform.TransformPoint(localPosition);
}
/// <summary>
/// Removes the spawn point from the manager.
/// </summary>
private void OnDisable()
{
SpawnPointManager.RemoveSpawnPoint(this);
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 37c3920022c7fba4bb45557e85435be4
timeCreated: 1509974222
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,270 +0,0 @@
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Game
{
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
/// <summary>
/// Determines which SpawnPoint to use in order to determine where the object should spawn.
/// </summary>
public class SpawnPointManager : MonoBehaviour
{
private static SpawnPointManager s_Instance;
private static SpawnPointManager Instance
{
get
{
if (!s_Initialized) {
s_Instance = new GameObject("Spawn Point Manager").AddComponent<SpawnPointManager>();
s_Initialized = true;
}
return s_Instance;
}
}
private static bool s_Initialized;
[Tooltip("Checks the first spawn point before checking the other spawn points.")]
[SerializeField] protected bool m_FirstSpawnPreferred;
private Dictionary<int, List<SpawnPoint>> m_SpawnPointGroupings = new Dictionary<int, List<SpawnPoint>>();
private Dictionary<int, SpawnPoint> m_FirstSpawnPoint = new Dictionary<int, SpawnPoint>();
/// <summary>
/// The object has been enabled.
/// </summary>
private void OnEnable()
{
// The object may have been enabled outside of the scene unloading.
if (s_Instance == null) {
s_Instance = this;
s_Initialized = true;
SceneManager.sceneUnloaded -= SceneUnloaded;
}
}
/// <summary>
/// Adds the specified spawn point to the manager.
/// </summary>
/// <param name="spawnPoint">The spawn point to add.</param>
public static void AddSpawnPoint(SpawnPoint spawnPoint)
{
Instance.AddSpawnPointInternal(spawnPoint);
}
/// <summary>
/// Internal method which adds the specified spawn point to the manager.
/// </summary>
/// <param name="spawnPoint">The spawn point to add.</param>
private void AddSpawnPointInternal(SpawnPoint spawnPoint)
{
AddSpawnPointGrouping(spawnPoint, spawnPoint.Grouping);
}
/// <summary>
/// Adds the SpawnPoint to the specified grouping.
/// </summary>
/// <param name="spawnPoint">The SpawnPoint that should be added.</param>
/// <param name="groupingIndex">The value of the grouping index.</param>
private void AddSpawnPointGrouping(SpawnPoint spawnPoint, int groupingIndex)
{
List<SpawnPoint> spawnPoints;
if (!m_SpawnPointGroupings.TryGetValue(groupingIndex, out spawnPoints)) {
spawnPoints = new List<SpawnPoint>();
m_SpawnPointGroupings.Add(groupingIndex, spawnPoints);
}
spawnPoints.Add(spawnPoint);
if (!m_FirstSpawnPoint.ContainsKey(groupingIndex)) {
m_FirstSpawnPoint.Add(groupingIndex, spawnPoint);
}
}
/// <summary>
/// The SpawnPoint's grouping value has changed. Update the internal group mapping.
/// </summary>
/// <param name="spawnPoint">The SpawnPoint whose grouping value changed.</param>
/// <param name="newGroupingIndex">The new grouping index of the SpawnPoint.</param>
public static void UpdateSpawnPointGrouping(SpawnPoint spawnPoint, int newGroupingIndex)
{
// If the manager isn't initialized yet then the grouping will be updated when the spawn point is added to the manager.
if (!s_Initialized) {
return;
}
Instance.UpdateSpawnPointGroupingInternal(spawnPoint, newGroupingIndex);
}
/// <summary>
/// The SpawnPoint's grouping value has changed. Internal method which updates the internal group mapping.
/// </summary>
/// <param name="spawnPoint">The SpawnPoint whose grouping value changed.</param>
/// <param name="newGroupingIndex">The new grouping value of the SpawnPoint.</param>
private void UpdateSpawnPointGroupingInternal(SpawnPoint spawnPoint, int newGroupingIndex)
{
// Remove from the old grouping map.
RemoveSpawnPoint(spawnPoint);
// Add to the updated grouping map.
AddSpawnPointGrouping(spawnPoint, newGroupingIndex);
}
/// <summary>
/// Gets the position and rotation of the spawn point with the specified grouping.
/// If false is returned then the point wasn't successfully retrieved.
/// </summary>
/// <param name="spawningObject">The object that is spawning.</param>
/// <param name="grouping">The grouping index of spawn points to select from.</param>
/// <param name="position">The position of the spawn point.</param>
/// <param name="rotation">The rotation of the spawn point.</param>
/// <returns>True if the spawn point was successfully retrieved.</returns>
public static bool GetPlacement(GameObject spawningObject, int grouping, ref Vector3 position, ref Quaternion rotation)
{
return Instance.GetPlacementInternal(spawningObject, grouping, ref position, ref rotation);
}
/// <summary>
/// Internal method which gets the position and rotation of the spawn point with the specified grouping.
/// If false is returned then the point wasn't successfully retrieved.
/// </summary>
/// <param name="spawningObject">The object that is spawning.</param>
/// <param name="grouping">The grouping index of spawn points to select from.</param>
/// <param name="position">The position of the spawn point.</param>
/// <param name="rotation">The rotation of the spawn point.</param>
/// <returns>True if the spawn point was successfully retrieved.</returns>
protected virtual bool GetPlacementInternal(GameObject spawningObject, int grouping, ref Vector3 position, ref Quaternion rotation)
{
List<SpawnPoint> spawnPoints;
if (!m_SpawnPointGroupings.TryGetValue(grouping, out spawnPoints)) {
Debug.LogError("Error: Unable to find a spawn point with the grouping index " + grouping);
return false;
}
// Optionally try to spawn in the first spawn point.
SpawnPoint firstSpawnPoint;
if (m_FirstSpawnPreferred && m_FirstSpawnPoint.TryGetValue(grouping, out firstSpawnPoint)) {
if (firstSpawnPoint.GetPlacement(spawningObject, ref position, ref rotation)) {
return true;
}
}
// Choose a random spawn point and get the spawn placement.
ShuffleSpawnPoints(spawnPoints);
var attempt = 0;
while (attempt < spawnPoints.Count) {
if (spawnPoints[attempt].GetPlacement(spawningObject, ref position, ref rotation)) {
return true;
}
attempt++;
}
return false;
}
/// <summary>
/// Shuffles the spawn points list.
/// </summary>
/// <param name="spawnPoints">The list that should be shuffled.</param>
private void ShuffleSpawnPoints(List<SpawnPoint> spawnPoints)
{
var n = spawnPoints.Count - 1;
while (n > 0) {
var k = Random.Range(0, n);
var temp = spawnPoints[n];
spawnPoints[n] = spawnPoints[k];
spawnPoints[k] = temp;
n--;
}
}
/// <summary>
/// Returns the list of spawn points that belong to the specified grouping.
/// </summary>
/// <param name="grouping">The grouping of spawn points that should be retrieved.</param>
/// <returns>The list of spawn points that belong to the specifeid grouping.</returns>
public static List<SpawnPoint> GetSpawnPoints(int grouping)
{
return Instance.GetSpawnPointsInternal(grouping);
}
/// <summary>
/// Internal method which returns the list of spawn points that belong to the specified grouping.
/// </summary>
/// <param name="grouping">The grouping of spawn points that should be retrieved.</param>
/// <returns>The list of spawn points that belong to the specifeid grouping.</returns>
private List<SpawnPoint> GetSpawnPointsInternal(int grouping)
{
List<SpawnPoint> spawnPoints;
if (!m_SpawnPointGroupings.TryGetValue(grouping, out spawnPoints)) {
Debug.LogError("Error: Unable to find a spawn point with the grouping index " + grouping);
}
return spawnPoints;
}
/// <summary>
/// Removes the specified spawn point from the manager.
/// </summary>
/// <param name="spawnPoint">The spawn point to remove.</param>
public static void RemoveSpawnPoint(SpawnPoint spawnPoint)
{
Instance.RemoveSpawnPointInternal(spawnPoint);
}
/// <summary>
/// Internal method which removes the specified spawn point from the manager.
/// </summary>
/// <param name="spawnPoint">The spawn point to remove.</param>
private void RemoveSpawnPointInternal(SpawnPoint spawnPoint)
{
List<SpawnPoint> spawnPoints;
if (m_SpawnPointGroupings.TryGetValue(spawnPoint.Grouping, out spawnPoints)) {
spawnPoints.Remove(spawnPoint);
SpawnPoint firstSpawnPoint;
if (m_FirstSpawnPoint.TryGetValue(spawnPoint.Grouping, out firstSpawnPoint)) {
// Update the first spawn point with the new first spawn point element.
if (spawnPoints.Count > 0) {
m_FirstSpawnPoint[spawnPoint.Grouping] = spawnPoints[0];
} else {
m_FirstSpawnPoint.Remove(spawnPoint.Grouping);
}
}
}
}
/// <summary>
/// The object has been disabled.
/// </summary>
private void OnDisable()
{
SceneManager.sceneUnloaded += SceneUnloaded;
}
/// <summary>
/// Reset the initialized variable when the scene is no longer loaded.
/// </summary>
/// <param name="scene">The scene that was unloaded.</param>
private void SceneUnloaded(Scene scene)
{
s_Initialized = false;
s_Instance = null;
SceneManager.sceneUnloaded -= SceneUnloaded;
}
#if UNITY_2019_3_OR_NEWER
/// <summary>
/// Reset the static variables for domain reloading.
/// </summary>
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void DomainReset()
{
s_Initialized = false;
s_Instance = null;
}
#endif
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: a757f3b80c1feef4a85331d2482be4a1
timeCreated: 1526491565
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: -450
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: