Calendar
Mo | Tu | We | Th | Fr | Sa | Su |
---|
28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
Archive
- 2002
- 2003
- 2004
- 2005
- 2006
- 2007
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2019
- 2020
|
Website may be up and down over next few months. I'm currently doing a complete overhaul of everything.
Going back to simple individual .htm pages, new overall site theme, sanitizing and cleaning up html of all
pages and blog posts, attempting to implement a new tooling and publishing system etc etc.
Below is a code sample containing drawing methods for drawing check boxes or any control type in a grid based layout similar to the SelectionGrid.
using System;
using UnityEngine;
public class ControlGrid
{
/// <summary>
/// Draw a grid of check boxes similar to SelectionGrid.
/// </summary>
/// <param name="checkedValues">Specifies the checked values of the check boxes.</param>
/// <param name="text">The content for each individual check box.</param>
/// <param name="columns">The number of columns in the grid.</param>
/// <param name="style">The style to be applied to each check box.</param>
/// <param name="options">Specifies layout options to be applied to each check box.</param>
/// <returns>Returns the checked state for each check box.</returns>
/// <remarks><p>Check boxes are drawn top to bottom, left to right.</p> </remarks>
/// <exception cref="IndexOutOfRangeException">Can occur if the size of the array is too small.</exception>
public static bool[] DrawCheckBoxGrid(bool[] checkedValues, string[] text, int columns, GUIStyle style, params GUILayoutOption[] options)
{
// convert string content into gui content
var content = new GUIContent[text.Length];
for (var i = 0; i < content.Length; i++)
{
content[i] = new GUIContent(text[i]);
}
return DrawCheckBoxGrid(checkedValues, content, columns, style, options);
}
/// <summary>
/// Draw a grid of check boxes similar to SelectionGrid.
/// </summary>
/// <param name="checkedValues">Specifies the checked values of the check boxes.</param>
/// <param name="textures">The content for each individual check box.</param>
/// <param name="columns">The number of columns in the grid.</param>
/// <param name="style">The style to be applied to each check box.</param>
/// <param name="options">Specifies layout options to be applied to each check box.</param>
/// <returns>Returns the checked state for each check box.</returns>
/// <remarks><p>Check boxes are drawn top to bottom, left to right.</p> </remarks>
/// <exception cref="IndexOutOfRangeException">Can occur if the size of the array is too small.</exception>
public static bool[] DrawCheckBoxGrid(bool[] checkedValues, Texture2D[] textures, int columns, GUIStyle style, params GUILayoutOption[] options)
{
// convert texture content into gui content
var content = new GUIContent[textures.Length];
for (var i = 0; i < content.Length; i++)
{
content[i] = new GUIContent(string.Empty, textures[i]);
}
return DrawCheckBoxGrid(checkedValues, content, columns, style, options);
}
/// <summary>
/// Draw a grid of check boxes similar to SelectionGrid.
/// </summary>
/// <param name="checkedValues">Specifies the checked values of the check boxes.</param>
/// <param name="content">The content for each individual check box.</param>
/// <param name="columns">The number of columns in the grid.</param>
/// <param name="style">The style to be applied to each check box.</param>
/// <param name="options">Specifies layout options to be applied to each check box.</param>
/// <returns>Returns the checked state for each check box.</returns>
/// <remarks><p>Check boxes are drawn top to bottom, left to right.</p> </remarks>
/// <exception cref="IndexOutOfRangeException">Can occur if the size of the array is too small.</exception>
public static bool[] DrawCheckBoxGrid(bool[] checkedValues, GUIContent[] content, int columns, GUIStyle style, params GUILayoutOption[] options)
{
return DrawGenericGrid((e, i, s, o) => GUILayout.Toggle(e[i], content[i], style, options), checkedValues, content, columns, style, options);
}
/// <summary>
/// Draw a grid of controls using a draw callback similar to SelectionGrid.
/// </summary>
/// <param name="drawCallback">Specifies a draw callback that is responsible for performing the actual drawing.</param>
/// <param name="values">Specifies the values of the controls.</param>
/// <param name="content">The content for each individual control.</param>
/// <param name="columns">The number of columns in the grid.</param>
/// <param name="style">The style to be applied to each control.</param>
/// <param name="options">Specifies layout options to be applied to each control.</param>
/// <returns>Returns the value for each control.</returns>
/// <remarks><p>Controls are drawn top to bottom, left to right.</p> </remarks>
/// <exception cref="IndexOutOfRangeException">Can occur if the size of the array is too small.</exception>
/// <exception cref="ArgumentNullException">If the drawCallback is null.</exception>
public static T[] DrawGenericGrid<T>(Func<T[], int, GUIStyle, GUILayoutOption[], T> drawCallback, T[] values, GUIContent[] content, int columns, GUIStyle style, params GUILayoutOption[] options)
{
if (drawCallback == null)
{
throw new ArgumentNullException("drawCallback");
}
GUILayout.BeginVertical();
var rowIndex = 0;
var columnIndex = 0;
var index = rowIndex * columns + columnIndex;
GUILayout.BeginHorizontal();
while (index < values.Length)
{
// draw control
values[index] = drawCallback(values, index, style, options);
// move to next column
columnIndex++;
// if passed max columns move down to next row and set to first column
if (columnIndex > columns - 1)
{
columnIndex = 0;
rowIndex++;
// remember to start a new horizontal layout
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
}
// re-calculate the index
index = rowIndex * columns + columnIndex;
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
return values;
}
}
Here is a simple example of how to use the draw methods
var emptyContent = new[] { GUIContent.none, GUIContent.none, GUIContent.none,
GUIContent.none, GUIContent.none, GUIContent.none,
GUIContent.none, GUIContent.none, GUIContent.none };
GUILayout.BeginVertical(GUILayout.MinWidth(128));
rule.IgnoreUpper = GUILayout.Toggle(rule.IgnoreUpper, "Upper Neighbors");
rule.NeighborsUpper = ControlGrid.DrawCheckBoxGrid(rule.NeighborsUpper, emptyContent, 3, GUI.skin.button, GUILayout.MaxWidth(32), GUILayout.MaxHeight(32));
GUILayout.EndVertical();
b55e85cb-8172-4da5-8ad2-359b5ebb0ee3|0|.0
MEFHelpers provides a helper class that provides a static method to make MEF composition easier. /// <summary>
/// Provides a helper class for MEF composition.
/// </summary>
public sealed class MEFHelpers
{
/// <summary>
/// Composes MEF parts.
/// </summary>
/// <param name="parts">The composable object parts.</param>
public static void Compose(params object[] parts)
{
Compose(parts, new string[0]);
}
/// <summary>
/// Composes MEF parts.
/// </summary>
/// <param name="searchFolders">Provides a series of search folders to search for *.dll files.</param>
/// <param name="parts">The composable object parts.</param>
public static void Compose(IEnumerable<string> searchFolders, params object[] parts)
{
// setup composition container
var catalog = new AggregateCatalog();
// check if folders were specified
if (searchFolders != null)
{
// add search folders
foreach (var folder in searchFolders.Where(System.IO.Directory.Exists))
{
catalog.Catalogs.Add(new DirectoryCatalog(folder, "*.dll"));
}
}
// compose and create plug ins
var composer = new CompositionContainer(catalog);
composer.ComposeParts(parts);
}
}
A usage scenario is provided below
public class KissCSMEFComposer
{
[ImportMany(typeof(IProcessor))]
public List<Lazy<IProcessor>> StringProcessors;
[ImportMany(typeof(ICommandRepository))]
public List<Lazy<ICommandRepository>> CommandRepository;
}
var composer = new KissCSMEFComposer();
// try to connect with MEF types
try
{
MEFHelpers.Compose(this.SearchFolders, composer);
}
catch (Exception ex)
{
// ERR: handle error
}
// register string processors
foreach (var processor in composer.StringProcessors)
{
StringProcessorRepository.Instance.Register(processor.Value);
}
// etc ...
12475fb8-8d55-450f-8018-946f135dffa0|0|.0
The code below can be used to log performance of your code.
using System.Collections.Generic;
using System.Diagnostics;
/// <summary>
/// Provides a simple performance testing class that utilizes <see cref="Stopwatch"/>.
/// </summary>
/// <typeparam name="T">The type that will be used as the indexer.</typeparam>
public class PerformanceTesting<T>
{
/// <summary>
/// Provides a model that contains timer information.
/// </summary>
private class TimerModel
{
/// <summary>
/// Used to record performance timings.
/// </summary>
public readonly Stopwatch Timer;
/// <summary>
/// Used to record how many times the <see cref="Timer"/> has been started.
/// </summary>
public int Count;
/// <summary>
/// Used to store the enabled state.
/// </summary>
private bool enabled;
/// <summary>
/// Gets or sets a value whether or not this timer if enabled.
/// </summary>
/// <remarks>If <see cref="Timer"/> has been started and Enabled is set to false the timer will be stopped.</remarks>
public bool Enabled
{
get
{
return this.enabled;
}
set
{
this.enabled = value;
// be sure to stop the timer if disabled
if (!value && this.Timer.IsRunning)
{
this.Timer.Stop();
}
}
}
/// <summary>
/// Default constructor.
/// </summary>
public TimerModel()
{
this.Timer = new Stopwatch();
this.enabled = true;
}
}
/// <summary>
/// Holds a reference to a singleton instance.
/// </summary>
private static PerformanceTesting<T> singleton;
/// <summary>
/// Used to store various timer information.
/// </summary>
private readonly Dictionary<T, TimerModel> timers;
/// <summary>
/// Default constructor.
/// </summary>
public PerformanceTesting()
{
this.timers = new Dictionary<T, TimerModel>();
}
/// <summary>
/// Creates a new timer.
/// </summary>
/// <param name="key">The unique key for the timer.</param>
/// <remarks>It is best to create the timer at the start of the application getting it ready for use.</remarks>
public void Create(T key)
{
this.timers.Add(key, new TimerModel());
}
/// <summary>
/// Creates a new timer for each key.
/// </summary>
/// <param name="keys">The unique keys for the timers.</param>
/// <remarks>It is best to create the timer at the start of the application getting it ready for use.</remarks>
public void Create(T[] keys)
{
foreach (var key in keys)
{
this.timers.Add(key, new TimerModel());
}
}
/// <summary>
/// Returns the total ticks that this timer has observed.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>Returns a time value in ticks.</returns>
public long TotalTicks(T key)
{
var model = this.timers[key];
return model.Timer.ElapsedTicks;
}
/// <summary>
/// Returns the total ticks that this timer has observed.
/// </summary>
/// <param name="keys">The keys to the timers information.</param>
/// <returns>Returns the sum of the time values in ticks.</returns>
public long TotalTicks(T[] keys)
{
long total = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Timer.ElapsedTicks;
}
return total;
}
/// <summary>
/// Gets the start count.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>The number of times the timer has started.</returns>
public int GetStartCount(T key)
{
var model = this.timers[key];
return model.Count;
}
/// <summary>
/// Gets the start count for specified timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <returns>The sum total of times all specified the timers have started.</returns>
public int GetStartCount(T[] keys)
{
int total = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Count;
}
return total;
}
/// <summary>
/// Returns the total ticks that this timer has observed.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>Returns a time value in milliseconds.</returns>
public long TotalMilliseconds(T key)
{
var model = this.timers[key];
return model.Timer.ElapsedMilliseconds;
}
/// <summary>
/// Returns the total ticks that this timer has observed.
/// </summary>
/// <param name="keys">The keys to the timers information.</param>
/// <returns>Returns the sum of the time values in milliseconds.</returns>
public long TotalMilliseconds(T[] keys)
{
long total = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Timer.ElapsedMilliseconds;
}
return total;
}
/// <summary>
/// Calculates the average time in ticks that elapsed while this timer was recording.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>Returns the average time in ticks that elapsed between each start and stop.</returns>
public long AverageTicks(T key)
{
var model = this.timers[key];
return model.Timer.ElapsedTicks / model.Count;
}
/// <summary>
/// Calculates the total average time in ticks that elapsed while the specified timers were recording.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <returns>Returns the total average time in ticks that elapsed between each start and stop for all the specified timers.</returns>
public long AverageTicks(T[] keys)
{
long total = 0;
var count = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Timer.ElapsedTicks;
count += model.Count;
}
return total / count;
}
/// <summary>
/// Calculates the average time in milliseconds that elapsed while this timer was recording.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>Returns the average time in milliseconds that elapsed between each start and stop.</returns>
public long AverageMilliseconds(T key)
{
var model = this.timers[key];
if (model.Count == 0)
{
return 0;
}
return model.Timer.ElapsedMilliseconds / model.Count;
}
/// <summary>
/// Calculates the total average time in milliseconds that elapsed while the specified timers were recording.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <returns>Returns the total average time in milliseconds that elapsed between each start and stop for all the specified timers.</returns>
public long AverageMilliseconds(T[] keys)
{
long total = 0;
var count = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Timer.ElapsedMilliseconds;
count += model.Count;
}
if (count == 0)
{
return 0;
}
return total / count;
}
/// <summary>
/// Removes the specified timers.
/// </summary>
/// <param name="keys">The keys to the timers that will be removed.</param>
public void Remove(T[] keys)
{
foreach (var key in keys)
{
this.timers.Remove(key);
}
}
/// <summary>
/// Removes a timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public void Remove(T key)
{
this.timers.Remove(key);
}
/// <summary>
/// Resets all the timers.
/// </summary>
public void ResetAll()
{
foreach (var pair in this.timers)
{
pair.Value.Timer.Reset();
}
}
/// <summary>
/// Resets all the timers.
/// </summary>
/// <param name="resetCounts">If true will set each timer start count to 0.</param>
public void ResetAll(bool resetCounts)
{
foreach (var pair in this.timers)
{
pair.Value.Timer.Reset();
if (resetCounts)
{
pair.Value.Count = 0;
}
}
}
/// <summary>
/// Gets an array of timer keys.
/// </summary>
/// <returns>Returns an array of timer keys.</returns>
public T[] GetKeys()
{
var keys = new T[this.timers.Count];
this.timers.Keys.CopyTo(keys, 0);
return keys;
}
/// <summary>
/// Sets the enabled state of the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <param name="enabled">If true the timer will be enabled. If false the timer will be stopped if it is running.</param>
public void SetEnabled(T key, bool enabled)
{
var model = this.timers[key];
model.Enabled = enabled;
}
/// <summary>
/// Sets the enabled state of the specified timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <param name="enabled">If true the timers will be enabled. If false the timers will be stopped if they are running.</param>
public void SetEnabled(T[] keys, bool enabled)
{
foreach (var key in keys)
{
var model = this.timers[key];
model.Enabled = enabled;
}
}
/// <summary>
/// Gets the enabled state of the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public bool IsEnabled(T key)
{
var model = this.timers[key];
return model.Enabled;
}
/// <summary>
/// Gets the enabled state of the specified timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <param name="enabled">Will contain the enabled state for each specified key.</param>
public void IsEnabled(T[] keys, out bool[] enabled)
{
var enabledStates = new bool[keys.Length];
for (int i = 0; i < keys.Length; i++)
{
var model = this.timers[keys[i]];
enabledStates[i] = model.Enabled;
}
enabled = enabledStates;
}
/// <summary>
/// Starts the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <remarks>Will not start if the enabled state is false.</remarks>
public void Start(T key)
{
var model = this.timers[key];
if (!model.Enabled)
{
return;
}
model.Count++;
model.Timer.Start();
}
/// <summary>
/// Starts the timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <remarks>Will not start if the timers enabled state is false.</remarks>
public void Start(T[] keys)
{
foreach (var key in keys)
{
var model = this.timers[key];
if (!model.Enabled)
{
continue;
}
model.Count++;
model.Timer.Start();
}
}
/// <summary>
/// Stops the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public void Stop(T key)
{
var model = this.timers[key];
if (!model.Enabled)
{
return;
}
model.Timer.Stop();
}
/// <summary>
/// Stops the timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
public void Stop(T[] keys)
{
foreach (var key in keys)
{
var model = this.timers[key];
if (!model.Enabled)
{
continue;
}
model.Timer.Stop();
}
}
/// <summary>
/// Resets the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public void Reset(T key)
{
this.Reset(key, false);
}
/// <summary>
/// Resets the timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
public void Reset(T[] keys)
{
this.Reset(keys, false);
}
/// <summary>
/// Resets the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <param name="resetCount">If true the start count for the timer will be set to 0.</param>
public void Reset(T key, bool resetCount)
{
var model = this.timers[key];
model.Timer.Reset();
if (resetCount)
{
model.Count = 0;
}
}
/// <summary>
/// Resets the timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <param name="resetCounts">If true the start count for the timers will be set to 0.</param>
public void Reset(T[] keys, bool resetCounts)
{
foreach (var key in keys)
{
var model = this.timers[key];
model.Timer.Reset();
if (resetCounts)
{
model.Count = 0;
}
}
}
/// <summary>
/// Resets the timer start count to 0.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public void ResetCount(T key)
{
var model = this.timers[key];
model.Count = 0;
}
/// <summary>
/// Resets each timer start count to 0.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
public void ResetCount(T[] keys)
{
foreach (var key in keys)
{
var model = this.timers[key];
model.Count = 0;
}
}
/// <summary>
/// Restarts the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <param name="resetCount">If true the start count for the timer will be set to 0.</param>
/// <remarks>The timer will be reset then started again.</remarks>
public void Restart(T key, bool resetCount)
{
var model = this.timers[key];
model.Timer.Reset();
if (resetCount)
{
model.Count = 0;
}
this.Start(key);
}
/// <summary>
/// Restarts the specified timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <param name="resetCounts">If true the start count for the timers will be set to 0.</param>
/// <remarks>Each timer will be reset then started again.</remarks>
public void Restart(T[] keys, bool resetCounts)
{
foreach (var key in keys)
{
var model = this.timers[key];
model.Timer.Reset();
if (resetCounts)
{
model.Count = 0;
}
}
this.Start(keys);
}
/// <summary>
/// Gets a singleton instance of the <see cref="PerformanceTesting{T}"/> class.
/// </summary>
public static PerformanceTesting<T> Instance
{
get
{
return singleton ?? (singleton = new PerformanceTesting<T>());
}
}
}
Setting up a performance counter
#if PERFORMANCE
var perf = PerformanceTesting<string>.Instance;
perf.Create("ScanLines");
#endif
A sample usage
#if PERFORMANCE
var perf = PerformanceTesting<string>.Instance;
perf.Reset("ScanLines");
perf.Start("ScanLines");
#endif
this.scanner.Calculate(this.points);
#if PERFORMANCE
perf.Stop("ScanLines");
#endif
How to report the results
#if PERFORMANCE
public static void ReportPerformanceTimes()
{
var perf = PerformanceTesting<string>.Instance;
foreach (var value in perf.GetKeys())
{
Debug.Log(string.Format("{0} - Total: {1}ms Average: {2} Count: {3}", value, perf.TotalMilliseconds(value), perf.AverageMilliseconds(value), perf.GetStartCount(value)));
}
Debug.Log(string.Format("Total Performance Times - Total: {0}ms", perf.TotalMilliseconds("ScanLines")));
}
#endif
67b32830-abeb-4028-a84c-0f87c797909b|0|.0
Some .net/mono frameworks do not support the IsNullOrWhiteSpace method. The code below provides a simple replacement. /// <summary>
/// Indicates whether a specified string is null, empty, or consists only of white-space characters.
/// </summary>
/// <param name="value">value: The string to test.</param>
/// <returns>true if the value parameter is null or System.String.Empty, or if value consists exclusively of white-space characters.</returns>
public static bool IsNullOrWhiteSpace(this string value)
{
if (value == null)
{
return true;
}
var index = 0;
while (index < value.Length)
{
if (char.IsWhiteSpace(value[index]))
{
index++;
}
else
{
return false;
}
}
return true;
}
232f867b-1708-435c-b8c6-e46cae4b37e3|1|5.0
Some .net/mono frameworks do not support the 3 argument GetDirectories method. The code below provides a simple replacement. /// <summary>
/// Builds an array of folders & sub folders.
/// </summary>
/// <param name="path">The path to search.</param>
/// <param name="pattern">The search string to match against the names of files in path. The parameter cannot end in two periods
/// ("..") or contain two periods ("..") followed by System.IO.Path.DirectorySeparatorChar or System.IO.Path.AltDirectorySeparatorChar,
/// nor can it contain any of the characters in System.IO.Path.InvalidPathChars.
///</param>
/// <param name="searchOptions">One of the System.IO.SearchOption values that specifies whether the search operation should include
/// all subdirectories or only the current directory.
///</param>
/// <returns>A String array of directories that match the search pattern.</returns>
public static string[] GetDirectories(string path, string pattern, SearchOption searchOptions)
{
// check if searching for all directories
if (searchOptions == SearchOption.AllDirectories)
{
// add start paths to list
var list = Directory.GetDirectories(path, pattern);
var index = 0;
var count = list.Length;
// process list and add folders to end of list
while (index < count)
{
var directories = Directory.GetDirectories(list[index++], pattern);
if (directories.Length > 0)
{
// check if we need more space to store the directories
if (count + directories.Length > list.Length - 1)
{
Array.Resize(ref list, list.Length + directories.Length + 1000);
}
// add directories to end of the list
foreach (var directory in directories)
{
list[count++] = directory;
}
}
// trim unused index from end of the array
if (list.Length > count)
{
Array.Resize(ref list, count);
}
}
return list;
}
// just return initial list of folder with no sub folders
return Directory.GetDirectories(path, pattern);
}
8c908bd4-0488-4e96-bd3d-1f3d057e612b|0|.0
/// <summary>
/// Provides a game object that automatically self terminates.
/// </summary>
[ExecuteInEditMode]
public class SelfTerminatingObject : MonoBehaviour
{
/// <summary>
/// Holds a reference to a callback that will be called just before termination.
/// </summary>
public Action Callback;
/// <summary>
/// Holds the time delay in seconds before object self terminates.
/// </summary>
public float Delay;
/// <summary>
/// Holds a time value used to determine whether it's time to self terminate.
/// </summary>
private DateTime lastTime;
/// <summary>
/// Called by Unity to update the object.
/// </summary>
public void Update()
{
this.PerformCheck();
}
/// <summary>
/// Called by Unity to draw the object's GUI.
/// </summary>
public void OnGui()
{
this.PerformCheck();
}
/// <summary>
/// Determines whether it's time to terminate.
/// </summary>
private void PerformCheck()
{
// check if specified time span has elapsed
if (DateTime.Now > this.lastTime + TimeSpan.FromSeconds(this.Delay))
{
// run callback is specified
if (this.Callback != null)
{
this.Callback();
}
// destroy object
#if UNITY_EDITOR
DestroyImmediate(this.gameObject, true);
#else
Destroy(this.gameObject);
#endif
}
}
/// <summary>
/// Creates a self terminating game object.
/// </summary>
/// <param name="callback">The method to be called before the object terminates.</param>
/// <returns>Returns a reference to the game object that will self terminate.</returns>
public static GameObject CreateUpdateCallback(Action callback)
{
return CreateUpdateCallback(callback, 0);
}
/// <summary>
/// Creates a self terminating game object.
/// </summary>
/// <param name="callback">The method to be called before the object terminates.</param>
/// <param name="delay">Specifies a delay value in seconds before the object will self terminate.</param>
/// <returns>Returns a reference to the game object that will self terminate.</returns>
public static GameObject CreateUpdateCallback(Action callback, float delay)
{
var obj = new GameObject();
var com = obj.AddComponent<SelfTerminatingObject>();
com.lastTime = DateTime.Now;
com.Delay = delay;
com.Callback = callback;
return obj;
}
}
fac90666-3035-4d9e-8e38-b3533a7b83bb|0|.0
This code is designed to hook into unity’s EditorApplication.update delegate. IRun.cs namespace CBX.CoreProjectCode.Interfaces
{
using CBX.CoreProjectCode.Models;
/// <summary>
/// Provides a interface for running a <see cref="CallbackModel{T}"/> type.
/// </summary>
public interface IRun
{
/// <summary>
/// Runs the <see cref="CallbackModel{T}"/> type.
/// </summary>
void Run();
}
}
CallbackModel.cs
namespace CBX.CoreProjectCode.Models
{
using System;
using CBX.CoreProjectCode.Interfaces;
/// <summary>
/// Provides a modal for callbacks.
/// </summary>
/// <typeparam name="T">The generic type used to represent the data type.</typeparam>
public class CallbackModel<T> : IRun
{
/// <summary>
/// A reference to a callback method.
/// </summary>
public Action<T> Callback;
/// <summary>
/// A reference to some data that will be passed to the callback method.
/// </summary>
public T Data;
/// <summary>
/// Implements <see cref="IRun.Run"/> to run the callback.
/// </summary>
public void Run()
{
this.Callback(this.Data);
}
}
}
EditorCallbackService.cs
namespace CBX.CoreProjectCode.Services
{
using System;
using System.Collections.Generic;
using CBX.CoreProjectCode.Interfaces;
using CBX.CoreProjectCode.Models;
/// <summary>
/// The editor callback service.
/// </summary>
public class EditorCallbackService
{
/// <summary>
/// Holds a singleton instance of the <see cref="EditorCallbackService"/> type.
/// </summary>
private static EditorCallbackService service;
/// <summary>
/// Holds a list of <see cref="CallbackModel{T}"/> types that implement <see cref="IRun"/>.
/// </summary>
private readonly Stack<IRun> callbacks;
/// <summary>
/// Initializes a new instance of the <see cref="EditorCallbackService"/> class.
/// </summary>
public EditorCallbackService()
{
this.callbacks = new Stack<IRun>();
}
/// <summary>
/// Returns a singleton instance of the <see cref="EditorCallbackService"/> type.
/// </summary>
public static EditorCallbackService Instance
{
get
{
// if no service yet exists create one
return service ?? (service = new EditorCallbackService());
}
}
/// <summary>
/// Runs any callbacks that have been registered.
/// </summary>
public void Run()
{
while (this.callbacks.Count > 0)
{
var cb = this.callbacks.Pop();
cb.Run();
}
}
/// <summary>
/// Registers a <see cref="Action{T}"/> callback.
/// </summary>
/// <typeparam name="T">The type of data that the <see cref="callback"/> takes as a parameter.</typeparam>
/// <param name="callback">A reference to a callback.</param>
public void Register<T>(Action<T> callback)
{
this.Register(callback, default(T));
}
/// <summary>
/// Registers a <see cref="Action{T}"/> callback.
/// </summary>
/// <typeparam name="T">
/// The type of data that the <see cref="callback"/> takes as a parameter.
/// </typeparam>
/// <param name="callback">
/// A reference to a callback.
/// </param>
/// <param name="data">
/// The data that will be passed as a parameter when the <see cref="callback"/> is invoked.
/// </param>
public void Register<T>(Action<T> callback, T data)
{
if (callback == null)
{
throw new ArgumentNullException("callback");
}
var modal = new CallbackModel<T> { Callback = callback, Data = data };
this.callbacks.Push(modal);
}
/// <summary>
/// Registers a <see cref="Action"/> callback.
/// </summary>
/// <param name="callback">A reference to a callback.</param>
public void Register(Action callback)
{
this.Register<object>(x => callback(), null);
}
}
}
Usage scenario …
[InitializeOnLoad]
public class EditorInitialization
{
/// <summary>
/// Holds a value indicating whether the RunCallbacks method has been called at least once before.
/// </summary>
private static bool ranOnce;
/// <summary>
/// Initializes static members of the <see cref="EditorInitialization"/> class.
/// </summary>
static EditorInitialization()
{
EditorApplication.update += RunCallbacks;
}
private static void RunCallbacks()
{
if (!ranOnce)
{
// setup the settings system
SetupSettings();
// load localization strings
LoadLocalizationData();
ranOnce = true;
return;
}
// invoke callbacks from editor callback service
EditorCallbackService.Instance.Run();
}
}
c10ab460-a05d-4911-8056-432495226416|0|.0
Source –> https://gist.github.com/chkn/4748252
using System;
using System.Linq;
public static class JSON
{
public static string Stringify (object obj)
{
string str;
if (obj == null) return "null";
if (obj is ValueType) return obj.ToString ().ToLowerInvariant ();
if ((str = obj as string) != null) return System.Text.RegularExpressions.Regex.Escape (str);
// assume it's a POCO
return "{" + string.Join (",",
from p in obj.GetType ().GetProperties ()
let json = (JSONAttribute) p.GetCustomAttributes (typeof (JSONAttribute), true).FirstOrDefault ()
where json != null
select "\"" + (json.Key ?? p.Name) + "\":" + Stringify (p.GetValue (obj, null))
) + "}";
}
}
public class JSONAttribute : Attribute
{
public string Key { get; set; }
public JSONAttribute () {}
public JSONAttribute (string key) { Key = key; }
}
481a00a4-49ee-4b07-a9ed-bc17792e0620|0|.0
/// <summary>
/// Determines if this rectangle intersects with rect.
/// </summary>
/// <param name="rect">
/// The rectangle to test.
/// </param>
/// <returns>
/// This method returns true if there is any intersection, otherwise false.
/// </returns>
public bool Intersects(RectangleF rect)
{
return !((this.X > rect.Right) || (this.Right < rect.Left) || (this.Y > rect.Bottom) || (this.Bottom < rect.Top));
}
/// <summary>
/// Replaces this RectangleF with the intersection of itself and the specified RectangleF.
/// </summary>
/// <param name="rect">
/// The RectangleF with which to intersect.
/// </param>
public void Intersect(RectangleF rect)
{
this.X = Math.Max(this.Left, rect.Left);
this.Y = Math.Max(this.Top, rect.Top);
this.Width = Math.Min(this.Right, rect.Right) - this.X;
this.Height = Math.Min(this.Bottom, rect.Bottom) - this.Y;
}
/// <summary>
/// Returns a third RectangleF structure that represents the intersection of two other RectangleF structures.
/// If there is no intersection, an empty RectangleF is returned.
/// </summary>
/// <param name="a">
/// A rectangle to intersect.
/// </param>
/// <param name="b">
/// B rectangle to intersect.
/// </param>
/// <returns>
/// A RectangleF that represents the intersection of a and b.
/// </returns>
public static RectangleF Intersect(RectangleF a, RectangleF b)
{
float x = Math.Max((sbyte)a.X, (sbyte)b.X);
float num2 = Math.Min(a.X + a.Width, b.X + b.Width);
float y = Math.Max((sbyte)a.Y, (sbyte)b.Y);
float num4 = Math.Min(a.Y + a.Height, b.Y + b.Height);
if ((num2 >= x) && (num4 >= y))
{
return new RectangleF(x, y, num2 - x, num4 - y);
}
return Empty;
}
05946fd4-7017-4962-94da-f20f0e53ca87|0|.0
/// <summary>
/// Blends two colors together.
/// </summary>
/// <param name="color">
/// The source color.
/// </param>
/// <param name="src">
/// The blend color.
/// </param>
/// <returns>
/// Returns the result as a <see cref="Color"/> type.
/// </returns>
/// <remarks>
/// From Wikipedia https://en.wikipedia.org/wiki/Alpha_compositing -> "Alpha blending"
/// </remarks>
public static Color Blend(this Color color, Color src)
{
float sr = src.R / 255f;
float sg = src.G / 255f;
float sb = src.B / 255f;
float sa = src.A / 255f;
float dr = color.R / 255f;
float dg = color.G / 255f;
float db = color.B / 255f;
float da = color.A / 255f;
float oa = sa + (da * (1 - sa));
float r = ((sr * sa) + ((dr * da) * (1 - sa))) / oa;
float g = ((sg * sa) + ((dg * da) * (1 - sa))) / oa;
float b = ((sb * sa) + ((db * da) * (1 - sa))) / oa;
float a = oa;
return new Color((byte)(r * 255), (byte)(g * 255), (byte)(b * 255), (byte)(a * 255));
}
9bbf3709-4044-433c-a98f-3f1cf8767be4|0|.0
|
|