- Thank my early backers, esp. Vitlam, if you end up having fun with this.
SimpleStateMachine
Main goals: - Help users build interactive, and sequential scenes, with less fear of making mistakes.
- Give the user a better sense of ability, without having to learn much more beyond the native UI.
- Give users a way to experiment with controller physics values
- Tinker with spring, damper, max-velocity, drive values, etc., between states/positions of Atoms and Character controllers.
- See 'ice skating', and the 'leg over ball' clips.
You won't need it until you've developed an idea that doesn't seem possible without it.
In short, here's what I suggest trying first.
1 Undo - Slap it onto the default Atom you build with / play with the most. Add 2 or more "All" type state slots. Make some edits. Click "Revert Unsaved Changes". That's your "Undo".
2 Experiment - Attach the plugin to the CyberPunk Apartment. Spam-create some "All" state collection types. Now, see what components in the Environment you can change and "trigger" for each state. Turn on the shower, Change the lights. Add some more Atoms and parent them to the Apartment Atom.
3 Adjust / Play w/ Physics - Parent a Person or 2 to a SubScene Atom. go to the Person Controller UI, and set all joints to a spring of 300 by altering the "All Joints Controller" Spring value to 3.0. Also, set Max Velocity in the same UI to 0, or 0.01. Spam-Create some "Controller" or "All" type slots. Use either use the plugin's UI each time, to click "Next", or better yet, use a keymapper, to iterate, or create a short looping Animation with the Scene Animation, SubScene Animation, or Timeline. Simply add the Plugin's "Next" action as a trigger. This is how I started out creating the skating video.
Tip: An example of what I've learned: If you are seeing the head/neck or other joint on a character bending oddly during an animation or state transition, try maxing out the neck/head/other joint's Joint Drive Spring, Joint Drive Force, and/or Joint Drive Damper, to put them in a more mannequin state. Set them back when not needed (eg. by duplicating a softer state into the next slot). Increase their range and re-max them out if they're still 'flopping/bending'.
4 Try Tracking/Modifying/Restoring the state of your favorite plugins! Eg. Create a state for a character with a Gaze script running. In one state, have the character look at the player. Create another slot, set the plugin to target the player's hand or another character. Create a slot... You now have two "presets" of Gaze you can switch between. Create as many as you wish - They do not all load at runtime as far as I can tell, but are "lazy-loaded" from JSON (which is about as efficient as we can ask for, without some targeted tweaking for scripts that use more intensive storing/loading routines).
Most seem to work as expected. Most likely, even if the plugin does not provide an Action to trigger a specific slider, for example, so long as the saving/restoring, works for that slider, SimpleStateMachine will likely work as the triggers for your plugin that you never knew you could have! Also, the plugin provides reachable actions for most of its capabilities, so you can control it with other plugins.
5 Try "Everything" - You can think of SimpleStateMachine as an "all-in-one" for the huge amount of triggers one would need to create, in order to make a scene with dozens of interactive elements, light sources in different places at different times, character dialogs, etc. etc. Every change you make for a state is "triggered" when you navigate back to that state.
I think that covers the basics.
- Usage:
- Overview:
- Create states.
- 1. Add a slot, and use VaM just the way you normally would, to update the state.
- 2. Save the state, by moving to the next state (while Edit Mode is enabled).
- 3. Repeat from #1.
- Test state transitions.
- For PoseMorph types, keep in mind that "zero/default" values in one state but not the other will result in a carry-over. You may find yourself having to set "near-zero/default" values when you don't want morph states to merge/overlap.
- For controllers, play with aforementioned physics values to see how much difference they can make during a transition.
- For Triggers, keep in mind that each collection slot containing a trigger gives that trigger its own trigger set.
- Create states.
- Attach to a SubScene (the most useful), or any Atom to which other Atoms are parented, to control child elements.
- May also track components in the parent, depending on the Atom type.
- Attach to a Person,for a specialized menu and abilities specific to Person Atoms.
- To move a Person or their controllers, make the Person a child of a SubScene or other element, and attach the plugin to that parent Atom.
- You can include and control multiple people and Atoms at once, for each state.
- Concepts:
- State - Collection of non-default component values in Atom / SubScene / Atom Tree (Atoms parented to one another).
- Slot - A container for a collection state. Represented in UI by x3 grid of elements with signifiers.
- Signifier - A property of an object that hints to users as to how it can be interacted with, or what action(s) it represents.
- Cursor - The "index pointer" to the current state slot.
- State Collection Type - The type of components tracked by the given state.
- State Range - How far notifications are sent out, when a state is restored to.
- Player State Range - Represents the range at which the given instance can be triggered by a restored state in another instance.
- UI:
- Left Side:
- State Collection Type
- what gets tracked
- State Range Type
- other SimpleStateMachine instances can be triggered by a state slot
- triggers occur after state of a non-singular type is restored.
- The receiving instance must have its Range set to a non-singular Range type in order to receive triggers.
- Add/Revert/Remove Slot
- Slot Signifiers (x3 grid)
- State Collection Type
- Right Side:
- Hide Instructions
- Play/Edit
- Use together to navigate and edit specific states
- Play Mode:
- State will be restored when "cursor" reaches state
- Edit Mode:
- State will be saved when "cursor" leaves state
- To update slots without letting them play, use "Next/Prev" with Edit mode on, and Play mode off
- To update a specific slot, turn both modes off until "cursor" reaches target state, then turn on Edit mode.
- Player Range Type
- Will trigger Next/Prev/Restore on Restore of state with matching Range
- Enable/Disable Swap
- Disables Swapping
- Different from Disabling Play+Edit, in that "cursor" will not move!
- Prev/Next (+ PoseMorph & SpeechBubble duration sliders if on Person Atom)
I've heard it works similar to Unreal Engine 5's Variant system, but I haven't used that, so I'm not sure.
I played with / built this for 3 months, and started to see all sorts of possibilities. Unfortunately for me, I've had to put a lot more time in creating the plugin, the UI, and running tests than I've been able to play with the plugin myself. I hope you guys can start enjoying w/out my having to document too much (I have a Patreon and Discord w/ more info). That said, I know the docs are lacking, and will try to improve them over time.
I expect it will take users a while to understand all of the use cases. I'm sure there are many I haven't thought of.
The first way to think of SimpleStateMachine is as a learning tool, then as a building tool. I'm releasing as a standalone, and building a scene to release later, possibly with an updated version of the script, depending on feedback/bug reports.
Example Use Cases:
- Swapping characters, and allowing swappable character to be updated from user input.
(given as response to a forum question)
-- Setup: Each character has 2 "All" state collection slots created.
-- "...swap Characters" will just call "Next" on both characters (on their plugin instances).
-- Actions: The "...update change" button uses the plugin instance actions, "PlayMode", "EditMode", and "Next", along with native actions "Person->AppearancePreset->name/store/load" to update the target character, and update the collection slot for the other character's 2nd look. You could give each character N number of slots, iterate through, and update all of them the same way.
-- Result: Subsequent triggers of the "...swap Characters" button will reflect the updated states of the characters.
(see video uploads for more)
(I had to keep most of my video clips under 10MB for Discord, so I apologize if some seem oddly short/uninspired)
- Fireworks covering the sky, using only 3 Firework-enabled Atoms, an initial trajectory, and physics transitions.
- Inspire "softer" animations and general physics for scenes (easy keyframe + transition testing for those not able to animate w/ mocap)
- NOTE: SubScene Animations are one of the many components you can track, save, and restore.
- Set up game-like scenes, with multiple paths, sequential parts, etc, without having to learn much beyond the native VaM UI. One of my goals is to see a pool table and bowling alley in game. When I say "tinker", what I really mean is "go wild"
(see clip 'IWasNotReady')
- Instead of having 20 lights in an apartment, you can theorize the minimum you need to keep the apartment lit with you as you walk through it, and re-use them. You can repurpose the lights as well, having a single Light Atom change in type, color, direction, etc. (see clip with wall lights + "sun" shadows)
- Re-Use your UIButtons and Menus instead of turning a series of them on/off. The same button can trigger different actions in each of its states, change its size, label, color, etc.
- Use the PoseMorph state transitions to place base expressions onto your models for different modes/states, and still let your favorite subtle morph expression plugin do the rest. Use the MVRScript state collection type on that plugin to create a version of its expression loops for each state.
- etc.
Any feedback or support is greatly appreciated.
Thanks for giving SimpleStateMachine a shot!
------
There are a few more things I'd want to implement, if circumstances permit - like "ghosting" the character immediately from one position to the next without needing extra steps/triggers or overlays to hide such transitions (eg. video clip with wall lights / shadows). But if there's a plugin for that, I won't feel it necessary.
If there is a next plugin, it will be creating the other big idea I had, which boils down to the title of "Presence". It would work similar to "Give ME FPS", but for personalized usability / scene editing routines vs. performance settings.