Optimising coroutine yielding in C#
When needing to yield a coroutine for a single frame in C#, most people – including myself usually go about it this way:
{
while (m_Alpha < 1.0f)
{
m_Alpha += Time.deltaTime;
yield return 0;
}
m_Alpha = 1.0f;
}
However, as Rodrigo recently brought to my attention, this approach ofcourse performs unneeded memory allocation, given that the zero needs boxing and unboxing before its passed to the coroutine system. Using null in stead saves you that work and allocation.
This might not seem like a lot at first glance, but if you make this a habit every time you need to yield for a frame, I guarantee you that you’ll see results in larger scenarios.
The more optimal way of yielding for a single frame in C#. Minor difference, but allocation saved – which is always awesome:
{
while (m_Alpha < 1.0f)
{
m_Alpha += Time.deltaTime;
yield return null;
}
m_Alpha = 1.0f;
}
An interesting test could be to, on a larger co-routine heavy project, do a project-wide find and replace on “yield return 0;” and “yield return null;” back and forth and measuring the performance difference with the profiler (for non-pro users, maybe the performance gain is even measurable using external monitoring tools).
Downloading the hydra
So I’ve seen some people asking how you would go about downloading executable code from an external location, reading it into memory and executing it in ones running application.
Now some readers might go "eh? why the heck would someone want to do that?". Well first off, its cool™, but seeing as that is rarely an argument which convinces decision makers, here’s a few others:
- Patching. The ability to modify the behaviour of your downloaded executable after distribution, without requiring re-download.
- Highly dynamic online content. Say you’re building a virtual world or something. You might want to have the ability to add more complex behaviours to downloaded content – more than what a data-driven approach allows for.
- Or how about expanding the capabilities of user generated content?
There. Those are my alibis and I’m sticking to them.
Now this example is quick and simple so as to not bloat the post too much. Regardless of your use, you’ll likely be wanting to add in for instance some cache functionality for real-world use.
Right. So this example contains three pieces of eight, uh, code:
- The loader utility – responsible for downloading and making available the remote code.
- The assembly – you know, the one we’re downloading.
- An example handler. For easy re-use, I’ve designed this example to allow for easy re-use of the loader utility by externalising handling of the assemblies via messages. This example handler shows some techniques for accessing the data of loaded assemblies.
Using the example:
- Download and save /Assets/WWWAssemblyLoader.cs, /Assets/NewBehaviourScript.cs and /MyAssembly.cs.
- Download and install the mono runtime (or the .net equivalent on Windnows – not tested, but should work just fine).
- Build the assembly from the terminal – using the build command supplied at the end of this post.
- Upload the assembly to some host (save the URL for later).
- Open up your Unity project.
- Add the WWWAssemblyLoader and NewBehaviourScript scripts to a GameObject and set the URL property of the first to that of your uploaded assembly.
- Press play.
- Profit!
And now the codes!
/Assets/WWWAssemblyLoader.cs
public class WWWAssemblyLoader : MonoBehaviour
{
public string m_AssemblyURL;
private string m_ErrorString = "";
private WWW m_WWW;
private bool m_Complete = true;
{
if (m_AssemblyURL != "")
{
ReloadAssembly (m_AssemblyURL);
}
}
public string AssemblyURL
{
get
{
return m_AssemblyURL;
}
set
{
if (m_AssemblyURL != value)
{
ReloadAssembly (value);
}
}
}
public float Progress
{
get
{
return m_Complete ? 1.0f : m_WWW.progress;
}
}
public string Error
{
get
{
return m_ErrorString;
}
}
{
m_Complete = false;
m_ErrorString = "";
m_AssemblyURL = url;
m_WWW = new WWW (m_AssemblyURL);
}
{
if (!m_Complete)
{
if (m_WWW.error != null)
{
m_ErrorString = m_WWW.error;
m_Complete = true;
SendMessage ("OnAssemblyLoadFailed", m_AssemblyURL);
}
else if (m_WWW.isDone)
{
Assembly assembly = LoadAssembly ();
m_Complete = true;
if (assembly != null)
{
Debug.Log ("Done");
SendMessage ("OnAssemblyLoaded", new WWWAssembly (m_AssemblyURL, assembly));
}
else
{
Debug.Log ("Failed");
SendMessage ("OnAssemblyLoadFailed", m_AssemblyURL);
}
}
}
}
{
try
{
return Assembly.Load (m_WWW.bytes);
}
catch (System.Exception e)
{
m_ErrorString = e.ToString ();
return null;
}
}
}
public class WWWAssembly
{
private string m_URL;
private Assembly m_Assembly;
public string URL
{
get
{
return m_URL;
}
}
public Assembly Assembly
{
get
{
return m_Assembly;
}
}
{
m_URL = url;
m_Assembly = assembly;
}
}
/Assets/NewBehaviourScript.cs
public class NewBehaviourScript : MonoBehaviour
{
private string m_MessageString = "Waiting for assembly";
{
m_MessageString = "Assembly " + loadedAssembly.URL + "\n";
System.Type type = loadedAssembly.Assembly.GetType ("MyClass");
FieldInfo field = type.GetField ("myString");
m_MessageString += (field.GetValue (null) as string) + "\n";
object instance = loadedAssembly.Assembly.CreateInstance ("MyClass");
MethodInfo method = type.GetMethod ("LogMyString");
m_MessageString += "Return value: " + method.Invoke (instance, null).ToString ();
}
{
m_MessageString = "Failed to load assembly at " + url;
}
{
GUILayout.BeginArea (new Rect (0.0f, 0.0f, Screen.width, Screen.height));
GUILayout.FlexibleSpace ();
GUILayout.BeginHorizontal ();
GUILayout.FlexibleSpace ();
GUILayout.Box (m_MessageString);
GUILayout.FlexibleSpace ();
GUILayout.EndHorizontal ();
GUILayout.FlexibleSpace ();
GUILayout.EndArea ();
}
}
/MyAssembly.cs
public class MyClass
{
public static string myString = "This is my string from my class in my assembly";
{
Debug.Log (myString);
return 2 + 2;
}
}
The assembly compile terminal command
mcs -target:library -out:MyAssembly.dll -r:/Applications/Unity/Unity.app/Contents/Frameworks/UnityEngine.dll MyAssembly.cs
New license of Path: GPL
Since I started at Unity, I haven’t really had the time to do much updating (read: none) of my private projects. In sheer size, Path is the largest of those, so a while ago I realised that maintaining that project is simply not feasible.
By adding the GPL license option to the existing two license options (the show-my-logo license displayed on download from angryant.com and the option for a custom negotiated one), users are able to test and modify the source of Path directly – before deciding on one of the other licenses.
Also, although very messy (yes – very), the source could also serve as a good learning resource for Unity editor scripting.
The project repository is available on github.
CopyInspector
Yea I know. It’s been a while. I do have two very good excuses though: 2.6 and Unite ’09. If you enjoyed those then zip it and read on. If not, I’m really out of ammo and sorry for the delay.
At Unite, I attended the talk by John Grden of infrared5 on the special (free) Unity for flash users day. During this session he complained about wanting to be able to copy his runtime transform changes inside the IDE (he was copying by way of paper notes it seemed). I decided to take up the challenge when he continued with “… but someone is probably going to show me how to do that after this” and after his talk I handed him a custom inspector editor script for solving that specific problem.
Later at the conference I had some time to kill and did a rewrite to expand the script to be general for any component type. I didn’t have the time to hand John that version, but I suppose I’ll just email him a link to this post.
- So anyway – lets talk implementation:
- Add CopyInspector.cs to Assets/Editor.
- Add CopyTransformInspector.cs to Assets/Editor.
- For each other component to be made copy/paste-able:
- Add CopyYourComponentTypeInspector.cs to Assets/Editor.
- Rename it appropriately.
- Rename the class to match the file name.
- Change YourComponentType in “[CustomEditor (typeof (YourComponentType))]” to the type of component you wish to affect.
You’ll notice that CopyTransformInspector has some additional code to it. This is due to the fact that this inspector is rendered non-standard and the code provided just replicates that.

