public override void OnInspectorGUI() { SpritesheetGenerator ssg = (SpritesheetGenerator)target; GUI.changed = false; // Add the custom button EditorGUILayout.LabelField("Frames", EditorStyles.boldLabel); if (GUILayout.Button("Collect Frame Info")) { this.CollectFrameInfo(ssg); } if (GUI.changed) { EditorUtility.SetDirty(ssg); } // Draw the rest of the editor EditorGUILayout.Separator(); DrawDefaultInspector(); }
private void CollectFrameInfo(SpritesheetGenerator ssg) { // Find all the animation clips on the first prefab (we assume all the prefabs are the same) Animator animator = ssg.Prefabs[0].GetComponent <Animator>(); var clips = animator.runtimeAnimatorController.animationClips; // Setup the info we need to collect Dictionary <string, bool> processedClips = new Dictionary <string, bool>(); List <AnimationClip> allClips = new List <AnimationClip>(); List <int> allFrameStarts = new List <int>(); List <int> allFrameCounts = new List <int>(); List <float> allFrameTimes = new List <float>(); // Process each animation clip foreach (var c in clips) { // Only do each one once (since the animator state machine could use the same clip twice) if (processedClips.ContainsKey(c.name)) { continue; } processedClips.Add(c.name, true); // Add the initial frame List <float> times = new List <float>(); times.Add(0); // Create a new clip if we need to alter it (disabled for now) AnimationClip overrideClip = null; //if (c.isLooping) //{ // overrideClip = new AnimationClip(); // overrideClip.name = c.name; //} // Search through each binding and add it's keyframe time to one we want to record var floatBindings = AnimationUtility.GetCurveBindings(c); foreach (var b in floatBindings) { var curve = AnimationUtility.GetEditorCurve(c, b); foreach (var k in curve.keys) { if (!times.Contains(k.time)) { times.Add(k.time); } } if (overrideClip != null) { overrideClip.SetCurve(b.path, b.type, b.propertyName, curve); } } // Do the same for the other types of bindings var objectBindings = AnimationUtility.GetObjectReferenceCurveBindings(c); foreach (var b in objectBindings) { var curve = AnimationUtility.GetEditorCurve(c, b); foreach (var k in curve.keys) { if (!times.Contains(k.time)) { times.Add(k.time); } } if (overrideClip != null) { overrideClip.SetCurve(b.path, b.type, b.propertyName, curve); } } // Add a new curve so that we can render the last frame even though this clip loops if (overrideClip != null) { overrideClip.SetCurve("", typeof(Transform), "localPosition.z", AnimationCurve.Constant(times[times.Count - 1] + 0.05f, times[times.Count - 1] + 0.05f, 0)); } // Sort all the keyframes in order times.Sort(); // Add the info into the separate collections (since Unity can't serialize a dictionary) allFrameStarts.Add(allFrameTimes.Count); allFrameCounts.Add(times.Count); allFrameTimes.AddRange(times); allClips.Add(overrideClip == null ? c : overrideClip); } // Add the info to the runtime script ssg.clips = allClips; ssg.clipFrameStarts = allFrameStarts; ssg.clipFrameCounts = allFrameCounts; ssg.frameTimes = allFrameTimes; // Create all the out folders (one for each prefab), since this needs to be done at edit time List <string> allOutFolders = new List <string>(); foreach (var p in ssg.Prefabs) { string folder = "Spritesheets"; string path = AssetDatabase.GetAssetPath(p); path = path.Substring(0, path.LastIndexOf("/", path.LastIndexOf("/") - 1)); if (!AssetDatabase.IsValidFolder(path + "/" + folder)) { AssetDatabase.CreateFolder(path, folder); } path += "/" + folder; string name = p.name.Replace(" Variant", "").Replace("(Clone)", ""); if (!AssetDatabase.IsValidFolder(path + "/" + name)) { AssetDatabase.CreateFolder(path, name); } allOutFolders.Add(path + "/" + name + "/"); } // Update the runtime script with the list of output folders ssg.outFolderPaths = allOutFolders; }