Forum rules - please read before posting.

Feature Request: ActionList Editor shortcuts / hotkeys

Adventure Creator's actionlist editor is my go-to cutscene creator, and I intend to keep using it even in non-adventure games. My only problem is, it's a little bit slow to use!

Right now, let's say I want to make this node:

Here are the steps to make that node:
1. Drag out a new node.
2. Select "Action type: Camera" from the dropdown.
3. Select "Switch" from the second dropdown.
4. Choose which camera to switch to.
5. Type in the transition time.
6. Select the move method from the dropdown.
7. Check "Smooth transition out".

That's seven steps to make this particular node. If I'm writing a cutscene with five or six camera changes I keep doing, then my options are to either keep doing this seven-step process every time I swap, or scroll up, try to find the last time I made the same node, copy it, and paste it. Assuming the cutscene is large and has a lot of camera swaps, finding the right node to copy might take longer than just making a new node.

My suggestion is to add customizable hotkeys to the editor that would let the user save their favorite few nodes. Like the copy/paste clipboard, but with more slots (say, the 10 number keys) and saved even when Unity is closed and restarted.

This would easily cut the time it takes to make common nodes by more than half!

I'm thinking just an extra option in the dropdown for nodes, like this:

And then maybe a sub menu where you choose which number key you'd like to overwrite with this node.

To paste, you'd just hit (for example) Shift+4 to paste the 4th saved node.

I hope this is a manageable request, because this would make a huge impact on how long cutscenes take to make!

