Add StickGame Assets
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoad]
|
||||
#endif
|
||||
public static class ApplicationState
|
||||
{
|
||||
|
||||
#if !UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// True if application is quitting.
|
||||
/// </summary>
|
||||
private static bool _isQuitting;
|
||||
#endif
|
||||
static ApplicationState()
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
_isQuitting = false;
|
||||
#endif
|
||||
Application.quitting -= Application_quitting;
|
||||
Application.quitting += Application_quitting;
|
||||
}
|
||||
|
||||
private static void Application_quitting()
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
_isQuitting = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the application is quitting for editor or builds.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsQuitting()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!EditorApplication.isPlayingOrWillChangePlaymode && EditorApplication.isPlaying)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
#else
|
||||
return _isQuitting;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the application is playing for editor or builds.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsPlaying()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return EditorApplication.isPlaying;
|
||||
#else
|
||||
return Application.isPlaying;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Quits the application for editor or builds.
|
||||
/// </summary>
|
||||
public static void Quit()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorApplication.isPlaying = false;
|
||||
#else
|
||||
Application.Quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54eb82a57a65e8548b57f5ca2a62bb76
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,97 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Arrays
|
||||
{
|
||||
/// <summary>
|
||||
/// Randomizer used for shuffling.
|
||||
/// </summary>
|
||||
private static System.Random _random = new System.Random();
|
||||
|
||||
/// <summary>
|
||||
/// Adds an entry to a list if it does not exist already.
|
||||
/// </summary>
|
||||
/// <returns>True if the entry was added.</returns>
|
||||
public static bool AddUnique<T>(this List<T> list, T value)
|
||||
{
|
||||
bool contains = list.Contains((T)value);
|
||||
if (!contains)
|
||||
list.Add((T)value);
|
||||
|
||||
return !contains;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an object from a list through re-ordering. This breaks the order of the list for a faster remove.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool FastReferenceRemove<T>(this List<T> list, object value)
|
||||
{
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (object.ReferenceEquals(list[i], value))
|
||||
{
|
||||
FastIndexRemove(list, i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an index from a list through re-ordering. This breaks the order of the list for a faster remove.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="index"></param>
|
||||
public static void FastIndexRemove<T>(this List<T> list, int index)
|
||||
{
|
||||
list[index] = list[list.Count - 1];
|
||||
list.RemoveAt(list.Count - 1);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Shuffles an array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="array"></param>
|
||||
public static void Shuffle<T>(this T[] array)
|
||||
{
|
||||
int n = array.Length;
|
||||
for (int i = 0; i < (n - 1); i++)
|
||||
{
|
||||
int r = i + _random.Next(n - i);
|
||||
T t = array[r];
|
||||
array[r] = array[i];
|
||||
array[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuffles a list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="lst"></param>
|
||||
public static void Shuffle<T>(this List<T> lst)
|
||||
{
|
||||
int n = lst.Count;
|
||||
for (int i = 0; i < (n - 1); i++)
|
||||
{
|
||||
int r = i + _random.Next(n - i);
|
||||
T t = lst[r];
|
||||
lst[r] = lst[i];
|
||||
lst[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b93eae9ff81b3e4b892128ca4b392ed
|
||||
timeCreated: 1530140103
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
public static class Booleans
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a boolean to an integer, 1 for true 0 for false.
|
||||
/// </summary>
|
||||
public static int ToInt(this bool b)
|
||||
{
|
||||
return (b) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 602eeac4b016b174f90ae5e85254ac86
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,93 @@
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Ways a CanvasGroup can have it's blocking properties modified.
|
||||
/// </summary>
|
||||
public enum CanvasGroupBlockingType
|
||||
{
|
||||
Unchanged = 0,
|
||||
DoNotBlock = 1,
|
||||
Block = 2,
|
||||
}
|
||||
|
||||
public static class CanvaseGroups
|
||||
{
|
||||
|
||||
public static void SetBlockingType(this CanvasGroup group, CanvasGroupBlockingType blockingType)
|
||||
{
|
||||
if (blockingType == CanvasGroupBlockingType.Unchanged)
|
||||
return;
|
||||
|
||||
bool block = (blockingType == CanvasGroupBlockingType.Block);
|
||||
group.blocksRaycasts = block;
|
||||
group.interactable = block;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a CanvasGroup blocking type and alpha.
|
||||
/// </summary>
|
||||
/// <param name="blockingType">How to handle interactions.</param>
|
||||
/// <param name="alpha">Alpha for CanvasGroup.</param>
|
||||
public static void SetActive(this CanvasGroup group, CanvasGroupBlockingType blockingType, float alpha)
|
||||
{
|
||||
group.SetBlockingType(blockingType);
|
||||
group.alpha = alpha;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a canvasGroup active with specified alpha.
|
||||
/// </summary>
|
||||
public static void SetActive(this CanvasGroup group, float alpha)
|
||||
{
|
||||
group.SetActive(true, false);
|
||||
group.alpha = alpha;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a canvasGroup inactive with specified alpha.
|
||||
/// </summary>
|
||||
public static void SetInactive(this CanvasGroup group, float alpha)
|
||||
{
|
||||
group.SetActive(false, false);
|
||||
group.alpha = alpha;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a group active state by changing alpha and interaction toggles.
|
||||
/// </summary>
|
||||
public static void SetActive(this CanvasGroup group, bool active, bool setAlpha)
|
||||
{
|
||||
if (group == null)
|
||||
return;
|
||||
|
||||
if (setAlpha)
|
||||
{
|
||||
if (active)
|
||||
group.alpha = 1f;
|
||||
else
|
||||
group.alpha = 0f;
|
||||
}
|
||||
|
||||
group.interactable = active;
|
||||
group.blocksRaycasts = active;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a group active state by changing alpha and interaction toggles with a custom alpha.
|
||||
/// </summary>
|
||||
public static void SetActive(this CanvasGroup group, bool active, float alpha)
|
||||
{
|
||||
if (group == null)
|
||||
return;
|
||||
|
||||
group.alpha = alpha;
|
||||
|
||||
group.interactable = active;
|
||||
group.blocksRaycasts = active;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0e7937b287d3d24d807a115c1a3a464
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
public static class DictionaryFN
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Uses a hacky way to TryGetValue on a dictionary when using IL2CPP and on mobile.
|
||||
/// This is to support older devices that don't properly handle IL2CPP builds.
|
||||
/// </summary>
|
||||
public static bool TryGetValueIL2CPP<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, out TValue value)
|
||||
{
|
||||
#if ENABLE_IL2CPP && UNITY_IOS || UNITY_ANDROID
|
||||
if (dict.ContainsKey(key))
|
||||
{
|
||||
value = dict[key];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return dict.TryGetValue(key, out value);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d31d19bc39eb6041bad18d8eb68ed68
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
102
phr/StickGame/Assets/FishNet/Plugins/GameKit/Utilities/Disks.cs
Normal file
102
phr/StickGame/Assets/FishNet/Plugins/GameKit/Utilities/Disks.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Disks
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Writes specified text to a file path.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="formatPath">True to format the path to the current platform.</param>
|
||||
public static void WriteToFile(string text, string path, bool formatPath = true)
|
||||
{
|
||||
//If to format the path for the platform.
|
||||
if (formatPath)
|
||||
path = FormatPlatformPath(path);
|
||||
|
||||
//Path came back or was passed in as an empty string.
|
||||
if (path == string.Empty)
|
||||
{
|
||||
Debug.LogError("Path cannot be null.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//Get directory path.
|
||||
string directory = Path.GetDirectoryName(path);
|
||||
//If directory doesn't exist try to create it.
|
||||
if (!Directory.Exists(directory))
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
//Try to write the file data.
|
||||
using (FileStream fs = new FileStream(path, FileMode.Create))
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(fs))
|
||||
writer.Write(text);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"An error occured during a file write. Error: {ex.Message} {Environment.NewLine} File path: {path} {Environment.NewLine} Text: {text}");
|
||||
}
|
||||
|
||||
/* If within the editor then refresh the asset database so changes
|
||||
* reflect in the project folder. */
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.AssetDatabase.Refresh();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a file path to the current platform.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatPlatformPath(string path)
|
||||
{
|
||||
//No path specified.
|
||||
if (path == string.Empty)
|
||||
{
|
||||
Debug.LogError("Path cannot be empty.");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string convertedPath = string.Empty;
|
||||
|
||||
//Get the directories as an array.
|
||||
string[] directories = path.Split(Path.DirectorySeparatorChar);
|
||||
|
||||
//Go through each directory.
|
||||
for (int i = 0; i < directories.Length; i++)
|
||||
{
|
||||
/* If only one entry in array then the path
|
||||
* is in the root of the Resources folder. */
|
||||
if (directories.Length == 1)
|
||||
{
|
||||
//Append to converted path and break from the loop.
|
||||
convertedPath = directories[i];
|
||||
break;
|
||||
}
|
||||
//More than one entry, meaning there are sub paths.
|
||||
else
|
||||
{
|
||||
/* Set converted path to the current
|
||||
* convertedPath combined with the next directory. */
|
||||
convertedPath = Path.Combine(convertedPath, directories[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return convertedPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3a909760282d284591c20c873f20837
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public enum EditorLayoutEnableType
|
||||
{
|
||||
Enabled = 0,
|
||||
Disabled = 1,
|
||||
DisabledWhilePlaying = 2
|
||||
}
|
||||
public static class Editing
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Adds a property field.
|
||||
/// </summary>
|
||||
public static void AddPropertyField(SerializedProperty sp, GUIContent guiContent, EditorLayoutEnableType enableType = EditorLayoutEnableType.Enabled, params GUILayoutOption[] options)
|
||||
{
|
||||
bool disable = DisableLayout(enableType);
|
||||
if (disable)
|
||||
GUI.enabled = false;
|
||||
|
||||
EditorGUILayout.PropertyField(sp, guiContent, options);
|
||||
|
||||
if (disable)
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an object field.
|
||||
/// </summary>
|
||||
public static void AddObjectField(string label, MonoScript ms, Type type, bool allowSceneObjects, EditorLayoutEnableType enableType = EditorLayoutEnableType.Enabled, params GUILayoutOption[] options)
|
||||
{
|
||||
bool disable = DisableLayout(enableType);
|
||||
if (disable)
|
||||
GUI.enabled = false;
|
||||
|
||||
EditorGUILayout.ObjectField("Script:", ms, type, allowSceneObjects, options);
|
||||
|
||||
if (disable)
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables GUI if playing.
|
||||
/// </summary>
|
||||
public static void DisableGUIIfPlaying()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
GUI.enabled = false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Enables GUI if playing.
|
||||
/// </summary>
|
||||
public static void EnableGUIIfPlaying()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a layout field should be disabled.
|
||||
/// </summary>
|
||||
/// <param name="enableType"></param>
|
||||
/// <returns></returns>
|
||||
private static bool DisableLayout(EditorLayoutEnableType enableType)
|
||||
{
|
||||
return (enableType == EditorLayoutEnableType.Disabled || (enableType == EditorLayoutEnableType.DisabledWhilePlaying && Application.isPlaying));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd42f76391fc1254f82767dbf1a4bc8b
|
||||
timeCreated: 1525378031
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
130
phr/StickGame/Assets/FishNet/Plugins/GameKit/Utilities/Enums.cs
Normal file
130
phr/StickGame/Assets/FishNet/Plugins/GameKit/Utilities/Enums.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
|
||||
public static class Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine an enum value from a given string. This can be an expensive function.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="text">Text of string.</param>
|
||||
/// <param name="defaultValue">Default value if enum couldn't be found.</param>
|
||||
/// <returns>Enum found or default value if no enum is found.</returns>
|
||||
public static T FromString<T>(string text, T defaultValue)
|
||||
{
|
||||
//If string is empty or null return default value.
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return defaultValue;
|
||||
//If enum isn't defined return default value.
|
||||
if (!Enum.IsDefined(typeof(T), (string)text))
|
||||
return defaultValue;
|
||||
//Return parsed value.
|
||||
return (T)Enum.Parse(typeof(T), text, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if whole(extended enum) has any of the part values.
|
||||
/// </summary>
|
||||
/// <param name="whole"></param>
|
||||
/// <param name="part">Values to check for within whole.</param>
|
||||
/// <returns>Returns true part is within whole.</returns>
|
||||
public static bool Contains(this Enum whole, Enum part)
|
||||
{
|
||||
//If not the same type of Enum return false.
|
||||
/* Commented out for performance. Designer
|
||||
* should know better than to compare two different
|
||||
* enums. */
|
||||
//if (!SameType(value, target))
|
||||
// return false;
|
||||
|
||||
/* Convert enum values to ulong. With so few
|
||||
* values a uint would be safe, but should
|
||||
* the options expand ulong is safer. */
|
||||
ulong wholeNum = Convert.ToUInt64(whole);
|
||||
ulong partNum = Convert.ToUInt64(part);
|
||||
|
||||
return ((wholeNum & partNum) != 0);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns if part values contains any of whole(extended enum).
|
||||
/// </summary>
|
||||
/// <param name="whole"></param>
|
||||
/// <param name="part"></param>
|
||||
/// <returns>Returns true whole is within part.</returns>
|
||||
public static bool ReverseContains(this Enum whole, Enum part)
|
||||
{
|
||||
//If not the same type of Enum return false.
|
||||
/* Commented out for performance. Designer
|
||||
* should know better than to compare two different
|
||||
* enums. */
|
||||
//if (!SameType(value, target))
|
||||
// return false;
|
||||
|
||||
/* Convert enum values to ulong. With so few
|
||||
* values a uint would be safe, but should
|
||||
* the options expand ulong is safer. */
|
||||
ulong wholeNum = Convert.ToUInt64(whole);
|
||||
ulong partNum = Convert.ToUInt64(part);
|
||||
|
||||
return ((partNum & wholeNum) != 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if an enum equals a specified value.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Equals(this Enum value, Enum target)
|
||||
{
|
||||
//If not the same type of Enum return false.
|
||||
/* Commented out for performance. Designer
|
||||
* should know better than to compare two different
|
||||
* enums. */
|
||||
//if (!SameType(value, target))
|
||||
// return false;
|
||||
|
||||
ulong valueNum = Convert.ToUInt64(value);
|
||||
ulong wholeNum = Convert.ToUInt64(target);
|
||||
|
||||
return (valueNum == wholeNum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a is the same Enum as b.
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <returns></returns>
|
||||
public static bool SameType(Enum a, Enum b)
|
||||
{
|
||||
return (a.GetType() == b.GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the highest numeric value for T.
|
||||
/// </summary>
|
||||
public static int GetHighestValue<T>()
|
||||
{
|
||||
Type enumType = typeof(T);
|
||||
/* Brute force enum values.
|
||||
* Linq Last/Max lookup throws for IL2CPP. */
|
||||
int highestValue = 0;
|
||||
Array pidValues = Enum.GetValues(enumType);
|
||||
foreach (T pid in pidValues)
|
||||
{
|
||||
object obj = Enum.Parse(enumType, pid.ToString());
|
||||
int value = Convert.ToInt32(obj);
|
||||
highestValue = Math.Max(highestValue, value);
|
||||
}
|
||||
|
||||
return highestValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6c66aec505f9254491b2b126a2d4745
|
||||
timeCreated: 1522959833
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
232
phr/StickGame/Assets/FishNet/Plugins/GameKit/Utilities/Floats.cs
Normal file
232
phr/StickGame/Assets/FishNet/Plugins/GameKit/Utilities/Floats.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Floats
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to randomize float values.
|
||||
/// </summary>
|
||||
private static System.Random _random = new System.Random();
|
||||
|
||||
/// <summary>
|
||||
/// Sets a source float to value if equal to or greater than tolerance.
|
||||
/// </summary>
|
||||
/// <param name="source">Float to check against tolerance.</param>
|
||||
/// <param name="tolerance">Tolerance float must be equal to or greater than to change to value.</param>
|
||||
/// <param name="value">Value source is set to when breaking tolerance.</param>
|
||||
public static float SetIfOverTolerance(this float source, float tolerance, float value)
|
||||
{
|
||||
if (source >= tolerance)
|
||||
source = value;
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a source float to value if equal to or less than tolerance.
|
||||
/// </summary>
|
||||
/// <param name="source">Float to check against tolerance.</param>
|
||||
/// <param name="tolerance">Tolerance float must be equal to or less than to change to value.</param>
|
||||
/// <param name="value">Value source is set to when breaking tolerance.</param>
|
||||
public static float SetIfUnderTolerance(this float source, float tolerance, float value)
|
||||
{
|
||||
if (source <= tolerance)
|
||||
source = value;
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns how much time is left on an endTime. Returns -1 if no time is left.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static float TimeRemainingValue(this float endTime)
|
||||
{
|
||||
float remaining = endTime - Time.time;
|
||||
//None remaining.
|
||||
if (remaining < 0f)
|
||||
return -1f;
|
||||
|
||||
return (endTime - Time.time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns how much time is left on an endTime. Returns -1 if no time is left.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static int TimeRemainingValue(this float endTime, bool useFloor = true)
|
||||
{
|
||||
float remaining = endTime - Time.time;
|
||||
//None remaining.
|
||||
if (remaining < 0f)
|
||||
return -1;
|
||||
|
||||
float result = (endTime - Time.time);
|
||||
return (useFloor) ? Mathf.FloorToInt(result) : Mathf.CeilToInt(result);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns time remaining as a string using hh:mm:ss.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="segments">Number of places to return. 1 is seconds, 2 is minutes, 3 is hours. If a placement does not exist it is replaced with 00.</param>
|
||||
/// <param name="emptyOnZero">True to return an empty string when value is 0 or less.</param>
|
||||
/// <returns></returns>
|
||||
public static string TimeRemainingText(this float value, byte segments, bool emptyOnZero = false)
|
||||
{
|
||||
if (emptyOnZero && value <= 0f)
|
||||
return string.Empty;
|
||||
|
||||
int timeRounded = Math.Max(Mathf.RoundToInt(value), 0);
|
||||
TimeSpan t = TimeSpan.FromSeconds(timeRounded);
|
||||
|
||||
int hours = Mathf.FloorToInt(t.Hours);
|
||||
int minutes = Mathf.FloorToInt(t.Minutes);
|
||||
int seconds = Mathf.FloorToInt(t.Seconds);
|
||||
|
||||
string timeText;
|
||||
if (segments == 1)
|
||||
{
|
||||
seconds += (minutes * 60);
|
||||
seconds += (hours * 3600);
|
||||
timeText = string.Format("{0:D2}", seconds);
|
||||
}
|
||||
else if (segments == 2)
|
||||
{
|
||||
minutes += (hours * 60);
|
||||
timeText = string.Format("{0:D2}:{1:D2}", minutes, seconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
timeText = string.Format("{0:D2}:{1:D2}:{2:D2}", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
return timeText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a random inclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
|
||||
/// </summary>
|
||||
/// <param name="minimum">Inclusive minimum value.</param>
|
||||
/// <param name="maximum">Inclusive maximum value.</param>
|
||||
/// <returns></returns>
|
||||
public static float RandomInclusiveRange(float minimum, float maximum)
|
||||
{
|
||||
double min = Convert.ToDouble(minimum);
|
||||
double max = Convert.ToDouble(maximum);
|
||||
|
||||
double result = (_random.NextDouble() * (max - min)) + min;
|
||||
return Convert.ToSingle(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random float between 0f and 1f.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static float Random01()
|
||||
{
|
||||
return RandomInclusiveRange(0f, 1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a target float is within variance of the source float.
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <param name="tolerance"></param>
|
||||
public static bool Near(this float a, float b, float tolerance = 0.01f)
|
||||
{
|
||||
return (Mathf.Abs(a - b) <= tolerance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps a float and returns if the float required clamping.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <param name="clamped"></param>
|
||||
/// <returns></returns>
|
||||
public static float Clamp(float value, float min, float max, ref bool clamped)
|
||||
{
|
||||
clamped = (value < min);
|
||||
if (clamped)
|
||||
return min;
|
||||
|
||||
clamped = (value > min);
|
||||
if (clamped)
|
||||
return max;
|
||||
|
||||
clamped = false;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a float after being adjusted by the specified variance.
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="variance"></param>
|
||||
/// <returns></returns>
|
||||
public static float Variance(this float source, float variance)
|
||||
{
|
||||
float pickedVariance = RandomInclusiveRange(1f - variance, 1f + variance);
|
||||
return (source * pickedVariance);
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets a float value to result after being adjusted by the specified variance.
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="variance"></param>
|
||||
/// <returns></returns>
|
||||
public static void Variance(this float source, float variance, ref float result)
|
||||
{
|
||||
float pickedVariance = RandomInclusiveRange(1f - variance, 1f + variance);
|
||||
result = (source * pickedVariance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns negative-one, zero, or postive-one of a value instead of just negative-one or positive-one.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to sign.</param>
|
||||
/// <returns>Precise sign.</returns>
|
||||
public static float PreciseSign(float value)
|
||||
{
|
||||
if (value == 0f)
|
||||
return 0f;
|
||||
else
|
||||
return (Mathf.Sign(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a float is within a range.
|
||||
/// </summary>
|
||||
/// <param name="source">Value of float.</param>
|
||||
/// <param name="rangeMin">Minimum of range.</param>
|
||||
/// <param name="rangeMax">Maximum of range.</param>
|
||||
/// <returns></returns>
|
||||
public static bool InRange(this float source, float rangeMin, float rangeMax)
|
||||
{
|
||||
return (source >= rangeMin && source <= rangeMax);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Randomly flips a float value.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static float RandomlyFlip(this float value)
|
||||
{
|
||||
if (Ints.RandomInclusiveRange(0, 1) == 0)
|
||||
return value;
|
||||
else
|
||||
return (value *= -1f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ab517aa5c3b6e34ca20461339adda04
|
||||
timeCreated: 1526172456
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "GameKit.Utilities",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||
"GUID:36bccdedfe0feeb4daf43bef9e43b65b"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.textmeshpro",
|
||||
"expression": "",
|
||||
"define": "TEXTMESHPRO"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17013b2a21298c14ea4808251346a38a
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,85 @@
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Hashing
|
||||
{
|
||||
|
||||
private const uint FNV_offset_basis32 = 2166136261;
|
||||
private const uint FNV_prime32 = 16777619;
|
||||
private const ulong FNV_offset_basis64 = 14695981039346656037;
|
||||
private const ulong FNV_prime64 = 1099511628211;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// non cryptographic stable hash code,
|
||||
/// it will always return the same hash for the same
|
||||
/// string.
|
||||
///
|
||||
/// This is simply an implementation of FNV-1 32 bit xor folded to 16 bit
|
||||
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||
/// </summary>
|
||||
/// <returns>The stable hash32.</returns>
|
||||
/// <param name="txt">Text.</param>
|
||||
public static ushort GetStableHashU16(this string txt)
|
||||
{
|
||||
uint hash32 = txt.GetStableHashU32();
|
||||
|
||||
return (ushort)((hash32 >> 16) ^ hash32);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// non cryptographic stable hash code,
|
||||
/// it will always return the same hash for the same
|
||||
/// string.
|
||||
///
|
||||
/// This is simply an implementation of FNV-1 32 bit
|
||||
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||
/// </summary>
|
||||
/// <returns>The stable hash32.</returns>
|
||||
/// <param name="txt">Text.</param>
|
||||
public static uint GetStableHashU32(this string txt)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint hash = FNV_offset_basis32;
|
||||
for (int i = 0; i < txt.Length; i++)
|
||||
{
|
||||
uint ch = txt[i];
|
||||
hash = hash * FNV_prime32;
|
||||
hash = hash ^ ch;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// non cryptographic stable hash code,
|
||||
/// it will always return the same hash for the same
|
||||
/// string.
|
||||
///
|
||||
/// This is simply an implementation of FNV-1 64 bit
|
||||
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||
/// </summary>
|
||||
/// <returns>The stable hash32.</returns>
|
||||
/// <param name="txt">Text.</param>
|
||||
public static ulong GetStableHashU64(this string txt)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
ulong hash = FNV_offset_basis64;
|
||||
for (int i = 0; i < txt.Length; i++)
|
||||
{
|
||||
ulong ch = txt[i];
|
||||
hash = hash * FNV_prime64;
|
||||
hash = hash ^ ch;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a54dd369b7206e4f9e7716a42e53454
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Various utility classes relating to floats.
|
||||
/// </summary>
|
||||
public static class Ints
|
||||
{
|
||||
private static System.Random _random = new System.Random();
|
||||
|
||||
/// <summary>
|
||||
/// Pads an index a specified value. Preferred over typical padding so that pad values used with skins can be easily found in the code.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="padding"></param>
|
||||
/// <returns></returns>
|
||||
public static string PadInt(int value, int padding)
|
||||
{
|
||||
return value.ToString().PadLeft(padding, '0');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a random inclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
|
||||
/// </summary>
|
||||
/// <param name="minimum">Inclusive minimum value.</param>
|
||||
/// <param name="maximum">Inclusive maximum value.</param>
|
||||
/// <returns></returns>
|
||||
public static int RandomInclusiveRange(int minimum, int maximum)
|
||||
{
|
||||
return _random.Next(minimum, maximum + 1);
|
||||
}
|
||||
/// <summary>
|
||||
/// Provides a random exclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
|
||||
/// </summary>
|
||||
/// <param name="minimum">Inclusive minimum value.</param>
|
||||
/// <param name="maximum">Exclusive maximum value.</param>
|
||||
/// <returns></returns>
|
||||
public static int RandomExclusiveRange(int minimum, int maximum)
|
||||
{
|
||||
return _random.Next(minimum, maximum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clamped int within a specified range.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to clamp.</param>
|
||||
/// <param name="minimum">Minimum value.</param>
|
||||
/// <param name="maximum">Maximum value.</param>
|
||||
/// <returns></returns>
|
||||
public static int Clamp(int value, int minimum, int maximum)
|
||||
{
|
||||
if (value < minimum)
|
||||
value = minimum;
|
||||
else if (value > maximum)
|
||||
value = maximum;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determins if all values passed in are the same.
|
||||
/// </summary>
|
||||
/// <param name="values">Values to check.</param>
|
||||
/// <returns>True if all values are the same.</returns>
|
||||
public static bool ValuesMatch(params int[] values)
|
||||
{
|
||||
if (values.Length == 0)
|
||||
{
|
||||
Debug.Log("Ints -> ValuesMatch -> values array is empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Assign first value as element in first array.
|
||||
int firstValue = values[0];
|
||||
//Check all values.
|
||||
for (int i = 1; i < values.Length; i++)
|
||||
{
|
||||
//If any value doesn't match first value return false.
|
||||
if (firstValue != values[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
//If this far all values match.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c673118198f5c4b41986d52762828363
|
||||
timeCreated: 1527268448
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,45 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Layers
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a layer mask to a layer number.
|
||||
/// </summary>
|
||||
/// <param name="mask"></param>
|
||||
/// <returns></returns>
|
||||
public static int LayerMaskToLayerNumber(LayerMask mask)
|
||||
{
|
||||
return LayerValueToLayerNumber(mask.value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts a layer value int to a layer int.
|
||||
/// </summary>
|
||||
/// <param name="bitmask"></param>
|
||||
/// <returns></returns>
|
||||
public static int LayerValueToLayerNumber(int bitmask)
|
||||
{
|
||||
int result = bitmask > 0 ? 0 : 31;
|
||||
while (bitmask > 1)
|
||||
{
|
||||
bitmask = bitmask >> 1;
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a LayerMask contains a specified layer.
|
||||
/// </summary>
|
||||
/// <param name="layerMask">LayerMask to check for layer in.</param>
|
||||
/// <param name="layer">Layer to check within LayerMask.</param>
|
||||
/// <returns></returns>
|
||||
public static bool ContainsLayer(LayerMask layerMask, int layer)
|
||||
{
|
||||
return (layerMask == (layerMask | (1 << layer)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c18e15e44d21a94d8919f4b6b125a1f
|
||||
timeCreated: 1522349045
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class LayoutGroups
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns how many entries can fit into a GridLayoutGroup
|
||||
/// </summary>
|
||||
public static int EntriesPerWidth(this GridLayoutGroup lg)
|
||||
{
|
||||
RectTransform rectTransform = lg.GetComponent<RectTransform>();
|
||||
return Mathf.CeilToInt(rectTransform.rect.width / lg.cellSize.x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e330113395c59ca4dba5de001e010f08
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Materials
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the color or tint color property for a material.
|
||||
/// </summary>
|
||||
/// <param name="material"></param>
|
||||
/// <returns></returns>
|
||||
public static Color GetColor(this Material material)
|
||||
{
|
||||
if (material.HasProperty("_Color"))
|
||||
return material.color;
|
||||
else if (material.HasProperty("_TintColor"))
|
||||
return material.GetColor("_TintColor");
|
||||
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color or tint color property for a material.
|
||||
/// </summary>
|
||||
/// <param name="material"></param>
|
||||
public static void SetColor(this Material material, Color color)
|
||||
{
|
||||
if (material.HasProperty("_Color"))
|
||||
material.color = color;
|
||||
else if (material.HasProperty("_TintColor"))
|
||||
material.SetColor("_TintColor", color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27a618c551d5fdb4ca70bf07e1905580
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Maths
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clamped SBytte.
|
||||
/// </summary>
|
||||
public static sbyte ClampSByte(long value, sbyte min, sbyte max)
|
||||
{
|
||||
if (value < min)
|
||||
return min;
|
||||
else if (value > max)
|
||||
return max;
|
||||
else
|
||||
return (sbyte)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clamped double.
|
||||
/// </summary>
|
||||
public static double ClampDouble(double value, double min, double max)
|
||||
{
|
||||
if (value < min)
|
||||
return min;
|
||||
else if (value > max)
|
||||
return max;
|
||||
else
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18a583dc22a9a0f4cabec0c4a0219c6e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,548 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Implement to use type with Caches.
|
||||
/// </summary>
|
||||
public interface IResettable
|
||||
{
|
||||
/// <summary>
|
||||
/// Resets values when being placed in a cache.
|
||||
/// </summary>
|
||||
void ResetState();
|
||||
/// <summary>
|
||||
/// Initializes values after being retrieved from a cache.
|
||||
/// </summary>
|
||||
void InitializeState();
|
||||
}
|
||||
|
||||
#region Resettable caches.
|
||||
/// <summary>
|
||||
/// Caches collections of multiple generics.
|
||||
/// </summary>
|
||||
public static class ResettableCollectionCaches<T1, T2> where T1 : IResettable where T2 : IResettable
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<T1, T2> RetrieveDictionary() => CollectionCaches<T1, T2>.RetrieveDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Dictionary<T1, T2> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
public static void Store(Dictionary<T1, T2> value)
|
||||
{
|
||||
foreach (KeyValuePair<T1, T2> kvp in value)
|
||||
{
|
||||
kvp.Key.ResetState();
|
||||
ObjectCaches<T1>.Store(kvp.Key);
|
||||
kvp.Value.ResetState();
|
||||
ObjectCaches<T2>.Store(kvp.Value);
|
||||
}
|
||||
value.Clear();
|
||||
CollectionCaches<T1, T2>.Store(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches collections of multiple generics.
|
||||
/// </summary>
|
||||
public static class ResettableT1CollectionCaches<T1, T2> where T1 : IResettable
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<T1, T2> RetrieveDictionary() => CollectionCaches<T1, T2>.RetrieveDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Dictionary<T1, T2> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
public static void Store(Dictionary<T1, T2> value)
|
||||
{
|
||||
foreach (T1 item in value.Keys)
|
||||
{
|
||||
item.ResetState();
|
||||
ObjectCaches<T1>.Store(item);
|
||||
}
|
||||
value.Clear();
|
||||
CollectionCaches<T1, T2>.Store(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches collections of multiple generics.
|
||||
/// </summary>
|
||||
public static class ResettableT2CollectionCaches<T1, T2> where T2 : IResettable
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<T1, T2> RetrieveDictionary() => CollectionCaches<T1, T2>.RetrieveDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Dictionary<T1, T2> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
public static void Store(Dictionary<T1, T2> value)
|
||||
{
|
||||
foreach (T2 item in value.Values)
|
||||
{
|
||||
item.ResetState();
|
||||
ObjectCaches<T2>.Store(item);
|
||||
}
|
||||
value.Clear();
|
||||
CollectionCaches<T1, T2>.Store(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Caches collections of a single generic.
|
||||
/// </summary>
|
||||
public static class ResettableCollectionCaches<T> where T : IResettable
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static T[] RetrieveArray() => CollectionCaches<T>.RetrieveArray();
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<T> RetrieveList() => CollectionCaches<T>.RetrieveList();
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static HashSet<T> RetrieveHashSet() => CollectionCaches<T>.RetrieveHashSet();
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
/// <param name="count">Number of entries in the array from the beginning.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref T[] value, int count)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value, count);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
/// <param name="count">Number of entries in the array from the beginning.</param>
|
||||
public static void Store(T[] value, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
value[i].ResetState();
|
||||
ObjectCaches<T>.Store(value[i]);
|
||||
}
|
||||
CollectionCaches<T>.Store(value, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref List<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
public static void Store(List<T> value)
|
||||
{
|
||||
for (int i = 0; i < value.Count; i++)
|
||||
{
|
||||
value[i].ResetState();
|
||||
ObjectCaches<T>.Store(value[i]);
|
||||
}
|
||||
value.Clear();
|
||||
CollectionCaches<T>.Store(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref HashSet<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
public static void Store(HashSet<T> value)
|
||||
{
|
||||
foreach (T item in value)
|
||||
{
|
||||
item.ResetState();
|
||||
ObjectCaches<T>.Store(item);
|
||||
}
|
||||
value.Clear();
|
||||
CollectionCaches<T>.Store(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches objects of a single generic.
|
||||
/// </summary>
|
||||
public static class ResettableObjectCaches<T> where T : IResettable
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves an instance of T.
|
||||
/// </summary>
|
||||
public static T Retrieve()
|
||||
{
|
||||
T result = ObjectCaches<T>.Retrieve();
|
||||
result.InitializeState();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores an instance of T and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref T value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores an instance of T.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
public static void Store(T value)
|
||||
{
|
||||
value.ResetState();
|
||||
ObjectCaches<T>.Store(value);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region NonResettable caches.
|
||||
/// <summary>
|
||||
/// Caches collections of multiple generics.
|
||||
/// </summary>
|
||||
public static class CollectionCaches<T1, T2>
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache for dictionaries.
|
||||
/// </summary>
|
||||
private readonly static Stack<Dictionary<T1, T2>> _dictionaryCache = new Stack<Dictionary<T1, T2>>();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<T1, T2> RetrieveDictionary()
|
||||
{
|
||||
if (_dictionaryCache.Count == 0)
|
||||
return new Dictionary<T1, T2>();
|
||||
else
|
||||
return _dictionaryCache.Pop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref Dictionary<T1, T2> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
public static void Store(Dictionary<T1, T2> value)
|
||||
{
|
||||
value.Clear();
|
||||
_dictionaryCache.Push(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches collections of a single generic.
|
||||
/// </summary>
|
||||
public static class CollectionCaches<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache for arrays.
|
||||
/// </summary>
|
||||
private readonly static Stack<T[]> _arrayCache = new Stack<T[]>();
|
||||
/// <summary>
|
||||
/// Cache for lists.
|
||||
/// </summary>
|
||||
private readonly static Stack<List<T>> _listCache = new Stack<List<T>>();
|
||||
/// <summary>
|
||||
/// Cache for hashset.
|
||||
/// </summary>
|
||||
private readonly static Stack<HashSet<T>> _hashsetCache = new Stack<HashSet<T>>();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static T[] RetrieveArray()
|
||||
{
|
||||
if (_arrayCache.Count == 0)
|
||||
return new T[0];
|
||||
else
|
||||
return _arrayCache.Pop();
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<T> RetrieveList()
|
||||
{
|
||||
if (_listCache.Count == 0)
|
||||
return new List<T>();
|
||||
else
|
||||
return _listCache.Pop();
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a collection adding one entry.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<T> RetrieveList(T entry)
|
||||
{
|
||||
List<T> result;
|
||||
if (_listCache.Count == 0)
|
||||
result = new List<T>();
|
||||
else
|
||||
result = _listCache.Pop();
|
||||
|
||||
result.Add(entry);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a HashSet<T>.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static HashSet<T> RetrieveHashSet()
|
||||
{
|
||||
if (_hashsetCache.Count == 0)
|
||||
return new HashSet<T>();
|
||||
else
|
||||
return _hashsetCache.Pop();
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a collection adding one entry.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static HashSet<T> RetrieveHashSet(T entry)
|
||||
{
|
||||
HashSet<T> result;
|
||||
if (_hashsetCache.Count == 0)
|
||||
result = new HashSet<T>();
|
||||
else
|
||||
result = _hashsetCache.Pop();
|
||||
|
||||
result.Add(entry);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.\
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
/// <param name="count">Number of entries in the array from the beginning.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref T[] value, int count)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value, count);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
/// <param name="count">Number of entries in the array from the beginning.</param>
|
||||
public static void Store(T[] value, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
value[i] = default;
|
||||
|
||||
_arrayCache.Push(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref List<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
public static void Store(List<T> value)
|
||||
{
|
||||
value.Clear();
|
||||
_listCache.Push(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a collection and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref HashSet<T> value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Stores a collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
public static void Store(HashSet<T> value)
|
||||
{
|
||||
value.Clear();
|
||||
_hashsetCache.Push(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches objects of a single generic.
|
||||
/// </summary>
|
||||
public static class ObjectCaches<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Stack to use.
|
||||
/// </summary>
|
||||
private readonly static Stack<T> _stack = new Stack<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value from the stack or creates an instance when the stack is empty.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static T Retrieve()
|
||||
{
|
||||
if (_stack.Count == 0)
|
||||
return Activator.CreateInstance<T>();
|
||||
else
|
||||
return _stack.Pop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores an instance of T and sets the original reference to default.
|
||||
/// Method will not execute if value is null.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to store.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StoreAndDefault(ref T value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
Store(value);
|
||||
value = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a value to the stack.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public static void Store(T value)
|
||||
{
|
||||
_stack.Push(value);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3cb13274f7491a941b6e89a767905f56
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
using GameKit.Utilities.Types;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns if an object has been destroyed from memory.
|
||||
/// </summary>
|
||||
/// <param name="gameObject"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsDestroyed(this GameObject gameObject)
|
||||
{
|
||||
// UnityEngine overloads the == operator for the GameObject type
|
||||
// and returns null when the object has been destroyed, but
|
||||
// actually the object is still there but has not been cleaned up yet
|
||||
// if we test both we can determine if the object has been destroyed.
|
||||
return (gameObject == null && !ReferenceEquals(gameObject, null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all objects in the scene of type. This method is very expensive.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="requireSceneLoaded">True if the scene must be fully loaded before trying to seek objects.</param>
|
||||
/// <returns></returns>
|
||||
public static List<T> FindAllObjectsOfType<T>(bool activeSceneOnly = true, bool requireSceneLoaded = false, bool includeDDOL = true, bool includeInactive = true)
|
||||
{
|
||||
List<T> results = new List<T>();
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
Scene scene = SceneManager.GetSceneAt(i);
|
||||
//If to include only current scene.
|
||||
if (activeSceneOnly)
|
||||
{
|
||||
if (SceneManager.GetActiveScene() != scene)
|
||||
continue;
|
||||
}
|
||||
//If the scene must be fully loaded to seek objects within.
|
||||
if (!scene.isLoaded && requireSceneLoaded)
|
||||
continue;
|
||||
|
||||
GameObject[] allGameObjects = scene.GetRootGameObjects();
|
||||
for (int j = 0; j < allGameObjects.Length; j++)
|
||||
{
|
||||
results.AddRange(allGameObjects[j].GetComponentsInChildren<T>(includeInactive));
|
||||
}
|
||||
}
|
||||
|
||||
//If to also include DDOL.
|
||||
if (includeDDOL)
|
||||
{
|
||||
GameObject ddolGo = DDOL.GetDDOL().gameObject;
|
||||
results.AddRange(ddolGo.GetComponentsInChildren<T>(includeInactive));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4fa6d28a28dbf6b4295602abad3de328
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,109 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Particles
|
||||
{
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems.
|
||||
/// </summary>
|
||||
/// <param name="systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem[] systems, bool stopLoopingOnly)
|
||||
{
|
||||
return StopParticleSystem(systems, stopLoopingOnly, ParticleSystemStopBehavior.StopEmitting);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems while returning the time required to play out.
|
||||
/// </summary>
|
||||
/// <param name="systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem[] systems, ParticleSystemStopBehavior stopBehavior = ParticleSystemStopBehavior.StopEmitting)
|
||||
{
|
||||
return StopParticleSystem(systems, false, stopBehavior);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems while returning the time required to play out.
|
||||
/// </summary>
|
||||
/// <param name="systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem[] systems, bool stopLoopingOnly, ParticleSystemStopBehavior stopBehavior = ParticleSystemStopBehavior.StopEmitting)
|
||||
{
|
||||
if (systems == null)
|
||||
return 0f;
|
||||
|
||||
float playOutDuration = 0f;
|
||||
for (int i = 0; i < systems.Length; i++)
|
||||
playOutDuration = Mathf.Max(playOutDuration, StopParticleSystem(systems[i], stopLoopingOnly, stopBehavior));
|
||||
|
||||
return playOutDuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems.
|
||||
/// </summary>
|
||||
/// <param name="systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem system, bool stopLoopingOnly, bool stopChildren = false)
|
||||
{
|
||||
return StopParticleSystem(system, stopLoopingOnly, ParticleSystemStopBehavior.StopEmitting, stopChildren);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle systems while returning the time required to play out.
|
||||
/// </summary>
|
||||
/// <param name="systems"></param>
|
||||
public static float StopParticleSystem(ParticleSystem system, ParticleSystemStopBehavior stopBehavior = ParticleSystemStopBehavior.StopEmitting, bool stopChildren = false)
|
||||
{
|
||||
return StopParticleSystem(system, false, stopBehavior, stopChildren);
|
||||
}
|
||||
/// <summary>
|
||||
/// Issues stop on the specified particle system while returning the time required to play out.
|
||||
/// </summary>
|
||||
public static float StopParticleSystem(ParticleSystem system, bool stopLoopingOnly, ParticleSystemStopBehavior stopBehavior = ParticleSystemStopBehavior.StopEmitting, bool stopChildren = false)
|
||||
{
|
||||
if (system == null)
|
||||
return 0f;
|
||||
if (stopChildren)
|
||||
{
|
||||
ParticleSystem[] all = system.GetComponentsInChildren<ParticleSystem>();
|
||||
StopParticleSystem(all, stopLoopingOnly, stopBehavior);
|
||||
}
|
||||
|
||||
float playOutDuration = 0f;
|
||||
float timeLeft = system.main.duration - system.time;
|
||||
playOutDuration = Mathf.Max(playOutDuration, timeLeft);
|
||||
|
||||
if (stopLoopingOnly)
|
||||
{
|
||||
if (system.main.loop)
|
||||
system.Stop(false, stopBehavior);
|
||||
}
|
||||
else
|
||||
{
|
||||
system.Stop(false, stopBehavior);
|
||||
}
|
||||
|
||||
return playOutDuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the longest time required for all systems to stop.
|
||||
/// </summary>
|
||||
/// <param name="systems"></param>
|
||||
/// <returns></returns>
|
||||
public static float ReturnLongestCycle(ParticleSystem[] systems)
|
||||
{
|
||||
float longestPlayTime = 0f;
|
||||
for (int i = 0; i < systems.Length; i++)
|
||||
{
|
||||
float timeLeft = systems[i].main.duration - systems[i].time;
|
||||
longestPlayTime = Mathf.Max(longestPlayTime, timeLeft);
|
||||
}
|
||||
|
||||
return longestPlayTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f3d973dcfa06554998575e8eef0938a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Quaternions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Returns how fast an object must rotate over duration to reach goal.
|
||||
/// </summary>
|
||||
/// <param name="goal">Quaternion to measure distance against.</param>
|
||||
/// <param name="duration">How long it should take to move to goal.</param>
|
||||
/// <param name="interval">A multiplier applied towards interval. Typically this is used for ticks passed.</param>
|
||||
/// <returns></returns>
|
||||
public static float GetRate(this Quaternion a, Quaternion goal, float duration, out float angle, uint interval = 1, float tolerance = 0f)
|
||||
{
|
||||
angle = a.Angle(goal, true);
|
||||
return angle / (duration * interval);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if two quaternions match.
|
||||
/// </summary>
|
||||
/// <param name="precise">True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return a match even when not true due to error tolerance.</param>
|
||||
/// <returns></returns>
|
||||
public static bool Matches(this Quaternion a, Quaternion b, bool precise = false)
|
||||
{
|
||||
if (precise)
|
||||
return (a.w == b.w && a.x == b.x && a.y == b.y && a.z == b.z);
|
||||
else
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the angle between two quaterions.
|
||||
/// </summary>
|
||||
/// <param name="precise">True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return 0f due to error tolerance, even while there is a difference.</param>
|
||||
/// <returns></returns>
|
||||
public static float Angle(this Quaternion a, Quaternion b, bool precise = false)
|
||||
{
|
||||
if (precise)
|
||||
{
|
||||
//This is run Unitys implementation without the error tolerance.
|
||||
float dot = (a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w);
|
||||
return (Mathf.Acos(Mathf.Min(Mathf.Abs(dot), 1f)) * 2f * 57.29578f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Quaternion.Angle(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02a9084f4f788cd4293cdff56a49b5dd
|
||||
timeCreated: 1522043602
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
|
||||
public static class Strings
|
||||
{
|
||||
/// <summary>
|
||||
/// Attachs or detaches an suffix to a string.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="suffix"></param>
|
||||
/// <param name="addExtension"></param>
|
||||
public static string ReturnModifySuffix(string text, string suffix, bool addExtension)
|
||||
{
|
||||
/* Since saving to a json, add the .json extension if not present.
|
||||
* Length must be greater than 6 to contain a character and .json. */
|
||||
if (text.Length > (suffix.Length + 1))
|
||||
{
|
||||
//If to add the extension.
|
||||
if (addExtension)
|
||||
{
|
||||
//If doesn't contain the extension then add it on.
|
||||
if (!text.Substring(text.Length - suffix.Length).Contains(suffix, StringComparison.CurrentCultureIgnoreCase))
|
||||
return (text + suffix);
|
||||
//Already contains extension.
|
||||
else
|
||||
return text;
|
||||
}
|
||||
//Remove extension.
|
||||
else
|
||||
{
|
||||
//If contains extension.
|
||||
if (text.Substring(text.Length - suffix.Length).Contains(suffix, StringComparison.CurrentCultureIgnoreCase))
|
||||
return text.Substring(0, text.Length - (suffix.Length));
|
||||
//Doesn't contain extension.
|
||||
return text;
|
||||
}
|
||||
}
|
||||
//Text isn't long enough to manipulate.
|
||||
else
|
||||
{
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a string contains another string using StringComparison.
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="contains"></param>
|
||||
/// <param name="comp"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Contains(this string s, string contains, StringComparison comp)
|
||||
{
|
||||
int index = s.IndexOf(contains, comp);
|
||||
return (index >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b396f2be4de550a4e92b552650311600
|
||||
timeCreated: 1525378031
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,177 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities
|
||||
{
|
||||
|
||||
public static class Transforms
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a position for the rectTransform ensuring it's fully on the screen.
|
||||
/// </summary>
|
||||
/// <param name="desiredPosition">Preferred position for the rectTransform.</param>
|
||||
/// <param name="padding">How much padding the transform must be from the screen edges.</param>
|
||||
public static Vector3 GetOnScreenPosition(this RectTransform rectTransform, Vector3 desiredPosition, Vector2 padding)
|
||||
{
|
||||
Vector2 scale = new Vector2(rectTransform.localScale.x, rectTransform.localScale.y);
|
||||
//Value of which the tooltip would exceed screen bounds.
|
||||
//If there would be overshoot then adjust to be just on the edge of the overshooting side.
|
||||
float overshoot;
|
||||
|
||||
float halfWidthRequired = ((rectTransform.sizeDelta.x * scale.x) / 2f) + padding.x;
|
||||
overshoot = (Screen.width - (desiredPosition.x + halfWidthRequired));
|
||||
//If overshooting on the right.
|
||||
if (overshoot < 0f)
|
||||
desiredPosition.x += overshoot;
|
||||
overshoot = (desiredPosition.x - halfWidthRequired);
|
||||
//If overshooting on the left.
|
||||
if (overshoot < 0f)
|
||||
desiredPosition.x = halfWidthRequired;
|
||||
|
||||
float halfHeightRequired = ((rectTransform.sizeDelta.y * scale.y) / 2f) + padding.y;
|
||||
overshoot = (Screen.height - (desiredPosition.y + halfHeightRequired));
|
||||
//If overshooting on the right.
|
||||
if (overshoot < 0f)
|
||||
desiredPosition.y += overshoot;
|
||||
overshoot = (desiredPosition.y - halfHeightRequired);
|
||||
//If overshooting on the left.
|
||||
if (overshoot < 0f)
|
||||
desiredPosition.y = halfHeightRequired;
|
||||
|
||||
return desiredPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a parent for src while maintaining position, rotation, and scale of src.
|
||||
/// </summary>
|
||||
/// <param name="parent">Transform to become a child of.</param>
|
||||
public static void SetParentAndKeepTransform(this Transform src, Transform parent)
|
||||
{
|
||||
Vector3 pos = src.position;
|
||||
Quaternion rot = src.rotation;
|
||||
Vector3 scale = src.localScale;
|
||||
|
||||
src.SetParent(parent);
|
||||
src.position = pos;
|
||||
src.rotation = rot;
|
||||
src.localScale = scale;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys all children under the specified transform.
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
public static void DestroyChildren(this Transform t, bool destroyImmediately = false)
|
||||
{
|
||||
foreach (Transform child in t)
|
||||
{
|
||||
if (destroyImmediately)
|
||||
MonoBehaviour.DestroyImmediate(child.gameObject);
|
||||
else
|
||||
MonoBehaviour.Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys all children of a type under the specified transform.
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
public static void DestroyChildren<T>(this Transform t, bool destroyImmediately = false) where T : MonoBehaviour
|
||||
{
|
||||
T[] children = t.GetComponentsInChildren<T>();
|
||||
foreach (T child in children)
|
||||
{
|
||||
if (destroyImmediately)
|
||||
MonoBehaviour.DestroyImmediate(child.gameObject);
|
||||
else
|
||||
MonoBehaviour.Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets components in children and optionally parent.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="results"></param>
|
||||
/// <param name="parent"></param>
|
||||
/// <param name="includeParent"></param>
|
||||
/// <param name="includeInactive"></param>
|
||||
public static void GetComponentsInChildren<T>(this Transform parent, List<T> results, bool includeParent = true, bool includeInactive = false) where T : Component
|
||||
{
|
||||
if (!includeParent)
|
||||
{
|
||||
List<T> current = GameKit.Utilities.CollectionCaches<T>.RetrieveList();
|
||||
for (int i = 0; i < parent.childCount; i++)
|
||||
{
|
||||
parent.GetChild(i).GetComponentsInChildren(includeInactive, current);
|
||||
results.AddRange(current);
|
||||
}
|
||||
GameKit.Utilities.CollectionCaches<T>.Store(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.GetComponentsInChildren(includeInactive, results);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the position of this transform.
|
||||
/// </summary>
|
||||
public static Vector3 GetPosition(this Transform t, bool localSpace)
|
||||
{
|
||||
return (localSpace) ? t.localPosition : t.position;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the rotation of this transform.
|
||||
/// </summary>
|
||||
public static Quaternion GetRotation(this Transform t, bool localSpace)
|
||||
{
|
||||
return (localSpace) ? t.localRotation : t.rotation;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the scale of this transform.
|
||||
/// </summary>
|
||||
public static Vector3 GetScale(this Transform t)
|
||||
{
|
||||
return t.localScale;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position of this transform.
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="localSpace"></param>
|
||||
public static void SetPosition(this Transform t, bool localSpace, Vector3 pos)
|
||||
{
|
||||
if (localSpace)
|
||||
t.localPosition = pos;
|
||||
else
|
||||
t.position = pos;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the position of this transform.
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="localSpace"></param>
|
||||
public static void SetRotation(this Transform t, bool localSpace, Quaternion rot)
|
||||
{
|
||||
if (localSpace)
|
||||
t.localRotation = rot;
|
||||
else
|
||||
t.rotation = rot;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the position of this transform.
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="localSpace"></param>
|
||||
public static void SetScale(this Transform t, Vector3 scale)
|
||||
{
|
||||
t.localScale = scale;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba23540de73f58b458e7d7a200f3bb30
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a29cd7621a70a044bb205cc8cfd96b3c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,236 @@
|
||||
using GameKit.Dependencies.Inspectors;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.Types
|
||||
{
|
||||
|
||||
public class CanvasGroupFader : MonoBehaviour
|
||||
{
|
||||
#region Types.
|
||||
/// <summary>
|
||||
/// Current fade state or goal for this class.
|
||||
/// </summary>
|
||||
public enum FadeGoalType
|
||||
{
|
||||
Unset = 0,
|
||||
Hidden = 1,
|
||||
Visible = 2,
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Current goal for the fader.
|
||||
/// </summary>
|
||||
public FadeGoalType FadeGoal { get; private set; } = FadeGoalType.Unset;
|
||||
/// <summary>
|
||||
/// True if hidden or in the process of hiding.
|
||||
/// </summary>
|
||||
public bool IsHiding => (FadeGoal == FadeGoalType.Hidden);
|
||||
/// <summary>
|
||||
/// True if visible. Will be true long as the CanvasGroup has alpha. Also see IsHiding.
|
||||
/// </summary>
|
||||
public bool IsVisible => (CanvasGroup.alpha > 0f);
|
||||
#endregion
|
||||
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// CanvasGroup to fade in and out.
|
||||
/// </summary>
|
||||
[Tooltip("CanvasGroup to fade in and out.")]
|
||||
[SerializeField, Group("Components")]
|
||||
protected CanvasGroup CanvasGroup;
|
||||
/// <summary>
|
||||
/// True to update the CanvasGroup blocking settings when showing and hiding.
|
||||
/// </summary>
|
||||
[Tooltip("True to update the CanvasGroup blocking settings when showing and hiding.")]
|
||||
[SerializeField, Group("Effects")]
|
||||
protected bool UpdateCanvasBlocking = true;
|
||||
/// <summary>
|
||||
/// How long it should take to fade in the CanvasGroup.
|
||||
/// </summary>
|
||||
[SerializeField, Group("Effects")]
|
||||
protected float FadeInDuration = 0.1f;
|
||||
/// <summary>
|
||||
/// How long it should take to fade out the CanvasGroup.
|
||||
/// </summary>
|
||||
[SerializeField, Group("Effects")]
|
||||
protected float FadeOutDuration = 0.3f;
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// True if a fade cycle has completed at least once.
|
||||
/// </summary>
|
||||
private bool _completedOnce;
|
||||
#endregion
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
FadeGoal = (CanvasGroup.alpha > 0f) ? FadeGoalType.Visible : FadeGoalType.Hidden;
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
if (FadeGoal == FadeGoalType.Visible)
|
||||
ShowImmediately();
|
||||
else
|
||||
HideImmediately();
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
Fade();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows CanvasGroup immediately.
|
||||
/// </summary>
|
||||
public virtual void ShowImmediately()
|
||||
{
|
||||
SetFadeGoal(true);
|
||||
CompleteFade(true);
|
||||
OnShow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hides CanvasGroup immediately.
|
||||
/// </summary>
|
||||
public virtual void HideImmediately()
|
||||
{
|
||||
SetFadeGoal(false);
|
||||
CompleteFade(false);
|
||||
OnHide();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows CanvasGroup with a fade.
|
||||
/// </summary>
|
||||
public virtual void Show()
|
||||
{
|
||||
if (FadeInDuration <= 0f)
|
||||
{
|
||||
ShowImmediately();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFadeGoal(true);
|
||||
OnShow();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after Show or ShowImmediate.
|
||||
/// </summary>
|
||||
protected virtual void OnShow() { }
|
||||
|
||||
/// <summary>
|
||||
/// Hides CanvasGroup with a fade.
|
||||
/// </summary>
|
||||
public virtual void Hide()
|
||||
{
|
||||
if (FadeOutDuration <= 0f)
|
||||
{
|
||||
HideImmediately();
|
||||
}
|
||||
else
|
||||
{
|
||||
//Immediately make unclickable so players cannot hit UI objects as it's fading out.
|
||||
SetCanvasGroupBlockingType(CanvasGroupBlockingType.Block);
|
||||
SetFadeGoal(false);
|
||||
OnHide();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after Hide or HideImmediate.
|
||||
/// </summary>
|
||||
protected virtual void OnHide() { }
|
||||
|
||||
/// <summary>
|
||||
/// Sets showing and begins fading if required.
|
||||
/// </summary>
|
||||
/// <param name="fadeIn"></param>
|
||||
private void SetFadeGoal(bool fadeIn)
|
||||
{
|
||||
FadeGoal = (fadeIn) ? FadeGoalType.Visible : FadeGoalType.Hidden;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fades in or out over time.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private void Fade()
|
||||
{
|
||||
//Should not be possible.
|
||||
if (FadeGoal == FadeGoalType.Unset)
|
||||
{
|
||||
Debug.LogError($"{gameObject.name} has an unset FadeGoal. This should not be possible.");
|
||||
return;
|
||||
}
|
||||
|
||||
bool fadingIn = (FadeGoal == FadeGoalType.Visible);
|
||||
float duration;
|
||||
float targetAlpha;
|
||||
if (fadingIn)
|
||||
{
|
||||
targetAlpha = 1f;
|
||||
duration = FadeInDuration;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetAlpha = 0f;
|
||||
duration = FadeOutDuration;
|
||||
}
|
||||
|
||||
/* Already at goal and had completed an iteration at least once.
|
||||
* This is checked because even if at alpha we want to
|
||||
* complete the cycle if not done once so that all
|
||||
* local states and canvasgroup settings are proper. */
|
||||
if (_completedOnce && CanvasGroup.alpha == targetAlpha)
|
||||
return;
|
||||
|
||||
float rate = (1f / duration);
|
||||
CanvasGroup.alpha = Mathf.MoveTowards(CanvasGroup.alpha, targetAlpha, rate * Time.deltaTime);
|
||||
|
||||
//If complete.
|
||||
if (CanvasGroup.alpha == targetAlpha)
|
||||
CompleteFade(fadingIn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the fade completes.
|
||||
/// </summary>
|
||||
protected virtual void CompleteFade(bool fadingIn)
|
||||
{
|
||||
CanvasGroupBlockingType blockingType;
|
||||
float alpha;
|
||||
if (fadingIn)
|
||||
{
|
||||
blockingType = CanvasGroupBlockingType.Block;
|
||||
alpha = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockingType = CanvasGroupBlockingType.DoNotBlock;
|
||||
alpha = 0f;
|
||||
}
|
||||
|
||||
SetCanvasGroupBlockingType(blockingType);
|
||||
CanvasGroup.alpha = alpha;
|
||||
_completedOnce = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the CanvasGroups interactable and bloacking state.
|
||||
/// </summary>
|
||||
protected virtual void SetCanvasGroupBlockingType(CanvasGroupBlockingType blockingType)
|
||||
{
|
||||
if (UpdateCanvasBlocking)
|
||||
CanvasGroup.SetBlockingType(blockingType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6aa7bd78c33474948b74e3c7a1d97454
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f04cb37e5f34ee749b8be696cb9c6ba3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
namespace GameKit.Utilities.Types.CanvasContainers
|
||||
{
|
||||
public class ButtonData : IResettable
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Text to place on the button.
|
||||
/// </summary>
|
||||
public string Text { get; protected set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// When not null this will be called when action is taken.
|
||||
/// </summary>
|
||||
/// <param name="key">Optional key to associate with callback.</param>
|
||||
public delegate void PressedDelegate(string key);
|
||||
/// <summary>
|
||||
/// Optional key to include within the callback.
|
||||
/// </summary>
|
||||
public string Key { get; protected set; } = string.Empty;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke when pressed.
|
||||
/// </summary>
|
||||
private PressedDelegate _delegate = null;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this for use.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to display on the button.</param>
|
||||
/// <param name="callback">Callback when OnPressed is called.</param>
|
||||
/// <param name="key">Optional key to include within the callback.</param>
|
||||
public void Initialize(string text, PressedDelegate callback, string key = "")
|
||||
{
|
||||
Text = text;
|
||||
Key = key;
|
||||
_delegate = callback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called whewn the button for this data is pressed.
|
||||
/// </summary>
|
||||
public virtual void OnPressed()
|
||||
{
|
||||
_delegate?.Invoke(Key);
|
||||
}
|
||||
|
||||
public virtual void ResetState()
|
||||
{
|
||||
Text = string.Empty;
|
||||
_delegate = null;
|
||||
Key = string.Empty;
|
||||
}
|
||||
|
||||
public void InitializeState() { }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1baacd2a6a8a0e94b897c6b7176c7000
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,232 @@
|
||||
using GameKit.Dependencies.Inspectors;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace GameKit.Utilities.Types.CanvasContainers
|
||||
{
|
||||
|
||||
public class FloatingContainer : CanvasGroupFader
|
||||
{
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// RectTransform to move.
|
||||
/// </summary>
|
||||
[Tooltip("RectTransform to move.")]
|
||||
[SerializeField, Group("Components")]
|
||||
protected RectTransform RectTransform;
|
||||
/// <summary>
|
||||
/// True to use edge avoidance.
|
||||
/// </summary>
|
||||
[Tooltip("True to use edge avoidance.")]
|
||||
[SerializeField, Group("Sizing")]
|
||||
protected bool UseEdgeAvoidance = true;
|
||||
/// <summary>
|
||||
/// How much to avoid screen edges when being moved.
|
||||
/// </summary>
|
||||
[Tooltip("How much to avoid screen edges when being moved.")]
|
||||
[SerializeField, Group("Sizing"), ShowIf(nameof(UseEdgeAvoidance), true)]
|
||||
protected Vector2 EdgeAvoidance;
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// Desired position.
|
||||
/// </summary>
|
||||
private Vector3 _positionGoal;
|
||||
/// <summary>
|
||||
/// Desired rotation.
|
||||
/// </summary>
|
||||
private Quaternion _rotationGoal;
|
||||
/// <summary>
|
||||
/// Desired scale.
|
||||
/// </summary>
|
||||
private Vector3 _scaleGoal = Vector3.one;
|
||||
/// <summary>
|
||||
/// How much edge avoidance to use.
|
||||
/// </summary>
|
||||
private Vector2? _edgeAvoidance;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Attachs a gameObject as a child of this object and sets transform valus to default.
|
||||
/// </summary>
|
||||
/// <param name="go">GameObject to attach.</param>
|
||||
public void AttachGameObject(GameObject go)
|
||||
{
|
||||
if (go == null)
|
||||
return;
|
||||
|
||||
Transform goT = go.transform;
|
||||
goT.SetParent(transform);
|
||||
goT.localPosition = Vector3.zero;
|
||||
goT.localRotation = Quaternion.identity;
|
||||
goT.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the container.
|
||||
/// </summary>
|
||||
/// <param name="position">Position to use.</param>
|
||||
/// <param name="rotation">Rotation to use.</param>
|
||||
/// <param name="scale">Scale to use.</param>
|
||||
/// <param name="pivot">Pivot for rectTransform.</param>
|
||||
/// <param name="edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
|
||||
public virtual void Show(Vector3 position, Quaternion rotation, Vector3 scale, Vector2 pivot, Vector2? edgeAvoidanceOverride = null)
|
||||
{
|
||||
UpdateEdgeAvoidance(edgeAvoidanceOverride, false);
|
||||
UpdatePivot(pivot, false);
|
||||
UpdatePositionRotationAndScale(position, rotation, scale);
|
||||
base.Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the container.
|
||||
/// </summary>
|
||||
/// <param name="position">Position to use.</param>
|
||||
/// <param name="edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public virtual void Show(Vector3 position, Vector2? edgeAvoidanceOverride = null)
|
||||
{
|
||||
Show(position, Quaternion.identity, Vector3.one, RectTransform.pivot);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the container.
|
||||
/// </summary>
|
||||
/// <param name="position">Position to use.</param>
|
||||
/// <param name="rotation">Rotation to use.</param>
|
||||
/// <param name="edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public virtual void Show(Vector3 position, Quaternion rotation, Vector2? edgeAvoidanceOverride = null)
|
||||
{
|
||||
Show(position, rotation, Vector3.one, RectTransform.pivot);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the container.
|
||||
/// </summary>
|
||||
/// <param name="startingPoint">Transform to use for position, rotation, and scale.</param>
|
||||
/// <param name="edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public virtual void Show(Transform startingPoint, Vector2? edgeAvoidanceOverride = null)
|
||||
{
|
||||
if (startingPoint == null)
|
||||
{
|
||||
Debug.LogError($"A null Transform cannot be used as the starting point.");
|
||||
return;
|
||||
}
|
||||
|
||||
Show(startingPoint.position, startingPoint.rotation, startingPoint.localScale, RectTransform.pivot);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the rectTransform pivot.
|
||||
/// </summary>
|
||||
/// <param name="pivot">New pivot.</param>
|
||||
/// <param name="move">True to move the RectTransform after updating.</param>
|
||||
public virtual void UpdatePivot(Vector2 pivot, bool move = true)
|
||||
{
|
||||
RectTransform.pivot = pivot;
|
||||
if (move)
|
||||
Move();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates to a new position.
|
||||
/// </summary>
|
||||
/// <param name="position">Next position.</param>
|
||||
/// <param name="move">True to move towards new position.</param>
|
||||
public virtual void UpdatePosition(Vector3 position, bool move = true)
|
||||
{
|
||||
_positionGoal = position;
|
||||
if (move)
|
||||
Move();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates to a new rotation.
|
||||
/// </summary>
|
||||
/// <param name="rotation">Next rotation.</param>
|
||||
public virtual void UpdateRotation(Quaternion rotation, bool move = true)
|
||||
{
|
||||
_rotationGoal = rotation;
|
||||
if (move)
|
||||
Move();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates to a new scale.
|
||||
/// </summary>
|
||||
/// <param name="scale">Next scale.</param>
|
||||
/// <param name="move">True to move the RectTransform after updating.</param>
|
||||
public virtual void UpdateScale(Vector3 scale, bool move = true)
|
||||
{
|
||||
_scaleGoal = scale;
|
||||
if (move)
|
||||
Move();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates to a new position and rotation.
|
||||
/// </summary>
|
||||
/// <param name="position">Next position.</param>
|
||||
/// <param name="rotation">Next rotation.</param>
|
||||
/// <param name="move">True to move the RectTransform after updating.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public virtual void UpdatePositionAndRotation(Vector3 position, Quaternion rotation, bool move = true)
|
||||
{
|
||||
UpdatePosition(position, false);
|
||||
UpdateRotation(rotation, false);
|
||||
if (move)
|
||||
Move();
|
||||
}
|
||||
/// <summary>
|
||||
/// Updates to a new position, rotation, and scale.
|
||||
/// </summary>
|
||||
/// <param name="position">Next position.</param>
|
||||
/// <param name="rotation">Next rotation.</param>
|
||||
/// <param name="scale">Next scale.</param>
|
||||
/// <param name="move">True to move the RectTransform after updating.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public virtual void UpdatePositionRotationAndScale(Vector3 position, Quaternion rotation, Vector3 scale, bool move = true)
|
||||
{
|
||||
UpdatePositionAndRotation(position, rotation, false);
|
||||
UpdateScale(scale, false);
|
||||
Move();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates how much edge avoidance to use. When null serialized values are used.
|
||||
/// </summary>
|
||||
/// <param name="edgeAvoidanceOverride">How far to keep the RectTransform from the edge. If null serialized avoidance will be used.</param>
|
||||
/// <param name="move">True to move the RectTransform after updating.</param>
|
||||
public virtual void UpdateEdgeAvoidance(Vector2? edgeAvoidanceOverride = null, bool move = true)
|
||||
{
|
||||
_edgeAvoidance = (edgeAvoidanceOverride.HasValue) ? edgeAvoidanceOverride.Value : EdgeAvoidance;
|
||||
if (move)
|
||||
Move();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves to configured goals.
|
||||
/// </summary>
|
||||
protected virtual void Move()
|
||||
{
|
||||
//Update scale first so edge avoidance takes it into consideration.
|
||||
RectTransform.localScale = _scaleGoal;
|
||||
|
||||
Vector2 position = _positionGoal;
|
||||
if (UseEdgeAvoidance)
|
||||
{
|
||||
Vector2 avoidance = (_edgeAvoidance.HasValue) ? _edgeAvoidance.Value : EdgeAvoidance;
|
||||
position = RectTransform.GetOnScreenPosition(_positionGoal, avoidance);
|
||||
}
|
||||
|
||||
RectTransform.SetPositionAndRotation(position, _rotationGoal);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1fcd998728ace94ea809c34ad0d09e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
using GameKit.Dependencies.Inspectors;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace GameKit.Utilities.Types.CanvasContainers
|
||||
{
|
||||
|
||||
public class FloatingImage : FloatingContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Renderer to apply sprite on.
|
||||
/// </summary>
|
||||
[Tooltip("Renderer to apply sprite on.")]
|
||||
[SerializeField, Group("Components")]
|
||||
protected Image Renderer;
|
||||
|
||||
/// <summary>
|
||||
/// Sets which sprite to use.
|
||||
/// </summary>
|
||||
/// <param name="sprite">Sprite to use.</param>
|
||||
/// <param name="sizeOverride">When has value the renderer will be set to this size. Otherwise, the size of the sprite will be used. This value assumes the sprite anchors are set to center.</param>
|
||||
public virtual void SetSprite(Sprite sprite, Vector3? sizeOverride)
|
||||
{
|
||||
Renderer.sprite = sprite;
|
||||
Vector3 size = (sizeOverride == null)
|
||||
? (sprite.bounds.size * sprite.pixelsPerUnit)
|
||||
: sizeOverride.Value;
|
||||
|
||||
Renderer.rectTransform.sizeDelta = size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2169e34ec7dd63a4e99b5cc89fd0e966
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,45 @@
|
||||
using GameKit.Utilities.Types;
|
||||
using GameKit.Utilities.Types.CanvasContainers;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace GameKit.Utilities.Types.OptionMenuButtons
|
||||
{
|
||||
|
||||
public class FloatingOptions : CanvasGroupFader
|
||||
{
|
||||
#region Protected.
|
||||
/// <summary>
|
||||
/// Current buttons.
|
||||
/// </summary>
|
||||
protected List<ButtonData> Buttons = new List<ButtonData>();
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Adds buttons.
|
||||
/// </summary>
|
||||
/// <param name="clearExisting">True to clear existing buttons first.</param>
|
||||
/// <param name="buttonDatas">Buttons to add.</param>
|
||||
protected virtual void AddButtons(bool clearExisting, IEnumerable<ButtonData> buttonDatas)
|
||||
{
|
||||
if (clearExisting)
|
||||
RemoveButtons();
|
||||
foreach (ButtonData item in buttonDatas)
|
||||
Buttons.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all buttons.
|
||||
/// </summary>
|
||||
protected virtual void RemoveButtons()
|
||||
{
|
||||
foreach (ButtonData item in Buttons)
|
||||
GameKit.Utilities.ResettableObjectCaches<ButtonData>.Store(item);
|
||||
Buttons.Clear();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbc5b08db621303449f60b59f56eac92
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.Types.CanvasContainers
|
||||
{
|
||||
public class ImageButtonData : ButtonData
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Image to display.
|
||||
/// </summary>
|
||||
public Sprite DisplayImage { get; protected set; } = null;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this for use.
|
||||
/// </summary>
|
||||
/// <param name="sprite">Image to use on the button.</param>
|
||||
/// <param name="text">Text to display on the button.</param>
|
||||
/// <param name="callback">Callback when OnPressed is called.</param>
|
||||
/// <param name="key">Optional key to include within the callback.</param>
|
||||
public void Initialize(Sprite sprite, string text, PressedDelegate callback, string key = "")
|
||||
{
|
||||
base.Initialize(text, callback, key);
|
||||
DisplayImage = sprite;
|
||||
}
|
||||
|
||||
public override void ResetState()
|
||||
{
|
||||
base.ResetState();
|
||||
DisplayImage = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d60e355b6d09be14487df1ed91e901b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
#if TEXTMESHPRO
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace GameKit.Utilities.Types.CanvasContainers
|
||||
{
|
||||
|
||||
public class OptionMenuImageButton : OptionMenuButton
|
||||
{
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// Image component to show image on.
|
||||
/// </summary>
|
||||
[Tooltip("Image component to show image on.")]
|
||||
[SerializeField]
|
||||
private Image _image;
|
||||
#endregion
|
||||
|
||||
public virtual void Initialize(ImageButtonData buttonData)
|
||||
{
|
||||
base.Initialize(buttonData);
|
||||
_image.sprite = buttonData.DisplayImage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2fee1d5cad375e84eaab6a4cd1d6e915
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
#if TEXTMESHPRO
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace GameKit.Utilities.Types.CanvasContainers
|
||||
{
|
||||
|
||||
public class OptionMenuButton : MonoBehaviour
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// ButtonData for this button.
|
||||
/// </summary>
|
||||
public ButtonData ButtonData { get; protected set; }
|
||||
#endregion
|
||||
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// Text component to show button text.
|
||||
/// </summary>
|
||||
[Tooltip("Text component to show button text.")]
|
||||
[SerializeField]
|
||||
private TextMeshProUGUI _text;
|
||||
#endregion
|
||||
|
||||
public virtual void Initialize(ButtonData buttonData)
|
||||
{
|
||||
ButtonData = buttonData;
|
||||
_text.text = buttonData.Text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22d4118a529704b49858d02b956dc48d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,111 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.Types
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gameplay canvases register to this manager.
|
||||
/// </summary>
|
||||
public class RectTransformResizer : MonoBehaviour
|
||||
{
|
||||
#region Types.
|
||||
public class ResizeData : IResettable
|
||||
{
|
||||
public byte Remaining;
|
||||
public ResizeDelegate Delegate;
|
||||
|
||||
public ResizeData()
|
||||
{
|
||||
Remaining = 2;
|
||||
}
|
||||
|
||||
public void InitializeState() { }
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
Remaining = 2;
|
||||
Delegate = null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Delegate for resizing RectTransforms.
|
||||
/// </summary>
|
||||
/// <param name="complete">True if the resize iterations are complete. Typically show your visuals when true.</param>
|
||||
public delegate void ResizeDelegate(bool complete);
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// Elements to resize.
|
||||
/// </summary>
|
||||
private List<ResizeData> _resizeDatas = new List<ResizeData>();
|
||||
/// <summary>
|
||||
/// Singleton instance of this class.
|
||||
/// </summary>
|
||||
private static RectTransformResizer _instance;
|
||||
#endregion
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
foreach (ResizeData item in _resizeDatas)
|
||||
ResettableObjectCaches<ResizeData>.Store(item);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
Resize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls pending resizeDatas.
|
||||
/// </summary>
|
||||
private void Resize()
|
||||
{
|
||||
for (int i = 0; i < _resizeDatas.Count; i++)
|
||||
{
|
||||
_resizeDatas[i].Remaining--;
|
||||
bool complete = (_resizeDatas[i].Remaining == 0);
|
||||
_resizeDatas[i].Delegate?.Invoke(complete);
|
||||
if (complete)
|
||||
{
|
||||
ResettableObjectCaches<ResizeData>.Store(_resizeDatas[i]);
|
||||
_resizeDatas.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to call a delegate twice, over two frames.
|
||||
/// This is an easy way to resize RectTransforms multiple times as they will often fail after the first resize due to Unity limitations.
|
||||
/// Note: this work-around may not be required for newer Unity versions.
|
||||
/// </summary>
|
||||
/// <param name="del">Delegate to invoke when resizing completes.</param>
|
||||
public static void Resize(ResizeDelegate del)
|
||||
{
|
||||
//Check to make a singleton instance.
|
||||
if (_instance == null)
|
||||
{
|
||||
GameObject go = new GameObject(typeof(RectTransformResizer).Name);
|
||||
_instance = go.AddComponent<RectTransformResizer>();
|
||||
DontDestroyOnLoad(go);
|
||||
}
|
||||
|
||||
_instance.Resize_Internal(del);
|
||||
}
|
||||
private void Resize_Internal(ResizeDelegate del)
|
||||
{
|
||||
ResizeData rd = ResettableObjectCaches<ResizeData>.Retrieve();
|
||||
rd.Delegate = del;
|
||||
_instance._resizeDatas.Add(rd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4b4655d59b39584faed638f43d4d287
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace GameKit.Utilities.Types.CanvasContainers
|
||||
{
|
||||
|
||||
public class ResizableContainer : FloatingContainer
|
||||
{
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// Minimum and maximum range for widwth and height of the RectTransform.
|
||||
/// </summary>
|
||||
[Tooltip("Minimum and maximum range for width and height of the RectTransform.")]
|
||||
//[Foldout("Sizing")]
|
||||
public FloatRange2D SizeLimits = new FloatRange2D()
|
||||
{
|
||||
X = new FloatRange(0f, 999999f),
|
||||
Y = new FloatRange(0f, 999999f)
|
||||
};
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Sets a size, and resizes if needed.
|
||||
/// Other transform values must be set separately using inherited methods.
|
||||
/// </summary>
|
||||
/// <param name="size">New size to use.</param>
|
||||
/// <param name="ignoreSizeLimits">True to ignore serialized Size limits.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetSizeAndShow(Vector2 size, bool ignoreSizeLimits = false)
|
||||
{
|
||||
ResizeAndShow(size, ignoreSizeLimits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resizes this canvas.
|
||||
/// </summary>
|
||||
protected virtual void ResizeAndShow(Vector2 desiredSize, bool ignoreSizeLimits)
|
||||
{
|
||||
float widthRequired = desiredSize.x;
|
||||
float heightRequired = desiredSize.y;
|
||||
//Clamp width and height.
|
||||
widthRequired = Mathf.Clamp(widthRequired, SizeLimits.X.Minimum, SizeLimits.X.Maximum);
|
||||
heightRequired = Mathf.Clamp(heightRequired, SizeLimits.Y.Minimum, SizeLimits.Y.Maximum);
|
||||
base.RectTransform.sizeDelta = new Vector2(widthRequired, heightRequired);
|
||||
base.Move();
|
||||
base.Show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5764e627642cf5643a3f4518d450840e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.Types
|
||||
{
|
||||
|
||||
|
||||
public class DDOL : MonoBehaviour
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Singleton instance of this class.
|
||||
/// </summary>
|
||||
[Obsolete("Use GetDDOL().")] //Remove on 2023/06/01.
|
||||
public static DDOL Instance => GetDDOL();
|
||||
/// <summary>
|
||||
/// Created instance of DDOL.
|
||||
/// </summary>
|
||||
private static DDOL _instance;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current DDOL or creates one if not yet created.
|
||||
/// </summary>
|
||||
public static DDOL GetDDOL()
|
||||
{
|
||||
//Not yet made.
|
||||
if (_instance == null)
|
||||
{
|
||||
GameObject obj = new GameObject();
|
||||
obj.name = "FirstGearGames DDOL";
|
||||
DDOL ddol = obj.AddComponent<DDOL>();
|
||||
DontDestroyOnLoad(ddol);
|
||||
_instance = ddol;
|
||||
return ddol;
|
||||
}
|
||||
//Already made.
|
||||
else
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e0b25628cfd4f241a22a7c0ee2b932f
|
||||
timeCreated: 1528404670
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4e1653f734aa924a947707391413c6c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,51 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.Types.Editing
|
||||
{
|
||||
/* Source https://forum.unity.com/threads/how-to-link-scenes-in-the-inspector.383140/ */
|
||||
|
||||
[CustomPropertyDrawer(typeof(SceneAttribute))]
|
||||
public class SceneDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (property.propertyType == SerializedPropertyType.String)
|
||||
{
|
||||
SceneAsset sceneObject = AssetDatabase.LoadAssetAtPath<SceneAsset>(property.stringValue);
|
||||
|
||||
if (sceneObject == null && !string.IsNullOrEmpty(property.stringValue))
|
||||
{
|
||||
// try to load it from the build settings for legacy compatibility
|
||||
sceneObject = GetBuildSettingsSceneObject(property.stringValue);
|
||||
}
|
||||
if (sceneObject == null && !string.IsNullOrEmpty(property.stringValue))
|
||||
{
|
||||
Debug.Log($"Could not find scene {property.stringValue} in {property.propertyPath}, assign the proper scenes in your NetworkManager");
|
||||
}
|
||||
SceneAsset scene = (SceneAsset)EditorGUI.ObjectField(position, label, sceneObject, typeof(SceneAsset), true);
|
||||
|
||||
property.stringValue = AssetDatabase.GetAssetPath(scene);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.LabelField(position, label.text, "Use [Scene] with strings.");
|
||||
}
|
||||
}
|
||||
|
||||
protected SceneAsset GetBuildSettingsSceneObject(string sceneName)
|
||||
{
|
||||
foreach (EditorBuildSettingsScene buildScene in EditorBuildSettings.scenes)
|
||||
{
|
||||
SceneAsset sceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(buildScene.path);
|
||||
if (sceneAsset != null && sceneAsset.name == sceneName)
|
||||
{
|
||||
return sceneAsset;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c144891e57ef5054d9b7e03b82c00cf2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.Types
|
||||
{
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public struct FloatRange
|
||||
{
|
||||
public FloatRange(float minimum, float maximum)
|
||||
{
|
||||
Minimum = minimum;
|
||||
Maximum = maximum;
|
||||
}
|
||||
/// <summary>
|
||||
/// Minimum range.
|
||||
/// </summary>
|
||||
public float Minimum;
|
||||
/// <summary>
|
||||
/// Maximum range.
|
||||
/// </summary>
|
||||
public float Maximum;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random value between Minimum and Maximum.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public float RandomInclusive()
|
||||
{
|
||||
return Floats.RandomInclusiveRange(Minimum, Maximum);
|
||||
}
|
||||
|
||||
public float Lerp(float percent)
|
||||
{
|
||||
return Mathf.Lerp(Minimum, Maximum, percent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35d4414338c0ab248a1b838402887ac0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.Types
|
||||
{
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
|
||||
public struct FloatRange2D
|
||||
{
|
||||
public FloatRange X;
|
||||
public FloatRange Y;
|
||||
|
||||
public FloatRange2D(FloatRange x, FloatRange y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
|
||||
public FloatRange2D(float xMin, float xMax, float yMin, float yMax)
|
||||
{
|
||||
X = new FloatRange(xMin, xMax);
|
||||
Y = new FloatRange(yMin, yMax);
|
||||
}
|
||||
|
||||
public Vector2 Clamp(Vector2 original)
|
||||
{
|
||||
return new Vector2(
|
||||
ClampX(original.x),
|
||||
ClampY(original.y)
|
||||
);
|
||||
}
|
||||
|
||||
public Vector3 Clamp(Vector3 original)
|
||||
{
|
||||
return new Vector3(
|
||||
ClampX(original.x),
|
||||
ClampY(original.y),
|
||||
original.z
|
||||
);
|
||||
}
|
||||
|
||||
public float ClampX(float original)
|
||||
{
|
||||
return Mathf.Clamp(original, X.Minimum, X.Maximum);
|
||||
}
|
||||
|
||||
public float ClampY(float original)
|
||||
{
|
||||
return Mathf.Clamp(original, Y.Minimum, Y.Maximum);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a2c6d65e69e9154b8f99096ed3096dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
namespace GameKit.Utilities.Types
|
||||
{
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public struct IntRange
|
||||
{
|
||||
public IntRange(int minimum, int maximum)
|
||||
{
|
||||
Minimum = minimum;
|
||||
Maximum = maximum;
|
||||
}
|
||||
/// <summary>
|
||||
/// Minimum range.
|
||||
/// </summary>
|
||||
public int Minimum;
|
||||
/// <summary>
|
||||
/// Maximum range.
|
||||
/// </summary>
|
||||
public int Maximum;
|
||||
|
||||
/// <summary>
|
||||
/// Returns an exclusive random value between Minimum and Maximum.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public float RandomExclusive()
|
||||
{
|
||||
return Ints.RandomExclusiveRange(Minimum, Maximum);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an inclusive random value between Minimum and Maximum.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public float RandomInclusive()
|
||||
{
|
||||
return Ints.RandomInclusiveRange(Minimum, Maximum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns value clamped within minimum and maximum.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public int Clamp(int value)
|
||||
{
|
||||
if (value < Minimum)
|
||||
return Minimum;
|
||||
if (value > Maximum)
|
||||
return Maximum;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16f03af589a154c47bcbcc3f82b710a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05bf45e6c53189b428920bb4f1f4244d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
2020/09/22
|
||||
+ Added demo scene.
|
||||
+ You can now Store with a delay, which will behave similar to Destroy(obj, delay).
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f20abb868e2b92a4d979359d81d97aa0
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9e1126c6a21b924ebe296adf0d3e282
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb1d9debba52ef04999d361f88e67f06
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ed8235e90a17434597bd75f8631dfe4
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4777e69010a7d0c4e92e16a1b690014a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,390 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 3
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 0}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 11
|
||||
m_GIWorkflowMode: 1
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 0
|
||||
m_EnableRealtimeLightmaps: 0
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 40
|
||||
m_AtlasSize: 1024
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 0}
|
||||
m_UseShadowmask: 1
|
||||
--- !u!196 &4
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 2
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &1154039407
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1154039409}
|
||||
- component: {fileID: 1154039408}
|
||||
m_Layer: 0
|
||||
m_Name: ObjectPool
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1154039408
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1154039407}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: ab8f6cec624bac24d8fcc6a7a27a07e8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_dataExpirationDelay: 60
|
||||
--- !u!4 &1154039409
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1154039407}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1433044100
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1433044102}
|
||||
- component: {fileID: 1433044101}
|
||||
m_Layer: 0
|
||||
m_Name: ProjectileSpawner
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1433044101
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1433044100}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 19304078402371645ac157640b97d523, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
Prefab: {fileID: 7907540912251384645, guid: 6ed8235e90a17434597bd75f8631dfe4, type: 3}
|
||||
UsePool: 1
|
||||
_instantiateDelay: 0.075
|
||||
--- !u!4 &1433044102
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1433044100}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: -5.81, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 1832075967}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1459728710
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1459728713}
|
||||
- component: {fileID: 1459728712}
|
||||
- component: {fileID: 1459728711}
|
||||
m_Layer: 0
|
||||
m_Name: Main Camera
|
||||
m_TagString: MainCamera
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!81 &1459728711
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1459728710}
|
||||
m_Enabled: 1
|
||||
--- !u!20 &1459728712
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1459728710}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 1
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 1
|
||||
orthographic size: 8
|
||||
m_Depth: -1
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &1459728713
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1459728710}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: -10}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1832075966
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1832075967}
|
||||
- component: {fileID: 1832075970}
|
||||
- component: {fileID: 1832075969}
|
||||
- component: {fileID: 1832075968}
|
||||
m_Layer: 0
|
||||
m_Name: Sphere
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1832075967
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1832075966}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1433044102}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!135 &1832075968
|
||||
SphereCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1832075966}
|
||||
m_Material: {fileID: 0}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_Radius: 0.5
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &1832075969
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1832075966}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &1832075970
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1832075966}
|
||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 986fe9a85bd2d904fa3d44ac2c7bf0da
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 898e607de9d654d40a5fcdd6a6aff11c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,87 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.ObjectPooling.Examples
|
||||
{
|
||||
|
||||
public class Projectile : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// If above 0f projectiles are stored with a delay rather than when off screen.
|
||||
/// </summary>
|
||||
[Tooltip("If above 0f projectiles are stored with a delay rather than when off screen.")]
|
||||
[Range(0f, 5f)]
|
||||
public float DestroyDelay = 0f;
|
||||
|
||||
public float MoveRate = 30f;
|
||||
|
||||
private ProjectileSpawner _spawner;
|
||||
private MeshRenderer[] _renderers;
|
||||
private Vector3 _moveDirection;
|
||||
/// <summary>
|
||||
/// True if existing play mode.
|
||||
/// </summary>
|
||||
private bool _exitingPlayMode = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.playModeStateChanged += EditorApplication_playModeStateChanged;
|
||||
#endif
|
||||
|
||||
|
||||
//Used as our pretend overhead.
|
||||
for (int i = 0; i < 30; i++)
|
||||
{
|
||||
_spawner = GameObject.FindObjectOfType<ProjectileSpawner>();
|
||||
_renderers = GetComponentsInChildren<MeshRenderer>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Received when editor play mode changes.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
private void EditorApplication_playModeStateChanged(PlayModeStateChange obj)
|
||||
{
|
||||
if (!EditorApplication.isPlayingOrWillChangePlaymode && EditorApplication.isPlaying)
|
||||
_exitingPlayMode = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
private void OnBecameInvisible()
|
||||
{
|
||||
//Don't try to pool if exiting play mode. Doesn't harm anything but creates annoying errors.
|
||||
if (_exitingPlayMode)
|
||||
return;
|
||||
|
||||
if (DestroyDelay <= 0f)
|
||||
{
|
||||
if (_spawner.UsePool)
|
||||
{
|
||||
ObjectPool.Store(gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_moveDirection = new Vector3(Random.Range(-1f, 1f), 1f, 0f).normalized;
|
||||
if (_spawner.UsePool && DestroyDelay > 0f)
|
||||
ObjectPool.Store(gameObject, DestroyDelay);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
transform.position += _moveDirection * MoveRate * Time.deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80e69d14230e52a45bba1fa6f40fd30c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.ObjectPooling.Examples
|
||||
{
|
||||
|
||||
public class ProjectileSpawner : MonoBehaviour
|
||||
{
|
||||
public GameObject Prefab;
|
||||
public bool UsePool = true;
|
||||
|
||||
public float _instantiateDelay = 0.075f;
|
||||
private float _nextInstantiate = 0f;
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
if (Time.unscaledTime < _nextInstantiate)
|
||||
return;
|
||||
|
||||
_nextInstantiate = Time.unscaledTime + _instantiateDelay;
|
||||
|
||||
if (UsePool)
|
||||
{
|
||||
ObjectPool.Retrieve(Prefab, transform.position, Quaternion.identity);
|
||||
}
|
||||
else
|
||||
{
|
||||
Instantiate(Prefab, transform.position, Quaternion.identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19304078402371645ac157640b97d523
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
IMPORTANT: this project requires the following packages.
|
||||
- Fundamentals.
|
||||
|
||||
|
||||
Fast Object Pool
|
||||
----------------
|
||||
|
||||
Setup:
|
||||
- Add ObjectPool to any object in your scene.
|
||||
- (Optional) Add ObjectPool under a DontDestroyOnLoad object for it to persist through scene changes.
|
||||
|
||||
Usage:
|
||||
- Return objects by using ObjectPool.Retrieve().
|
||||
- You may return types, such as scripts, by using ObjectPool.Retrieve<YourScript>().
|
||||
- Send objects back to the pool using ObjectPool.Store(). You may also store using a delay, like as with Destroy(obj, delay).
|
||||
|
||||
Notes:
|
||||
- All of Fast Object Pool Retrieve() methods mimic Unity Instantiate() overrides.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc20ec02dbc4fea4aa15d8b2c132de4c
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f82c3c8b428ad15498a91dbfd2f7ad87
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,153 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.ObjectPooling
|
||||
{
|
||||
|
||||
|
||||
public class ListStack<GameObject>
|
||||
{
|
||||
public ListStack()
|
||||
{
|
||||
_lastAccessedTime = Time.time;
|
||||
}
|
||||
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Number of entries within the stack.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return Entries.Count; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Entries within this ListStack.
|
||||
/// </summary>
|
||||
public List<GameObject> Entries { get; private set; } = new List<GameObject>();
|
||||
/// <summary>
|
||||
/// Time an entry was added. Indexes will always match up with Entries.
|
||||
/// </summary>
|
||||
public List<float> EntriesAddedTimes { get; private set; } = new List<float>();
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// Last time this ListStack was pushed or popped.
|
||||
/// </summary>
|
||||
private float _lastAccessedTime = 0f;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns if this ListStack has been accessed recently.
|
||||
/// </summary>
|
||||
/// <param name="threshold"></param>
|
||||
/// <returns></returns>
|
||||
public bool AccessedRecently(float threshold)
|
||||
{
|
||||
return ((Time.time - _lastAccessedTime) < threshold);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of GameObjects which were culled from the stack.
|
||||
/// </summary>
|
||||
/// <param name="threshold"></param>
|
||||
/// <returns></returns>
|
||||
public List<GameObject> Cull(float threshold)
|
||||
{
|
||||
List<GameObject> results = new List<GameObject>();
|
||||
float time = Time.time;
|
||||
|
||||
for (int i = 0; i < EntriesAddedTimes.Count; i++)
|
||||
{
|
||||
if (time - EntriesAddedTimes[i] > threshold)
|
||||
results.Add(Entries[i]);
|
||||
}
|
||||
|
||||
if (results.Count > 0)
|
||||
{
|
||||
Entries.RemoveRange(0, results.Count);
|
||||
EntriesAddedTimes.RemoveRange(0, results.Count);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Push an item to the stack.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void Push(GameObject item)
|
||||
{
|
||||
_lastAccessedTime = Time.time;
|
||||
Entries.Add(item);
|
||||
EntriesAddedTimes.Add(_lastAccessedTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pop an item from the stack.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public GameObject Pop()
|
||||
{
|
||||
_lastAccessedTime = Time.time;
|
||||
if (Entries.Count > 0)
|
||||
{
|
||||
//Return the last entry as it's cheaper than returning the first.
|
||||
int nextIndex = Entries.Count - 1;
|
||||
//Set entry then remove from lists.
|
||||
GameObject entry = Entries[nextIndex];
|
||||
Entries.RemoveAt(nextIndex);
|
||||
EntriesAddedTimes.RemoveAt(nextIndex);
|
||||
return entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(GameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove an entry at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void Remove(int index)
|
||||
{
|
||||
_lastAccessedTime = Time.time;
|
||||
Entries.RemoveAt(index);
|
||||
EntriesAddedTimes.RemoveAt(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to remove an item from the entries.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns>True if an item was removed.</returns>
|
||||
public bool Remove(GameObject item)
|
||||
{
|
||||
_lastAccessedTime = Time.time;
|
||||
int index = Entries.IndexOf(item);
|
||||
if (index == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Entries.RemoveAt(index);
|
||||
EntriesAddedTimes.RemoveAt(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the stack; does not destroy items within the stack.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
_lastAccessedTime = Time.time;
|
||||
Entries.Clear();
|
||||
EntriesAddedTimes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d88e910cb7436e44bf78505a26d77ed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,633 @@
|
||||
using GameKit.Utilities;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameKit.Utilities.ObjectPooling
|
||||
{
|
||||
|
||||
public class ObjectPool : MonoBehaviour
|
||||
{
|
||||
#region Types.
|
||||
/// <summary>
|
||||
/// Data for a delayed store object.
|
||||
/// </summary>
|
||||
private struct DelayedStoreData
|
||||
{
|
||||
public DelayedStoreData(float storeTime, bool parentPooler)
|
||||
{
|
||||
StoreTime = storeTime;
|
||||
ParentPooler = parentPooler;
|
||||
}
|
||||
public readonly float StoreTime;
|
||||
public readonly bool ParentPooler;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// Time to wait before destroying object pools with no activity as well pool entries which haven't been used recently. Use -1f to disable this feature.
|
||||
/// </summary>
|
||||
[Tooltip("Time to wait before destroying object pools with no activity as well pool entries which haven't been used recently. Use -1f to disable this feature.")]
|
||||
[SerializeField]
|
||||
private float _dataExpirationDelay = 60f;
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// A singleton instance of this script.
|
||||
/// </summary>
|
||||
private static ObjectPool _instance;
|
||||
/// <summary>
|
||||
/// Transform which houses all pooled objects.
|
||||
/// </summary>
|
||||
private Transform _collector = null;
|
||||
/// <summary>
|
||||
/// List of all object pools.
|
||||
/// </summary>
|
||||
private List<PoolData> _pools = new List<PoolData>();
|
||||
/// <summary>
|
||||
/// Holds transform information for categories of pooled objects. Used to sort pooled objects for easier hierarchy navigation.
|
||||
/// </summary>
|
||||
private Dictionary<string, Transform> _categoryChildren = new Dictionary<string, Transform>();
|
||||
/// <summary>
|
||||
/// Stores which PoolData prefabs are using.
|
||||
/// </summary>
|
||||
private Dictionary<GameObject, PoolData> _poolPrefabs = new Dictionary<GameObject, PoolData>();
|
||||
/// <summary>
|
||||
/// Stores which Pooldata retrieved objects belong to.
|
||||
/// </summary>
|
||||
private Dictionary<GameObject, PoolData> _activeObjects = new Dictionary<GameObject, PoolData>();
|
||||
/// <summary>
|
||||
/// Objects which will be stored after a delay.
|
||||
/// </summary>
|
||||
private Dictionary<GameObject, DelayedStoreData> _delayedStoreObjects = new Dictionary<GameObject, DelayedStoreData>();
|
||||
#endregion
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
//Make sure there is only once instance.
|
||||
if (_instance != null && _instance != this)
|
||||
{
|
||||
if (Debug.isDebugBuild) Debug.LogWarning("Multiple ObjectPool scripts found. This script auto loads itself and does not need to be placed in your scenes.");
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
|
||||
}
|
||||
private void Start()
|
||||
{
|
||||
StartCoroutine(__CleanupChecks());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys null objects within SpawnedObjects.
|
||||
/// </summary>
|
||||
private IEnumerator __CleanupChecks()
|
||||
{
|
||||
int poolIndex = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* Check which objects must be delayed stored first.
|
||||
* This is so objects which need to be stored will
|
||||
* be added to their appropriate pool before it
|
||||
* potentially gets expired, which would double the work
|
||||
* because then the pool would get recreated. */
|
||||
if (_delayedStoreObjects.Count > 0)
|
||||
{
|
||||
List<GameObject> keysToRemove = new List<GameObject>();
|
||||
foreach (KeyValuePair<GameObject, DelayedStoreData> item in _delayedStoreObjects)
|
||||
{
|
||||
if (Time.time >= item.Value.StoreTime)
|
||||
{
|
||||
//Add to collection of keys to remove after.
|
||||
keysToRemove.Add(item.Key);
|
||||
//Store object.
|
||||
Store(item.Key, item.Value.ParentPooler);
|
||||
}
|
||||
}
|
||||
//Now store away keys to remove, and get them out of the dictionary.
|
||||
for (int i = 0; i < keysToRemove.Count; i++)
|
||||
_delayedStoreObjects.Remove(keysToRemove[i]);
|
||||
}
|
||||
|
||||
if (_dataExpirationDelay > 0f && _pools.Count > 0)
|
||||
{
|
||||
if (poolIndex >= _pools.Count)
|
||||
poolIndex = 0;
|
||||
|
||||
//If pool hasn't been used in awhile then expire it.
|
||||
if (_pools[poolIndex].PoolExpired())
|
||||
{
|
||||
_poolPrefabs.Remove(_pools[poolIndex].Prefab);
|
||||
DestroyPool(_pools[poolIndex], false);
|
||||
_pools.RemoveAt(poolIndex);
|
||||
poolIndex--;
|
||||
}
|
||||
//Not expired. Try to cull the pool.
|
||||
else
|
||||
{
|
||||
List<GameObject> culledObjects = _pools[poolIndex].Cull();
|
||||
for (int i = 0; i < culledObjects.Count; i++)
|
||||
{
|
||||
Destroy(culledObjects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
poolIndex++;
|
||||
}
|
||||
|
||||
//Wait a frame.
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys all stored and optionally retrieved objects. Race conditions may be created by this coroutine if trying to retrieve or store objects before it finishes executing.
|
||||
/// </summary>
|
||||
/// <param name="destroyActive">True to also destroy active retrieved gameObjects. False will erase active objects from memory, but not destroy them.</param>
|
||||
public IEnumerator __Reset(bool destroyActive)
|
||||
{
|
||||
/* Clear references to which pool is for each prefab,
|
||||
* as well to which transform spawned objects child to when stored. */
|
||||
_poolPrefabs.Clear();
|
||||
_categoryChildren.Clear();
|
||||
_pools.Clear();
|
||||
/* When resetting clear the delayed store
|
||||
* objects. If destroyActive is set to true
|
||||
* then they will be picked up. */
|
||||
_delayedStoreObjects.Clear();
|
||||
|
||||
//Destory all children.
|
||||
transform.DestroyChildren(false);
|
||||
|
||||
WaitForEndOfFrame endOfFrame = new WaitForEndOfFrame();
|
||||
while (transform.childCount > 0)
|
||||
yield return endOfFrame;
|
||||
|
||||
//Destroy active objects.
|
||||
if (destroyActive)
|
||||
{
|
||||
//Make a new list to prevent collection from being modified.
|
||||
List<GameObject> objects = new List<GameObject>();
|
||||
foreach (KeyValuePair<GameObject, PoolData> value in _activeObjects)
|
||||
objects.Add(value.Key);
|
||||
//Go through collection.
|
||||
for (int i = 0; i < objects.Count; i++)
|
||||
{
|
||||
if (objects[i] != null)
|
||||
{
|
||||
Destroy(objects[i]);
|
||||
while (objects[i] != null)
|
||||
yield return endOfFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
_activeObjects.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys all Objects within the specified PoolData then clears the PoolData.
|
||||
/// </summary>
|
||||
/// <param name="poolData"></param>
|
||||
/// <param name="removeFromList">True to remove from pools list.</param>
|
||||
private void DestroyPool(PoolData poolData, bool removeFromList)
|
||||
{
|
||||
for (int i = 0; i < poolData.Objects.Entries.Count; i++)
|
||||
{
|
||||
if (poolData.Objects.Entries[i] != null)
|
||||
Destroy(poolData.Objects.Entries[i]);
|
||||
}
|
||||
|
||||
if (removeFromList)
|
||||
_pools.Remove(poolData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the PoolData which houses the desired prefab.
|
||||
/// </summary>
|
||||
/// <param name="prefab">Prefab to return a pool for.</param>
|
||||
/// <returns></returns>
|
||||
private PoolData ReturnPoolData(GameObject prefab)
|
||||
{
|
||||
PoolData result;
|
||||
_poolPrefabs.TryGetValue(prefab, out result);
|
||||
|
||||
if (result == null)
|
||||
result = CreatePool(prefab);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position and rotation of the specified GameObject.
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="position"></param>
|
||||
/// <param name="rotation"></param>
|
||||
private void SetGameObjectPositionRotation(GameObject result, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
result.transform.position = position;
|
||||
result.transform.rotation = rotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pooled object of the specified prefab.
|
||||
/// </summary>
|
||||
/// <param name="poolObject">Prefab to retrieve.</param>
|
||||
/// <returns></returns>
|
||||
public static GameObject Retrieve(GameObject poolObject)
|
||||
{
|
||||
return _instance.RetrieveInternal(poolObject);
|
||||
}
|
||||
private GameObject RetrieveInternal(GameObject poolObject)
|
||||
{
|
||||
PoolData pool;
|
||||
GameObject result = ReturnPooledObject(poolObject, out pool);
|
||||
|
||||
//If pool isn't null then reset result.
|
||||
if (result != null && pool != null)
|
||||
{
|
||||
SetGameObjectPositionRotation(result, pool.Prefab.transform.position, pool.Prefab.transform.rotation);
|
||||
result.transform.SetParent(null);
|
||||
}
|
||||
|
||||
return FinalizeRetrieve(result, pool);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a pooled object of the specified prefab.
|
||||
/// </summary>
|
||||
/// <param name="poolObject">Prefab to retrieve.</param>
|
||||
/// <param name="parent">Parent to attach the retrieved prefab to.</param>
|
||||
/// <param name="instantiateInWorldSpace">Use true when assigning a parent Object to maintain the world position of the Object, instead of setting its position relative to the new parent. Pass false to set the Object's position relative to its new parent.</param>
|
||||
/// <returns></returns>
|
||||
public static GameObject Retrieve(GameObject poolObject, Transform parent, bool instantiateInWorldSpace = true)
|
||||
{
|
||||
return _instance.RetrieveInternal(poolObject, parent, instantiateInWorldSpace);
|
||||
}
|
||||
public GameObject RetrieveInternal(GameObject poolObject, Transform parent, bool instantiateInWorldSpace = true)
|
||||
{
|
||||
PoolData pool;
|
||||
GameObject result = ReturnPooledObject(poolObject, out pool);
|
||||
|
||||
//If pool isn't null then reset result.
|
||||
if (result != null && pool != null)
|
||||
{
|
||||
SetGameObjectPositionRotation(result, pool.Prefab.transform.position, pool.Prefab.transform.rotation);
|
||||
result.transform.SetParent(parent, instantiateInWorldSpace);
|
||||
}
|
||||
|
||||
return FinalizeRetrieve(result, pool);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pooled object of the specified prefab.
|
||||
/// </summary>
|
||||
/// <param name="poolObject">Prefab to retrieve.</param>
|
||||
/// <param name="position">Position for the retrieved object.</param>
|
||||
/// <param name="rotation">Orientation for the retrieved object.</param>
|
||||
/// <returns></returns>
|
||||
public static GameObject Retrieve(GameObject poolObject, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
return _instance.RetrieveInternal(poolObject, position, rotation);
|
||||
}
|
||||
private GameObject RetrieveInternal(GameObject poolObject, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
PoolData pool;
|
||||
GameObject result = ReturnPooledObject(poolObject, out pool);
|
||||
|
||||
//If pool isn't null then reset result.
|
||||
if (result != null)
|
||||
{
|
||||
SetGameObjectPositionRotation(result, position, rotation);
|
||||
result.transform.SetParent(null);
|
||||
}
|
||||
|
||||
return FinalizeRetrieve(result, pool);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a pooled object of the specified prefab.
|
||||
/// </summary>
|
||||
/// <param name="poolObject">Prefab to retrieve.</param>
|
||||
/// <param name="position">Position for the retrieved object.</param>
|
||||
/// <param name="rotation">Orientation for the retrieved object.</param>
|
||||
/// <param name="parent">Transform to parent the retrieved object to.</param>
|
||||
/// <returns></returns>
|
||||
public GameObject Retrieve(GameObject poolObject, Vector3 position, Quaternion rotation, Transform parent)
|
||||
{
|
||||
PoolData pool;
|
||||
GameObject result = ReturnPooledObject(poolObject, out pool);
|
||||
|
||||
//If pool isn't null then reset result.
|
||||
if (result != null)
|
||||
{
|
||||
SetGameObjectPositionRotation(result, position, rotation);
|
||||
result.transform.SetParent(parent, true);
|
||||
}
|
||||
|
||||
return FinalizeRetrieve(result, pool);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pooled object of the specified prefab.
|
||||
/// </summary>
|
||||
/// <param name="prefab">Prefab to retrieve.</param>
|
||||
/// <returns></returns>
|
||||
public static T Retrieve<T>(GameObject prefab)
|
||||
{
|
||||
return _instance.RetrieveInternal<T>(prefab);
|
||||
}
|
||||
private T RetrieveInternal<T>(GameObject prefab)
|
||||
{
|
||||
PoolData pool;
|
||||
GameObject result = ReturnPooledObject(prefab, out pool);
|
||||
|
||||
//If pool isn't null then reset result.
|
||||
if (result != null && pool != null)
|
||||
{
|
||||
SetGameObjectPositionRotation(result, pool.Prefab.transform.position, pool.Prefab.transform.rotation);
|
||||
result.transform.SetParent(null);
|
||||
}
|
||||
|
||||
return FinalizeRetrieve(result, pool).GetComponent<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pooled object of the specified prefab.
|
||||
/// </summary>
|
||||
/// <param name="prefab">Prefab to retrieve.</param>
|
||||
/// <param name="parent">Parent to attach the retrieved prefab to.</param>
|
||||
/// <param name="instantiateInWorldSpace">Use true when assigning a parent Object to maintain the world position of the Object, instead of setting its position relative to the new parent. Pass false to set the Object's position relative to its new parent.</param>
|
||||
/// <returns></returns>
|
||||
public static T Retrieve<T>(GameObject prefab, Transform parent, bool instantiateInWorldSpace = true)
|
||||
{
|
||||
return _instance.RetrieveInternal<T>(prefab, parent, instantiateInWorldSpace);
|
||||
}
|
||||
private T RetrieveInternal<T>(GameObject prefab, Transform parent, bool instantiateInWorldSpace = true)
|
||||
{
|
||||
PoolData pool;
|
||||
GameObject result = ReturnPooledObject(prefab, out pool);
|
||||
|
||||
//If pool isn't null then reset result.
|
||||
if (result != null && pool != null)
|
||||
{
|
||||
SetGameObjectPositionRotation(result, pool.Prefab.transform.position, pool.Prefab.transform.rotation);
|
||||
result.transform.SetParent(parent, instantiateInWorldSpace);
|
||||
}
|
||||
|
||||
return FinalizeRetrieve(result, pool).GetComponent<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pooled object of the specified prefab.
|
||||
/// </summary>
|
||||
/// <param name="prefab">Prefab to retrieve.</param>
|
||||
/// <param name="position">Position for the retrieved object.</param>
|
||||
/// <param name="rotation">Orientation for the retrieved object.</param>
|
||||
/// <returns></returns>
|
||||
public static T Retrieve<T>(GameObject prefab, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
return _instance.RetrieveInternal<T>(prefab, position, rotation);
|
||||
}
|
||||
private T RetrieveInternal<T>(GameObject prefab, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
PoolData pool;
|
||||
GameObject result = ReturnPooledObject(prefab, out pool);
|
||||
|
||||
//If pool isn't null then reset result.
|
||||
if (result != null)
|
||||
{
|
||||
SetGameObjectPositionRotation(result, position, rotation);
|
||||
result.transform.SetParent(null);
|
||||
}
|
||||
|
||||
return FinalizeRetrieve(result, pool).GetComponent<T>();
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a pooled object of the specified prefab.
|
||||
/// </summary>
|
||||
/// <param name="prefab">Prefab to retrieve.</param>
|
||||
/// <param name="position">Position for the retrieved object.</param>
|
||||
/// <param name="rotation">Orientation for the retrieved object.</param>
|
||||
/// <param name="parent">Transform to parent the retrieved object to.</param>
|
||||
/// <returns></returns>
|
||||
public static T Retrieve<T>(GameObject prefab, Vector3 position, Quaternion rotation, Transform parent)
|
||||
{
|
||||
return _instance.RetrieveInternal<T>(prefab, position, rotation, parent);
|
||||
}
|
||||
private T RetrieveInternal<T>(GameObject prefab, Vector3 position, Quaternion rotation, Transform parent)
|
||||
{
|
||||
PoolData pool;
|
||||
GameObject result = ReturnPooledObject(prefab, out pool);
|
||||
|
||||
//If pool isn't null then reset result.
|
||||
if (result != null)
|
||||
{
|
||||
SetGameObjectPositionRotation(result, position, rotation);
|
||||
result.transform.SetParent(parent, true);
|
||||
}
|
||||
|
||||
return FinalizeRetrieve(result, pool).GetComponent<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes the retrieved object by performing additional reset actions before returning git.
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="pool"></param>
|
||||
/// <returns></returns>
|
||||
private GameObject FinalizeRetrieve(GameObject result, PoolData pool)
|
||||
{
|
||||
_activeObjects[result] = pool;
|
||||
//Set the item active based on if the prefab is.
|
||||
if (pool != null)
|
||||
result.SetActive(pool.Prefab.activeSelf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an object to it's pool.
|
||||
/// </summary>
|
||||
/// <param name="instantiatedObject"></param>
|
||||
/// <param name="parentPooler">True to set the objects parent as the ObjectPooler.</param>
|
||||
public static void Store(GameObject instantiatedObject, float delay, bool parentPooler = true)
|
||||
{
|
||||
|
||||
_instance.StoreInternal(instantiatedObject, delay, parentPooler);
|
||||
}
|
||||
private void StoreInternal(GameObject instantiatedObject, float delay, bool parentPooler = true)
|
||||
{
|
||||
_delayedStoreObjects[instantiatedObject] = new DelayedStoreData(Time.time + delay, parentPooler);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an object to it's pool.
|
||||
/// </summary>
|
||||
/// <param name="instantiatedObject"></param>
|
||||
/// <param name="parentPooler">True to set the objects parent as the ObjectPooler.</param>
|
||||
public static void Store(GameObject instantiatedObject, bool parentPooler = true)
|
||||
{
|
||||
_instance.StoreInternal(instantiatedObject, parentPooler);
|
||||
}
|
||||
private void StoreInternal(GameObject instantiatedObject, bool parentPooler = true)
|
||||
{
|
||||
//If passed in pool object is null.
|
||||
if (instantiatedObject == null)
|
||||
{
|
||||
Debug.LogWarning("ObjectPooler -> StoreObject -> poolObject cannot be null.");
|
||||
return;
|
||||
}
|
||||
|
||||
PoolData pool;
|
||||
/* Try to get the pool from the dictionary lookup.
|
||||
* If not found then create a new pool. */
|
||||
if (_activeObjects.TryGetValue(instantiatedObject, out pool))
|
||||
_activeObjects.Remove(instantiatedObject);
|
||||
else
|
||||
pool = ReturnPoolData(instantiatedObject);
|
||||
|
||||
AddToPool(instantiatedObject, pool, parentPooler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes and assigns the collector transform.
|
||||
/// </summary>
|
||||
private void MakeCollector()
|
||||
{
|
||||
if (_collector == null)
|
||||
{
|
||||
/* If collect is null it's safe to assume it's children were destroyed
|
||||
* in which case clear dictionary used for categories. */
|
||||
_categoryChildren.Clear();
|
||||
//Make a new collector.
|
||||
_collector = new GameObject().transform;
|
||||
_collector.name = "ObjectPoolerCollector";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a poolobject without performing any operations on it.
|
||||
/// </summary>
|
||||
/// <param name="prefab"></param>
|
||||
/// <param name="pool">Pool the returned GameObject came from.</param>
|
||||
private GameObject ReturnPooledObject(GameObject prefab, out PoolData pool)
|
||||
{
|
||||
//If passed in prefab is null.
|
||||
if (prefab == null)
|
||||
{
|
||||
pool = null;
|
||||
Debug.LogError("ObjectPooler -> RetrieveObject -> prefab cannot be null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
pool = ReturnPoolData(prefab);
|
||||
|
||||
GameObject result = pool.Objects.Pop();
|
||||
/* If a null object was returned then instantiate a new object and
|
||||
* use it as the result. Doing so bypasses the need to check pool
|
||||
* count, as well handles conditions in which the object may have
|
||||
* been destroyed or the pool has become corrupt. In the chance the pool was
|
||||
* corrupt or an object destroyed it will progressively clean itself with every Pop(). */
|
||||
if (result == null)
|
||||
result = Instantiate(prefab);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a pool of the specified prefab with one entry and adds it to the pools list.
|
||||
/// </summary>
|
||||
/// <param name="prefab"></param>
|
||||
/// <returns>Returns the created PoolData.</returns>
|
||||
private PoolData CreatePool(GameObject prefab)
|
||||
{
|
||||
if (prefab == null)
|
||||
{
|
||||
Debug.LogError("ObjectPooler -> CreatePool -> prefab cannot be null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
//Make a new pool.
|
||||
PoolData pool = new PoolData(prefab, _dataExpirationDelay);
|
||||
|
||||
/* Check if the poolObject has a name in the scene.
|
||||
* If it does then the object is spawned. If not
|
||||
* it must be a prefab. */
|
||||
if (prefab.scene.name != null)
|
||||
AddToPool(prefab, pool, true);
|
||||
|
||||
//Add new pool to list then return it.
|
||||
_pools.Add(pool);
|
||||
_poolPrefabs[prefab] = pool;
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an object to a specified pool.
|
||||
/// </summary>
|
||||
/// <param name="poolObject"></param>
|
||||
/// <param name="pool"></param>
|
||||
/// <param name="parentPooler">True to set the objects parent as the ObjectPooler.</param>
|
||||
private void AddToPool(GameObject instantiatedObject, PoolData pool, bool parentPooler = true)
|
||||
{
|
||||
if (instantiatedObject == null)
|
||||
{
|
||||
Debug.LogError("ObjectPooler -> AddToPool -> instantiatedObject is null.");
|
||||
return;
|
||||
}
|
||||
if (pool == null)
|
||||
{
|
||||
Debug.LogError("ObjectPooler -> AddToPool -> pool is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
instantiatedObject.SetActive(false);
|
||||
|
||||
pool.Objects.Push(instantiatedObject);
|
||||
|
||||
if (parentPooler)
|
||||
ParentPooler(instantiatedObject, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the parent of the specified object to the proper child within the ObjectPooler.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
private void ParentPooler(GameObject poolObject, bool worldPositionStays)
|
||||
{
|
||||
MakeCollector();
|
||||
|
||||
Transform newParent;
|
||||
string tag = poolObject.tag;
|
||||
/* Try to set parent from dictionary. If not found then make a new
|
||||
* child object attached to the object pooler and add to dictionary,
|
||||
* then use created value. */
|
||||
if (!_categoryChildren.TryGetValue(tag, out newParent))
|
||||
{
|
||||
newParent = new GameObject().transform;
|
||||
newParent.name = tag;
|
||||
//Set category transform to collector.
|
||||
newParent.SetParent(_collector);
|
||||
_categoryChildren[tag] = newParent;
|
||||
}
|
||||
|
||||
poolObject.transform.SetParent(newParent, worldPositionStays);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab8f6cec624bac24d8fcc6a7a27a07e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace GameKit.Utilities.ObjectPooling
|
||||
{
|
||||
|
||||
public class PoolData
|
||||
{
|
||||
public PoolData(GameObject prefab, float expirationDuration)
|
||||
{
|
||||
Prefab = prefab;
|
||||
_expirationDuration = expirationDuration;
|
||||
}
|
||||
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Prefab for this pool.
|
||||
/// </summary>
|
||||
public readonly GameObject Prefab = null;
|
||||
/// <summary>
|
||||
/// Objects currently in the pool.
|
||||
/// </summary>
|
||||
public ListStack<GameObject> Objects = new ListStack<GameObject>();
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// Time this pool must remain idle before it's considered expired.
|
||||
/// </summary>
|
||||
private float _expirationDuration = -1f;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the pool has expired due to inactivity.
|
||||
/// </summary>
|
||||
/// <param name="expirationDuration"></param>
|
||||
/// <returns></returns>
|
||||
public bool PoolExpired()
|
||||
{
|
||||
if (_expirationDuration == -1f)
|
||||
return false;
|
||||
|
||||
return !Objects.AccessedRecently(_expirationDuration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of GameObjects which were culled from the stack using the default expiration duration.
|
||||
/// </summary>
|
||||
/// <param name="threshold"></param>
|
||||
/// <returns></returns>
|
||||
public List<GameObject> Cull()
|
||||
{
|
||||
if (_expirationDuration == -1f)
|
||||
return new List<GameObject>();
|
||||
|
||||
return Objects.Cull(_expirationDuration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user