Cheatsheet
A simple guide through the concepts behind solstack.
Core Concepts
There's really only three things you should care about in solstack: States, Trans and the Stack.
A State represents what your program should run at that moment. A MainMenu state does not render the player in a game; it renders options and pushes other relevant states on top of itself if the correct inputs are provided, or even quits the application entirely.
Take a look at the previous chapter Use Case for understanding a typical application flow in
solstack.
A Stack is a type that holds a list of States. When the stack's tick method is called, it looks for the topmost state it holds and executes its methods (namely on_tick and on_shadow_tick). This way, only the topmost state in a stack is run at a time; while the others are effectively paused.
In v0.3.0 we introduced the concept of a
shadow_tick. TheStacknow, when ticked, will execute the methodon_shadow_tickof every single state it holds. It can simply be ignored, of course.
A Trans represents a transition between States on a Stack. You can perform this directly through the Stacks methods (namely push, pop, quit, none, etc.). But the most useful way is through returning a Trans on the States on_update and/or on_shadow_update. Returning allows you to easily code conditional transitions, like if the player presses Esc, push the PauseMenu state.
Modeling an Application
Bring the important stuff into scope.
// State, Trans and Stack
use solstack::prelude::*;
// optional macros for cleaner code (i'll use both ways so you can choose)
use solstack::macros::*; Create an application data type that will hold important information. This will be shared mutably by all of your states.
#[derive(Default)] // optional
struct AppData {
// important data for your app
name: String,
age: i32,
}Create some states.
struct Menu; // the main menu.
struct PromptName; // prompts the user for their name (stores in AppData).
struct PromptAge; // prompts the user for their age (stores in AppData).
struct Greet; // prints a greeting to the user and their age (reads from AppData).Implement
Statefor your states.
impl State<AppData> for Menu {
fn on_start(&mut self, _data: &mut AppData) {}
fn on_stop(&mut self, _data: &mut AppData) {}
fn on_pause(&mut self, _data: &mut AppData) {}
fn on_resume(&mut self, _data: &mut AppData) {}
fn on_tick(&mut self, _data: &mut AppData) -> Trans<AppData> {
Trans::None
}
fn on_shadow_tick(&mut self, _data: &mut AppData) -> Trans<AppData> {
Trans::None
}
}Your IDE might bring the
dataparameter on the methods as_data. This tells rust it's not currently being used. If you're going to use it, change it dodata.
All of the methods are documented below in Callbacks and in the crate's docs.
All of the
Transitions are documented below in Transition and in the crate's docs.
Instatiate your data and a new stack; set up a loop.
fn main() {
let data = AppData::default();
let stack = Stack::<AppData>::new();
// push at least one state directly, otherwise `is_running` will immediately
// return false.
stack.push(&mut data, Box::new(Menu));
// or stack_push!(stack, data, Menu);
while stack.is_running() { // keeps going until there are no states inside.
stack.tick(&mut data);
// or stack_tick!(stack, data);
}
If you are goin to use
is_running, make sure that eventually at least one of your states requests for aTrans::Quit. Otherwise you'll have an infinite loop. If you need your ticks to be called, for instance, 60 times/frames per second, you'd do that logic here. Thesolstacklib won't opinate on how or how often totick, thoughfeatures are planned for that.
Callbacks
on_pause
no
on_resume
no
on_tick
Represents a single tick/update. It’s called when the Stack’s .tick() is called. Your loop logic should call your stack’s tick, not this directly.
yes
The methods marked as
TRANSrequires returning aTrans(see how at the chapter below Transitions.
Transitions
Push(Box<State<D>>)
stack.push
stack_push!
trans_push!
Trans::Push
Pushes a new state above the current one. Effectively pauses the current state until everything above it is popped.
Pop
stack.pop
stack_pop!
trans_pop!
Trans::Pop
Pops the current state from the stack.
Replace<Box<State<D>>
stack.replace
stack_replace!
trans_replace!
Trans::Replace
Pops and pushes a new state. Effectively replaces the current state with a new one.
Isolate<Box<State<D>>
stack.isolate
stack_isolate!
trans_isolate!
Trans::Isolate
Pops every state from the stack and pushes a new one. Effectively isolates it as the only state on the stack.
Quit
stack.quit
stack_quit!
trans_quit!
Trans::Quit
Pops everything from the stack. Effectively ends the state stack machine.
None
trans_none!
Trans::None
Does nothing to the stack. Effectively keeps the current state and the stack the way it is.
Stack Ticking (Not a Transition)
stack.tick
stack_tick!
Ticks the current (topmost at the stack) state once and performs any necessary transitions. Also ticks every state's shadow tick and performs their transitions.
Last updated