The copy transform inspector
Not really sure why syntax highlighting is not kicking in… Will have a look at that later.
Codes!
CopyInspector.cs
public class CopyInspector : Editor
{
static System.Type m_OriginalType;
static Dictionary <PropertyInfo, object> m_Values;
private List <PropertyInfo> GetProperties (Component component)
{
List <string> ignoredProperties;
List <PropertyInfo> properties;
properties = new List <PropertyInfo> ();
ignoredProperties = new List <string> ();
foreach (PropertyInfo propertyInfo in typeof (Component).GetProperties ())
{
ignoredProperties.Add (propertyInfo.Name);
}
foreach (PropertyInfo propertyInfo in component.GetType ().GetProperties ())
{
if (ignoredProperties.Contains (propertyInfo.Name))
{
continue;
}
properties.Add (propertyInfo);
}
return properties;
}
{
DrawDefaultInspector ();
OnCopyInspectorGUI ();
}
{
bool enabled;
List <PropertyInfo> properties;
Component component;
component = target as Component;
if (component == null)
{
return;
}
GUILayout.Space (10.0f);
Color backgroundColor = GUI.backgroundColor;
GUI.backgroundColor = new Color (0.8f, 0.8f, 0.8f);
GUILayout.BeginVertical ("Toolbar");
GUI.backgroundColor = backgroundColor;
GUILayout.BeginHorizontal ();
GUILayout.Space (10.0f);
GUILayout.Label ("Copied: " + (m_OriginalType != null ? m_OriginalType.Name : "Nothing"), "MiniLabel");
GUILayout.FlexibleSpace ();
if (GUILayout.Button (new GUIContent ("Copy", "Copy component values"), "MiniLabel"))
{
m_OriginalType = target.GetType ();
properties = GetProperties (component);
m_Values = new Dictionary <PropertyInfo, object> ();
foreach (PropertyInfo property in properties)
{
m_Values [property] = property.GetValue (component, null);
}
}
enabled = GUI.enabled;
GUI.enabled = target.GetType () == m_OriginalType;
GUILayout.Space (10.0f);
if (GUILayout.Button (new GUIContent ("Paste", "Paste component values"), "MiniLabel"))
{
properties = GetProperties (component);
foreach (PropertyInfo property in properties)
{
if (!property.CanWrite)
{
continue;
}
property.SetValue (component, m_Values [property], null);
}
}
GUILayout.Space (10.0f);
GUI.enabled = enabled;
GUILayout.EndHorizontal ();
GUILayout.EndVertical ();
GUILayout.Space (-2.0f);
}
}
CopyTransformInspector.cs
[CustomEditor (typeof (Transform))]
public class CopyTransformInspector : CopyInspector
{
{
Transform transform;
Vector3 localPosition, localScale;
Quaternion localRotation;
transform = target as Transform;
localPosition = EditorGUILayout.Vector3Field ("Position", transform.localPosition);
localRotation = Quaternion.Euler (EditorGUILayout.Vector3Field ("Rotation", transform.localRotation.eulerAngles));
localScale = EditorGUILayout.Vector3Field ("Scale", transform.localScale);
if (GUI.changed)
{
transform.localPosition = localPosition;
transform.localRotation = localRotation;
transform.localScale = localScale;
}
OnCopyInspectorGUI ();
}
}
CopyYourComponentTypeInspector.cs
[CustomEditor (typeof (YourComponentType))]
public class CopyYourComponentTypeInspector : CopyInspector{}
Magnetic
You know how Little Big Planet, Kingdom Hearts and similar have various pickups move towards your character when you get up close? Yea I also find that’s a nice bit of polish.
One way of getting that up and running in Unity is via the code below. Setup:
- Add all objects you want to get attracted to the player to a special layer.
- Attach the script below to your player.
- Set the layer mask on the component to include the layer from step one.
- Tweak, play, repeat.
Magnetic.cs:
public class Magnetic : MonoBehaviour
{
public LayerMask m_MagneticLayers;
public Vector3 m_Position;
public float m_Radius;
public float m_Force;
{
Collider[] colliders;
Rigidbody rigidbody;
colliders = Physics.OverlapSphere (transform.position + m_Position, m_Radius, m_MagneticLayers);
foreach (Collider collider in colliders)
{
rigidbody = (Rigidbody) collider.gameObject.GetComponent (typeof (Rigidbody));
if (rigidbody == null)
{
continue;
}
rigidbody.AddExplosionForce (m_Force * -1, transform.position + m_Position, m_Radius);
}
}
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere (transform.position + m_Position, m_Radius);
}
}
GUI drag-drop
A lot of people have been asking for tips on how to implement drag-drop functionality in Unity GUI scripting, so I decided to put together a reusable script for the purpose.
Basically the solution requires that your data class derives from GUIDraggableObject and at some point in its OnGUI method call Drag( Rect ) – just like GUI.Window handles dragging.
Right. Codez. First off the GUIDraggableObject.cs file:
public class GUIDraggableObject
{
protected Vector2 m_Position;
private Vector2 m_DragStart;
private bool m_Dragging;
{
m_Position = position;
}
public bool Dragging
{
get
{
return m_Dragging;
}
}
public Vector2 Position
{
get
{
return m_Position;
}
set
{
m_Position = value;
}
}
{
if (Event.current.type == EventType.MouseUp)
{
m_Dragging = false;
}
else if (Event.current.type == EventType.MouseDown && draggingRect.Contains (Event.current.mousePosition))
{
m_Dragging = true;
m_DragStart = Event.current.mousePosition - m_Position;
Event.current.Use();
}
if (m_Dragging)
{
m_Position = Event.current.mousePosition - m_DragStart;
}
}
}
An example data class inheriting from GUIDraggableObject – DataObject.cs:
public class DataObject : GUIDraggableObject
// This class just has the capability of being dragged in GUI - it could be any type of generic data class
{
private string m_Name;
private int m_Value;
: base (position)
{
m_Name = name;
m_Value = value;
}
{
Rect drawRect = new Rect (m_Position.x, m_Position.y, 100.0f, 100.0f), dragRect;
GUILayout.BeginArea (drawRect, GUI.skin.GetStyle ("Box"));
GUILayout.Label (m_Name, GUI.skin.GetStyle ("Box"), GUILayout.ExpandWidth (true));
dragRect = GUILayoutUtility.GetLastRect ();
dragRect = new Rect (dragRect.x + m_Position.x, dragRect.y + m_Position.y, dragRect.width, dragRect.height);
if (Dragging)
{
GUILayout.Label ("Wooo...");
}
else if (GUILayout.Button ("Yes!"))
{
Debug.Log ("Yes. It is " + m_Value + "!");
}
GUILayout.EndArea ();
Drag (dragRect);
}
}
And finally, this script demonstrates how you could have your data manager class use Unity GUI for data visualisation with drag-drop enabled – MyMonoBehaviour.cs:
public class MyMonoBehaviour : MonoBehaviour
{
private List< DataObject > m_Data = new List< DataObject > ();
private Rect dropTargetRect = new Rect (10.0f, 10.0f, 30.0f, 30.0f);
{
m_Data.Add (new DataObject ("One", 1, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
m_Data.Add (new DataObject ("Two", 2, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
m_Data.Add (new DataObject ("Three", 3, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
m_Data.Add (new DataObject ("Four", 4, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
m_Data.Add (new DataObject ("Five", 5, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
}
{
DataObject toFront, dropDead;
Color color;
GUI.Box(dropTargetRect, "Die");
toFront = dropDead = null;
foreach (DataObject data in m_Data)
{
color = GUI.color;
if (data.Dragging)
{
GUI.color = dropTargetRect.Contains (Event.current.mousePosition) ? Color.red : color;
}
data.OnGUI ();
GUI.color = color;
if (data.Dragging)
{
if (m_Data.IndexOf (data) != m_Data.Count - 1)
{
toFront = data;
}
}
}
if (toFront != null)
// Move an object to front if needed
{
m_Data.Remove (toFront);
m_Data.Add (toFront);
}
}
}
Ah yea and an example of how you could do the same in an editor window – MyEditorWindow.cs:
public class MyEditorWindow : EditorWindow
{
private List< DataObject > m_Data = new List< DataObject > ();
private bool doRepaint = false;
private Rect dropTargetRect = new Rect (10.0f, 10.0f, 30.0f, 30.0f);
{
m_Data.Add (new DataObject ("One", 1, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
m_Data.Add (new DataObject ("Two", 2, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
m_Data.Add (new DataObject ("Three", 3, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
m_Data.Add (new DataObject ("Four", 4, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
m_Data.Add (new DataObject ("Five", 5, new Vector2 (20.0f * Random.Range (1.0f, 10.0f), 20.0f * Random.Range (1.0f, 10.0f))));
}
[MenuItem ("Window/MyEditorWindow")]
{
GetWindow (typeof (MyEditorWindow)).Show ();
}
{
if (doRepaint)
{
Repaint ();
}
}
{
DataObject toFront, dropDead;
bool previousState, flipRepaint;
Color color;
GUI.Box(dropTargetRect, "Die");
toFront = dropDead = null;
doRepaint = false;
flipRepaint = false;
foreach (DataObject data in m_Data)
{
previousState = data.Dragging;
color = GUI.color;
if (previousState)
{
GUI.color = dropTargetRect.Contains (Event.current.mousePosition) ? Color.red : color;
}
data.OnGUI ();
GUI.color = color;
if (data.Dragging)
{
doRepaint = true;
if (m_Data.IndexOf (data) != m_Data.Count - 1)
{
toFront = data;
}
}
else if (previousState)
{
flipRepaint = true;
if (dropTargetRect.Contains (Event.current.mousePosition))
{
dropDead = data;
}
}
}
if (toFront != null)
// Move an object to front if needed
{
m_Data.Remove (toFront);
m_Data.Add (toFront);
}
if (dropDead != null)
// Destroy an object if needed
{
m_Data.Remove (dropDead);
}
if (flipRepaint)
// If some object just stopped being dragged, we should repaing for the state change
{
Repaint ();
}
}
}
Logging an entire GameObject
More stuff from the shadowy corners of my hard-drive. Don’t remember the context, but someone needed to log every single piece of information available on a particular GameObject. I suppose this could be useful for end-user “This GameObject Just Went Completely FUBAR” ™ scenarios.
Anyway – it has reflection in it which by definition makes it cool.
Le codez:
public class Utilities
{
/* ... */
{
Component[] components = gameObject.GetComponents( typeof( Component ) );
FieldInfo[] fields;
PropertyInfo[] properties;
Debug.Log( gameObject.name + ":" );
foreach( Component component in components )
{
Debug.Log( " - " + component.GetType().Name + ":" );
fields = component.GetType().GetFields();
foreach( FieldInfo field in fields )
{
Debug.Log( " ." + field.Name + " = " + field.GetValue( component ) );
}
properties = component.GetType().GetProperties();
foreach( PropertyInfo property in properties )
{
Debug.Log( " ." + property.Name + " = " + property.GetGetMethod().Invoke( component, null ) );
}
}
if( children )
{
foreach( Transform transform in gameObject.transform )
{
Debug.Log( "->" );
LogGameObject( transform.gameObject, children );
}
}
}
{
LogGameObject( gameObject, false );
}
/* ... */
}
I bet you can’t type an A!
Keys got special meaning and shouldn’t be fed into parts of the GUI? This handy little snippet takes care of that job:
private string text = "I bet you can't type an A!";
{
if( !Event.current.isKey )
{
return;
}
foreach( KeyCode key in keys )
{
if( Event.current.keyCode == key )
{
Event.current.Use();
}
}
}
{
DisableKeys( new KeyCode[]{ key } );
}
{
DisableKey( KeyCode.A );
text = GUILayout.TextArea( text );
}
Where did that component go?
In larger Unity projects, components sometimes “get lost” – you refactor something and there’s an audio source still attached somewhere in your hierarchy and you simply cannot remember where.
You’re not the first one. A while ago I created a simple editor script to combat this issue as a response to a similar frustrated post on the Unity forums. Earlier this week I stumbled on the script again, picked it up and dusted it off a bit and decided to give it another chance to shine in some spotlight.
Use:
- Save the script as ComponentLister.cs.
- Place it in /Assets/Editor in your project.
- Launch the window from the Component menu – should be the last item titled “Component lister”.
- Click “Refresh” to list all components in your scene and the GameObjects to which they are attached.
- To investigate, click a GameObject name in the list and it will be set as the active selection in the hierarchy.
Codes:
public class ComponentLister : EditorWindow
{
private Hashtable sets = new Hashtable();
private Vector2 scrollPosition;
[ MenuItem( "Component/Component lister" ) ]
{
EditorWindow window = GetWindow( typeof( ComponentLister ) );
window.Show();
}
{
Object[] objects;
sets.Clear();
objects = FindObjectsOfType( typeof( Component ) );
foreach( Component component in objects )
{
if( !sets.ContainsKey( component.GetType() ) )
{
sets[ component.GetType() ] = new ArrayList();
}
( ( ArrayList )sets[ component.GetType() ] ).Add( component.gameObject );
}
}
{
GUILayout.BeginHorizontal( GUI.skin.GetStyle( "Box" ) );
GUILayout.Label( "Components in scene:" );
GUILayout.FlexibleSpace();
if( GUILayout.Button( "Refresh" ) )
{
UpdateList();
}
GUILayout.EndHorizontal();
scrollPosition = GUILayout.BeginScrollView(scrollPosition);
foreach( System.Type type in sets.Keys )
{
GUILayout.Label( type.Name + ":" );
foreach( GameObject gameObject in ( ArrayList )sets[ type ] )
{
if( GUILayout.Button( gameObject.name ) )
{
Selection.activeObject = gameObject;
}
}
}
GUILayout.EndScrollView();
}
}
UnitySteer
Ok so I’ve been quite busy lately and so I haven’t been updating the site as much as I should. In the beginning of July, UnitySteer was released. Ricardo Mendez of Arges Systems did the majority of the work and I did some early coding and design on the project.
UnitySteer is a collection of steering behaviours – enabling complex movement behaviour by combining the default behaviour set or creating new custom ones. The project is based on OpenSteerDotNet which is a .net port of OpenSteer. During the implementation of the Unity interface, however, a lot of the existing code base was either rewritten or discarded completely, so code based on the previous OpenSteer versions is not directly compatible.
For more information, check out Ricardo’s blog post and the library and examples repositories.
UnitySteer is open source, released under the MIT license.