A collection of useful C# extension methods for the Unity engine. |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
public static class ShuffleListExtensions | |
{ | |
/// <summary> | |
/// Shuffle the list in place using the Fisher-Yates method. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="list"></param> | |
public static void Shuffle<T>(this IList<T> list) | |
{ | |
Random rng = new Random(); | |
int n = list.Count; | |
while (n > 1) | |
{ | |
n--; | |
int k = rng.Next(n + 1); | |
T value = list[k]; | |
list[k] = list[n]; | |
list[n] = value; | |
} | |
} | |
/// <summary> | |
/// Return a random item from the list. | |
/// Sampling with replacement. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="list"></param> | |
/// <returns></returns> | |
public static T RandomItem<T>(this IList<T> list) | |
{ | |
if (list.Count == 0) throw new System.IndexOutOfRangeException("Cannot select a random item from an empty list"); | |
return list[UnityEngine.Random.Range(0, list.Count)]; | |
} | |
/// <summary> | |
/// Removes a random item from the list, returning that item. | |
/// Sampling without replacement. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="list"></param> | |
/// <returns></returns> | |
public static T RemoveRandom<T>(this IList<T> list) | |
{ | |
if (list.Count == 0) throw new System.IndexOutOfRangeException("Cannot remove a random item from an empty list"); | |
int index = UnityEngine.Random.Range(0, list.Count); | |
T item = list[index]; | |
list.RemoveAt(index); | |
return item; | |
} | |
} |
using System; | |
using System.Reflection; | |
using System.Text.RegularExpressions; | |
using System.Text; | |
public static class StringExtensionMethods | |
{ | |
public static string Truncate(this string value, int maxLength) | |
{ | |
if (string.IsNullOrEmpty(value)) return value; | |
return value.Length <= maxLength ? value : value.Substring(0, maxLength); | |
} | |
// Named format strings from object attributes. Eg: | |
// string blaStr = aPerson.ToString("My name is {FirstName} {LastName}.") | |
// From: http://www.hanselman.com/blog/CommentView.aspx?guid=fde45b51-9d12-46fd-b877-da6172fe1791 | |
public static string ToString(this object anObject, string aFormat) | |
{ | |
return ToString(anObject, aFormat, null); | |
} | |
public static string ToString(this object anObject, string aFormat, IFormatProvider formatProvider) | |
{ | |
StringBuilder sb = new StringBuilder(); | |
Type type = anObject.GetType(); | |
Regex reg = new Regex(@"({)([^}]+)(})", RegexOptions.IgnoreCase); | |
MatchCollection mc = reg.Matches(aFormat); | |
int startIndex = 0; | |
foreach (Match m in mc) | |
{ | |
Group g = m.Groups[2]; //it's second in the match between { and } | |
int length = g.Index - startIndex - 1; | |
sb.Append(aFormat.Substring(startIndex, length)); | |
string toGet = string.Empty; | |
string toFormat = string.Empty; | |
int formatIndex = g.Value.IndexOf(":"); //formatting would be to the right of a : | |
if (formatIndex == -1) //no formatting, no worries | |
{ | |
toGet = g.Value; | |
} | |
else //pickup the formatting | |
{ | |
toGet = g.Value.Substring(0, formatIndex); | |
toFormat = g.Value.Substring(formatIndex + 1); | |
} | |
//first try properties | |
PropertyInfo retrievedProperty = type.GetProperty(toGet); | |
Type retrievedType = null; | |
object retrievedObject = null; | |
if (retrievedProperty != null) | |
{ | |
retrievedType = retrievedProperty.PropertyType; | |
retrievedObject = retrievedProperty.GetValue(anObject, null); | |
} | |
else //try fields | |
{ | |
FieldInfo retrievedField = type.GetField(toGet); | |
if (retrievedField != null) | |
{ | |
retrievedType = retrievedField.FieldType; | |
retrievedObject = retrievedField.GetValue(anObject); | |
} | |
} | |
if (retrievedType != null) //Cool, we found something | |
{ | |
string result = string.Empty; | |
if (toFormat == string.Empty) //no format info | |
{ | |
result = retrievedType.InvokeMember("ToString", | |
BindingFlags.Public | BindingFlags.NonPublic | | |
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase | |
, null, retrievedObject, null) as string; | |
} | |
else //format info | |
{ | |
result = retrievedType.InvokeMember("ToString", | |
BindingFlags.Public | BindingFlags.NonPublic | | |
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase | |
, null, retrievedObject, new object[] { toFormat, formatProvider }) as string; | |
} | |
sb.Append(result); | |
} | |
else //didn't find a property with that name, so be gracious and put it back | |
{ | |
sb.Append("{"); | |
sb.Append(g.Value); | |
sb.Append("}"); | |
} | |
startIndex = g.Index + g.Length + 1; | |
} | |
if (startIndex < aFormat.Length) //include the rest (end) of the string | |
{ | |
sb.Append(aFormat.Substring(startIndex)); | |
} | |
return sb.ToString(); | |
} | |
} |
using UnityEngine; | |
public static class ExtensionMethods | |
{ | |
public static float LinearRemap(this float value, | |
float valueRangeMin, float valueRangeMax, | |
float newRangeMin, float newRangeMax) | |
{ | |
return (value - valueRangeMin) / (valueRangeMax - valueRangeMin) * (newRangeMax - newRangeMin) + newRangeMin; | |
} | |
public static int WithRandomSign(this int value, float negativeProbability = 0.5f) | |
{ | |
return Random.value < negativeProbability ? -value : value; | |
} | |
} |
using UnityEngine; | |
public static class VectorExtensionMethods { | |
public static Vector2 xy(this Vector3 v) { | |
return new Vector2(v.x, v.y); | |
} | |
public static Vector3 WithX(this Vector3 v, float x) { | |
return new Vector3(x, v.y, v.z); | |
} | |
public static Vector3 WithY(this Vector3 v, float y) { | |
return new Vector3(v.x, y, v.z); | |
} | |
public static Vector3 WithZ(this Vector3 v, float z) { | |
return new Vector3(v.x, v.y, z); | |
} | |
public static Vector2 WithX(this Vector2 v, float x) { | |
return new Vector2(x, v.y); | |
} | |
public static Vector2 WithY(this Vector2 v, float y) { | |
return new Vector2(v.x, y); | |
} | |
public static Vector3 WithZ(this Vector2 v, float z) { | |
return new Vector3(v.x, v.y, z); | |
} | |
// axisDirection - unit vector in direction of an axis (eg, defines a line that passes through zero) | |
// point - the point to find nearest on line for | |
public static Vector3 NearestPointOnAxis(this Vector3 axisDirection, Vector3 point, bool isNormalized = false) | |
{ | |
if (!isNormalized) axisDirection.Normalize(); | |
var d = Vector3.Dot(point, axisDirection); | |
return axisDirection * d; | |
} | |
// lineDirection - unit vector in direction of line | |
// pointOnLine - a point on the line (allowing us to define an actual line in space) | |
// point - the point to find nearest on line for | |
public static Vector3 NearestPointOnLine( | |
this Vector3 lineDirection, Vector3 point, Vector3 pointOnLine, bool isNormalized = false) | |
{ | |
if (!isNormalized) lineDirection.Normalize(); | |
var d = Vector3.Dot(point - pointOnLine, lineDirection); | |
return pointOnLine + (lineDirection * d); | |
} | |
} |
This comment has been minimized.
This comment has been minimized.
david-jares
commented
Feb 5, 2019
@mollsju I Dont think its a typo, as that is the only function that makes sense. vector2 has no Z. So when you have a vector 2 and need to convert it to vector3, you can pass the vector2 and a zvalue as an argument. |
This comment has been minimized.
This comment has been minimized.
david-jares
commented
Feb 5, 2019
•
I personally also added public static Vector3 WithAddY(this Vector3 v, float y) public static Vector3 WithAddZ(this Vector3 v, float z) so that I can just add to the existing value |
This comment has been minimized.
This comment has been minimized.
dracolytch
commented
Apr 10, 2019
Some of these are really helpful. I'm also working on a library of extension methods. Would it be OK for me to integrate some of these with my project? It's MIT license, so any of these you give me permission to integrate would become MIT license. https://github.com/dracolytch/DracoSoftwareExtensionsForUnity |
This comment has been minimized.
mollsju commentedOct 11, 2017
•
edited
Theres a typo in vector extensions:
public static Vector3 WithZ(this Vector2 v, float z) { return new Vector3(v.x, v.y, z); }
Should be
public static Vector2 WithZ
and it should return a Vector2, as the Vector3.WithZ is already defined.