I’ve been using this script for a while now to debug timing and interaction issues between lots of crossfaded animations in my main scene, so I thought I’d share it here. IIRC, I made this because I saw something similar at an animation talk during Unite 09, and I’m not certain that it was ever released.
What this does is allow you to closely monitor animations that are playing, what their wrapmode is, what time they are at, and what the animation length is at. All you need to do is add your animated gameobjects to its internal array.
It presents this in a skinnable UnityGUI box, and the other handy thing it has is a draggable “Timescale” slider that lets you change the timescale dynamically in order to easily examine animations very closely.
It’s been extremely handy in tracking down weird interactions due to animations triggering unintentionally, small animation “blips”, reviewing animations in slow-mo with a 3d artist, etc.
Here are a couple screenshots to give an example of what this looks like both without a skin assigned and with a skin:
To use it, add this code to a Unityscript file named DebugAnimations.js:
var debugObjects : GameObject[];
var debugObjectNames : String[];
var boxRect : Rect = Rect(20, 20, 250, 250);
var labelRect : Rect = Rect(20, 280, 50, 30);
var sliderRect : Rect = Rect(70, 280, 120, 15);
var enable : boolean = true;
private var stateRef : AnimationState;
private var clipRef : AnimationClip;
private var debugText : String;
var myGUISkin : GUISkin;
function OnGUI () {
if (enable) {
GUI.skin = myGUISkin;
var lengthVal : float;
var timeVal : float;
var speedVal : float;
var nameVal : String;
var wrapModeVal : WrapMode;
debugText = "";
for (var i : int = 0; i < debugObjects.length; i++) {
if (debugObjectNames.length > i debugObjectNames[i]) {
debugText += debugObjectNames[i] + ":\n";
} else {
// Reinitialize text
debugText += "Object " + i + ":\n";
}
// Fetch animations
for (stateRef in debugObjects[i].animation) {
if (debugObjects[i].animation.IsPlaying((stateRef as AnimationState).name)) {
// Construct string
debugText += GetTextDesc(stateRef) + "\n";
}
}
}
GUI.Box(boxRect, debugText);
GUI.Label(labelRect, "Timescale");
Time.timeScale = GUI.HorizontalSlider(sliderRect, Time.timeScale, 0.0, 1.0);
}
}
function GetTextDesc(st : AnimationState) {
if (enable) {
clipRef = st.clip;
lengthVal = st.length;
timeVal = st.time;
nameVal = st.name;
wrapModeVal = st.wrapMode;
speedVal = st.speed;
// Allocation
return String.Format("{0}: {1} {2:0.00}/{3:0.00} {4}", nameVal, wrapModeVal, timeVal, lengthVal, speedVal);
}
}
Create an empty gameobject, name it something like DebugAnimations, and add this script component to it. Go to the Inspector for it, and populate the Debug Objects array with objects that have an animation component (for example, the root node of imported FBX files). If you add anything that has no animation component, it might throw an error. You can also optionally populate the Debug Object Names array with names that come in the same order as your objects, for clarity’s sake.
You may have to adjust the OnGUI code if you want to monitor a lot of objects, because it probably won’t handle content overflow very well. If you just want to debug a couple of animated characters, this script comes in pretty handy as-is. Also, if you have other scripts that modify the Time.timeScale, it will override whatever you’ve selected in your slider, so be aware of that.
Once it’s in your scene, you can enable or disable the entire gameobject (not just the enable flag) to avoid the OnGUI overhead. I keep it around and enable it whenever I have animation glitches. I use this in Unity iPhone 1.5.1 at the moment, and haven’t tested it in anything else. Feel free to try it on other Unity versions and post your results!