Tuesday, June 19, 2018

INK now available on Switch!

We handled porting this fun and challenging platform game, where you splat invisible walls with ink to discover the level!  Plus we added cooperative play in the process, for pretty sweet couch multiplayer.  Check it out!




Tuesday, May 22, 2018

Unity3D Default Script Properties

I get the impression a lot of people aren't aware that Unity lets you set the default properties for any script file with serialized fields.  This means when you add that script as a component to a GameObject, those defaults will be applied upon creation.

This is something that doesn't matter that often, but in the right situation can be very useful.  For example, I just completed a task in which I needed to apply a component that plays appropriate selection/activation sounds for a button.  This component requires that I set an audio mixer channel, and fill in lists of which sounds to play.  Since the menu has dozens of button objects, many of which do not have a prefab, these assignments would need to be manually done dozens of times.

This is obviously a chore, and beyond that there's a lot of room to accidentally miss a couple of fields as I went through and did them all.  Using default properties, however, I could avoid those problems. I can simply select the script file, fill in the defaults for those fields, then whenever I added the component the standard sounds and channel were filled in automatically.

For reference, when selecting a script file look for a section at the top of the inspector panel, like so:


Friday, January 12, 2018

A Useful Feature of Unity's Debug.Log

This really isn't hidden, but somehow we've been using Unity for years without ever realizing.  Debug.Log (and related methods) actually have a second argument you can fill in.   Pass it an Object as a second argument, like so:

Debug.Log( "Some sort of problem!", myGameObject );

This will print to the Unity console as normal, but filling in the object means clicking on the log entry will take you to that object in the hierarchy.

Friday, October 13, 2017

What level does "Force Anisotropic" in Unity force it to?

Unity3D's quality settings have a drop-down for "Anisotropic Filtering", and one of those settings is "Forced On".  But what level of anisotropy does it force to?

Experimentation tells me that it forces to 8x.  If your texture is already set to use anisotropic filtering at a level above 8x, it will remain at that level rather than being downgraded.

This was tested with Unity 5.6.2p4.

Tuesday, October 3, 2017

Unity3D Matrix Layout

I had trouble finding a reference for this, so I wanted to post a table of the Unity matrix component layout.  The member names don't go the obvious direction for XY coordinates.

m00  m01  m02  m03
m10  m11  m12  m13
m20  m21  m22  m23
m30  m31  m32  m33

03, 13, 23 = Translation X, Y, Z
00, 11, 22 = Scale X, Y, Z

Tuesday, September 19, 2017

Unity3D Performance With InvokeRepeating()

The current project we're working on has a number of places where a Unity MonoBehavior's Update() function is basically just being used to keep a timer going, with every so often actual work happening.  I suggested moving stuff like this into a call to InvokeRepeating with an appropriate frequency, and generally met with some skepticism.  Research online led to the same sort of thing, with very few actual numbers and a few places where people treated it like a vampire treats sunlight.  "Reflection! Hissss!"

These kind of reactions sounded extreme to me, and "it's slower" doesn't tell you much, so I wanted to actually measure it.


I created an empty Unity project, and created a scene with 2100 static objects arranged in a grid.  Each object is a textureless sphere, and has one component called PerformanceTest.  The component is written in C#.  This component contains a start() method, and another method that does a few useless things just so it's not empty: Allocate a Vector3(), check its magnitude, multiply that result up and down a few times.  This method is either Update() or UpdateInvokeRepeating() depending on the test.  I also ran a test with no update method present at all, just an empty start() method.

When InvokeRepeating is used in this test, their timings and delays are all set the same, to make the difference as obvious as possible.  With 2100 of these in the scene it's pretty easy to see results in the Unity profiler.  These were tested on a Ryzen 1600 running at 3.3 GHz.

Nothing Startup: CoroutinesDelayedCalls 3.78ms, containing PerformanceTest.Start() 1.26ms
Update() Startup: CoroutinesDelayedCalls 3.78ms, containing PerformanceTest.Start() 1.26ms
InvokeRepeating() Startup: CoroutinesDelayedCalls 5.23ms, containing PerformanceTest.Start() 2.75ms

You can see here that upon startup, calling InvokeRepeating 2100 times cost approximately 1.5ms.  The other two startup methods were present, but totally empty.  Since the method name is provided as a string, this is the point where a search will have to happen, so this could potentially get slower if you have a lengthy class.

Nothing Update: BehaviorUpdate 0.0ms (of course)
Update() Update: BehaviorUpdate 2.34ms, containing PerformanceTest.Update() 0.92ms
InvokeRepeating() Update: CoroutinesDelayedCalls 3.44ms, containing PerformanceTest.UpdateInvokeRepeating () 0.94ms

Stacking all the InvokeRepeating calls does indeed lose to a straight Update, with the overhead appearing to be roughly 50% higher than Update has.  Notable is that CoroutinesDelayedCalls is not present in the list on frames where no invocations occur, and the Unity generic "Overhead" does not meaningfully change either.  There isn't an obvious ongoing performance penalty between invocations.

What this suggests to me is that unless your repeated invocation is more frequent than every other frame, you're probably getting a net win by using InvokeRepeating rather than Update() if possible.  While that may not be worth it if you need to have the overhead of Update() being present anyway, it doesn't have a dramatic startup cost and its additional overhead is easily overcome if your component doesn't need to update every frame.