Slate Forums › Custom Clips › Slate Tweaks Megapost
I probably gestured at making this thread over a year ago. I’ve now been on two projects where I’ve used Slate, mostly as a programmer helping designers and cinematics folks get the results they want. In both these projects (and a big reason we went with Slate over Timeline) I’ve made lots of tweaks and improvements to the editor and its ActionClips to suit our needs. This time, though, I documented most of the biggest tweaks I’ve made so that I can reapply them whenever we end up upgrading, but also because I anticipated wanting to share these with the wider userbase.
NOTE 1: I want to state at the top that I know how legally/ethically precarious a post like this can be for a developer when they want to make decisions on features to add to their software. So let me say in no uncertain terms: everything here is completely free to use and steal by other users and ParadoxNotion, no credit or compensation needed. This stuff helps make Slate more useful for me and I think it can help it be more useful for others. If you agree, incorporate away!
NOTE 2: To further lower the temperature, all the code below is written by me, noting where in the Slate codebase to apply it. No code written by ParadoxNotion has been pasted here. You obviously need to own a legit copy of Slate for any of this to matter.
NOTE 3: These modifications were made off of Slate 1.99. The package has been upgraded since we started our project, so some noted tweaks may be out of date.
1. Cutscene List Dropdown Size
Made the cutscene dropdown width always match the length of the selected cutscene:
Inside ShowToolbar()
1 2 3 4 5 6 |
GUIContent cutsceneName = new GUIContent(cutscene.name); Vector2 nameSize = EditorStyles.toolbarDropDown.CalcSize(cutsceneName); if ( GUILayout.Button($"[{cutsceneName.text}]", EditorStyles.toolbarDropDown, GUILayout.Width(nameSize.x + 8f)) ) { // Normal code |
2. ActionClips have a virtual PreferredLength property
I added a command (both in a dropdown and as a hotkey) that sets an ActionClip length to match a clip’s “preferred length.” ActionClip’s preferredLength is by default 1f unless overwritten by an implementation. For example: PlayAnimatorClip’s preferredLength is the length of the AnimationClip attached to it, SubCutscene’s preferredLength is the length of the cutscene it references. Handy to ensure that clips that play events of a certain length match that length, if a designer wants it to.
Inside ActionClip
1 2 3 4 5 6 |
public virtual float preferredLength { get { return 1f; } } |
Inside CutsceneEditor.DoClipContextMenu()
1 2 3 4 5 6 7 8 9 |
if (action is ActionClip clip) { menu.AddItem(new GUIContent("Set to Preferred Length"), false, () => { clip.length = clip.preferredLength; }); } |
3. Pressing F over Slate with no selection fits cutscene timeline to editor window
Quickly set the zoom to show the whole cutscene.
Inside DoKeyboardShortcuts()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
if ( e.keyCode == KeyCode.F ) { if (CutsceneUtility.selectedObject == null) { // Fit cutscene view to window float margin = length * 0.075f; viewTimeMin = -margin; viewTimeMax = cutscene.length + margin; } else { // The normal stretch-fit code } e.Use(); } |
4. Pressing Escape kills editor playback
A very simple addition that sped up my workflow quite a bit
Inside DoKeyboardShotcuts()
1 2 3 4 5 6 7 |
if (e.keyCode == KeyCode.Escape) { Stop(false); e.Use(); } |
5. Cutscenes Dropdown List is Sorted Alphabetically
Some of our scenes have a lot of cutscenes, and this makes the list easier to scan through.
Inside Cutscene
1 2 3 4 5 6 |
public static int Compare (Cutscene a, Cutscene b) { return String.Compare(a.name, b.name, StringComparison.InvariantCulture); } |
Inside CutsceneEditor.ShowToolbar() and CutsceneEditor.ShowWelcome()
1 2 3 4 |
List cutscenes = new List(FindObjectsOfType()); cutscenes.Sort(Cutscene.Compare); |
6. Added OnDelete method to ActionClip
If your ActionClip is managing other child objects that you want to delete if the clip is removed, this comes in really handy. Override the OnDelete() method to add this to your ActionClips.
Inside ActionClip
1 2 3 4 5 6 7 8 |
public void PreDelete () { OnDelete(); } virtual protected void OnDelete() { } |
Inside CutsceneTrack
1 2 3 4 5 6 7 8 9 |
///Remove an ActionClip from this Track public void DeleteAction(ActionClip action) { //... action.PreDelete(); UnityEditor.Undo.DestroyObjectImmediate(action); //... } |
7. Added “Set Cutscene Length” Popup
If you right-click on the end caret, you’ll get a context menu with the option to “Set To Last Clip Time” and now also a “Set Cutscene Length” option. Clicking this last option will open a pop-up window that lets you specify the length of the cutscene in Seconds or Frames.
Inside CutsceneEditor in DoScrubControls after the “Set To Last Clip Time” menu item is created
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 |
menu.AddItem(new GUIContent("Set Cutscene Length"), false, () => { DoPopup(() => { EditorGUILayout.LabelField(new GUIContent("<b>Set Cutscene Length</b>"), Slate.Styles.leftLabel); EditorGUI.BeginChangeCheck(); float newLength = length; newLength = EditorGUILayout.DelayedFloatField(new GUIContent("Seconds"), newLength); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(cutscene, "Set Cutscene Length"); length = newLength; } // cutscene.currentTime * Prefs.frameRate int frames = Mathf.FloorToInt(length * Prefs.frameRate); EditorGUI.BeginChangeCheck(); frames = EditorGUILayout.DelayedIntField(new GUIContent("Frames"), frames); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(cutscene, "Set Cutscene Length"); length = (float)frames / Prefs.frameRate; } }); }); |
8. Can resize the start of a cutscene
One of our team members requested the ability to extend the length of the cutscene and offset all the existing clips forward the same amount. The solution I came up with was adding a “cutscene resize caret” to the beginning of the cutscene, just like the one that’s on the end. When the user lets go of the Start Caret, it runs this method:
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 31 32 33 34 |
// When the user lets go of scrubbing the start time caret (in DoScrubControls()), // take that startOffsetTime and offset the starting time void OffsetCutsceneStartTime () { if (cutscene != null) { Undo.RecordObjects(new Object[]{cutscene, this}, "Set Cutscene Start Time"); cutscene.length -= startTimeOffset; viewTimeMin -= startTimeOffset; viewTimeMax -= startTimeOffset; foreach (CutsceneGroup group in cutscene.groups) { // Move sections if (group is DirectorGroup) { foreach (Section section in group.sections) { section.time -= startTimeOffset; } } // Move all clips foreach (CutsceneTrack track in group.tracks) { foreach (ActionClip clip in track.clips) { clip.startTime -= startTimeOffset; } } } } startTimeOffset = 0f; } |
9. Cutscene resizing carets are locked by toolbar button
Coworkers would accidentally resize the cutscene when they meant to to scrub a surprising number of times. So to the toolbar, I added a lock button that, when enabled, will disable the cutscene resizing carets. You can’t resize the cutscene until you disengage that button.
10. AnimatableParameter always keys if modified in inspector field
Whether or not you have Auto-Key turned on, if the user modifies an AnamatableParameter in the inspector by changing its value, I assume they intended to key that value change. Multiple people found it confusing when they’d change one of these values and it would just snap back.
This is only for inspector value changes, not scene gizmos. Those still adhere to Auto-Key rules.
Inside AnimatableParameterEditor near the bottom of DoParameterField, we modify what happens when GUI changes have been made:
1 2 3 4 5 6 7 8 9 |
if ( EditorGUI.EndChangeCheck() && newValue != value ) { animParam.SetCurrentValue(newValue); bool hasAnyKey = animParam.HasAnyKey(); if ( hasAnyKey || ( animParam.isExternal && !hasAnyKey ) ) { animParam.TryAutoKey(time); } } |
11. ActionClips have hasWarning virtual property
If I want to have a clip present itself as having an issue the designer should look into (something not set up, setting that has a weird value, etc), I have a property that will turn the clip yellow so it jumps out at them. This is usually accompanied by a warning box in the clip inspector explaining the warning, but that’s written manually.
Inside ActionClip:
1 2 3 4 5 6 |
public virtual bool hasWarning { get { return false; } } |
Inside CutsceneEditor.OnClipGUI() just before action.ShowClipGUI(wholeRect):
1 2 3 4 5 6 |
if (action.hasWarning) { EditorGUI.DrawRect(wholeRect, Color.yellow); } |
Ah, looks like the formatting got smoothed over. Or admin lent a quiet hand. Thank you!