Comments

  • edited May 2019

    Thanks for the suggestion. I would mention that AC does now provide speech and camera tracks for Timeline, which is a viable alternative for creating cutscenes over ActionLists.

    Having hotkeys - particularly alphanumeric ones - compete with e.g. text fields etc could cause issues. I will give it some thought, however.

  • I've given this some consideration, but I don't think I'll be making this an official feature - at least for the moment.

    However, I will open up the API for the ActionList Editor window so that such extensions can be made in the next update. When v1.68.0 is out, I'll paste a script that allows for the copy/pasting of "favourite" Actions here for you.

  • As promised:

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using AC;
    using UnityEditor;
    
    public class FavouriteActionsEditor : EditorWindow
    {
    
        [MenuItem ("Adventure Creator/Editors/Favourite Actions", false, 4)]
        public static void Init ()
        {
            FavouriteActionsEditor window = EditorWindow.GetWindowWithRect <FavouriteActionsEditor> (new Rect (0, 0, 420, 360), true, "Favourite Actions", true);
            UnityVersionHandler.SetWindowTitle (window, "Favourite Actions");
            window.position = new Rect (300, 200, 420, 360);
        }
    
        private void OnGUI ()
        {
            if (ActionListEditorWindow.MainInstance == null)
            {
                EditorGUILayout.HelpBox ("The ActionList Editor window must be open for this to show.", MessageType.Warning);
                return;
            }
    
            for (int i=1; i<=10; i++)
            {
                EditorGUILayout.BeginHorizontal ();
                GUILayout.Label (i.ToString () + ":");
                if (GUILayout.Button ("Record"))
                {
                    Action markedAction = GetMarkedAction (ActionListEditorWindow.MainInstance.GetActions ());
    
                    if (markedAction != null)
                    {
                        RecordFavourite (markedAction, i);
                        ACDebug.Log ("Stored action " + markedAction.name + " as favourite " + i);
                        break;
                    }   
                }
                if (GUILayout.Button ("Paste"))
                {
                    Action favouriteAction = CreateFavourite (i, ActionListEditorWindow.MainInstance.CentrePosition);
                    if (favouriteAction != null)
                    {
                        if (ActionListEditorWindow.MainInstance.windowData.targetAsset != null)
                        {
                            ActionListAssetEditor.AddAction (favouriteAction, -1, ActionListEditorWindow.MainInstance.windowData.targetAsset);
                        }
                        if (ActionListEditorWindow.MainInstance.windowData.target != null)
                        {
                            ActionListEditor.AddAction (favouriteAction, -1, ActionListEditorWindow.MainInstance.windowData.target);
                        }
                    }
                }
                EditorGUILayout.EndHorizontal ();
            }
        }
    
        private Action GetMarkedAction (List<Action> actions)
        {
            if (actions != null)
            {
                foreach (Action action in actions)
                {
                    if (action != null && action.isMarked)
                    {
                        return action;
                    }
                }
            }
            return null;
        }
    
        private const string keyName = "AC.FavouriteActions";
        private static List<FavouriteAction> FavouriteActions = null;
    
        private static Action CreateFavourite (int keyNumber, Vector2 nodePosition)
        {
            // Get Prefs
            DownloadPrefs ();
    
            foreach (FavouriteAction FavouriteAction in FavouriteActions)
            {
                if (FavouriteAction.KeyNumber == keyNumber)
                {
                    Action createdAction = FavouriteAction.CreateAction ();
    
                    createdAction.nodeRect.x = nodePosition.x;
                    createdAction.nodeRect.y = nodePosition.y;
    
                    createdAction.endAction = ResultAction.Stop;
    
                    ActionCheck actionCheck = createdAction as ActionCheck;
                    if (actionCheck != null)
                    {
                        actionCheck.resultActionTrue = ResultAction.Stop;
                        actionCheck.resultActionFail = ResultAction.Stop;
                    }
    
                    ActionCheckMultiple actionCheckMultiple = createdAction as ActionCheckMultiple;
                    if (actionCheckMultiple != null)
                    {
                        foreach (ActionEnd ending in actionCheckMultiple.endings)
                        {
                            ending.resultAction = ResultAction.Stop;
                        }
                    }
    
                    ActionParallel actionParallel = createdAction as ActionParallel;
                    if (actionParallel != null)
                    {
                        foreach (ActionEnd ending in actionParallel.endings)
                        {
                            ending.resultAction = ResultAction.Stop;
                        }
                    }
    
                    return createdAction;
                }
            }
    
            return null;
        }
    
        private static void RecordFavourite (Action action, int keyNumber)
        {
            if (action == null)
            {
                return;
            }
    
            // Update or create new?
            DownloadPrefs ();
    
            foreach (FavouriteAction FavouriteAction in FavouriteActions)
            {
                if (FavouriteAction.KeyNumber == keyNumber)
                {
                    // Update
                    FavouriteAction.Update (action);
                    return; 
                }
            }
    
            // Create new
            FavouriteAction newFavourite = new FavouriteAction (action, keyNumber);
            FavouriteActions.Add (newFavourite);
    
            // Set Prefs
            string valueData = string.Empty;
            for (int i=0; i<FavouriteActions.Count; i++)
            {
                valueData += FavouriteActions[i].AsString;
                if (i < (FavouriteActions.Count - 1))
                {
                    valueData += SaveSystem.pipe;
                }
            }
            EditorPrefs.SetString (keyName, valueData);
        }
    
        private static void DownloadPrefs ()
        {
            if (FavouriteActions == null || FavouriteActions.Count == 0)
            {
                FavouriteActions = new List<FavouriteAction>();
    
                string allData = EditorPrefs.GetString (keyName);
                if (!string.IsNullOrEmpty (allData))
                {
                    FavouriteActions = new List<FavouriteAction>();
    
                    string[] splitData = allData.Split (SaveSystem.pipe[0]);
                    foreach (string data in splitData)
                    {
                        FavouriteActions.Add (new FavouriteAction (data));
                    }
                }
            }
        }
    
        private class FavouriteAction
        {
    
            private string actionAsJson;
            private string className;
            private int keyNumber;
    
    
            public FavouriteAction (Action action, int _keyNumber)
            {
                Update (action);
                keyNumber = _keyNumber;
            }
    
            public FavouriteAction (string data)
            {
                if (!string.IsNullOrEmpty (data))
                {
                    string[] splitData = data.Split (SaveSystem.colon[0]);
                    if (splitData != null && splitData.Length == 3)
                    {
                        className = splitData[0];
                        int.TryParse (splitData[1], out keyNumber);
                        actionAsJson = splitData[2].Replace ("*_PIPE_*", SaveSystem.pipe).Replace ("*_COLON_*", SaveSystem.colon);
                    }
                }
            }
    
            public void Update (Action action)
            {
                actionAsJson = JsonUtility.ToJson (action);
                className = action.GetType ().ToString ();
    
                if (!string.IsNullOrEmpty (className) && className.StartsWith ("AC."))
                {
                    className = className.Substring (3);
                }
            }
    
            public string AsString
            {
                get
                {
                    return className + SaveSystem.colon + keyNumber.ToString () + SaveSystem.colon + actionAsJson.Replace (SaveSystem.colon, "*_COLON_*").Replace (SaveSystem.pipe, "*_PIPE_*");
                }
            }
    
            public Action CreateAction ()
            {
                if (string.IsNullOrEmpty (className) || string.IsNullOrEmpty (actionAsJson))
                {
                    ACDebug.LogWarning ("Cannot create favourite Action.");
                    return null;
                }
                Action newAction = (Action) ScriptableObject.CreateInstance (className);
                JsonUtility.FromJsonOverwrite (actionAsJson, newAction);
                return newAction;
            }
    
            public int KeyNumber
            {
                get
                {
                    return keyNumber;
                }
            }
    
        }
    
    }
    
  • Thanks so much!!!

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.