gd-YAFSM(Finite State Machine) demo
by imjp94
Demo for gd-YAFSM
The purpose of this project is to showcase how you can integrate gd-YAFSM into your project.
Content
Manage App State
One of the best way to show the potential of StateMachine
/gd-YAFSM is through managing app state as you can have full control over transitions of scenes.
Change Scene
func _on_AppState_transited(from, to):
......
# Handle previous scene
var prev_scene
if from_dir.is_nested():
if from_dir.is_exit():
prev_scene = get_node_or_null(from_dir.get_base())
else:
prev_scene = get_node_or_null(from)
if prev_scene:
prev_scene.queue_free()
# Handle next scene
var next_scene
match to_dir.next():
"SplashScreen":
next_scene = splash_screen_scn.instance()
"StartScreen":
next_scene = start_screen_scn.instance()
"MainMenu":
next_scene = main_menu_scn.instance()
"LevelSelect":
next_scene = level_select_scn.instance()
"Game":
match to_dir.next(): # Match nested state
"Entry": # Game/Entry
next_scene = game_scn.instance()
"Exit":
get_tree().quit()
if next_scene:
next_scene.name = to_dir.get_base()
next_scene.set("app_state", app_state)
add_child(next_scene)
Main.gd free previous scene & spawn next scene in "transited(from, to)" signal
Cache Scene
Cache a unfinished game level, then restore it on next time
func _on_AppState_transited(from, to):
......
match to_dir.next():
"Game":
match to_dir.next():
"Exit": # Game/Exit
if not ("End" in from): # Not from Game/End(not finished)
remove_child(current_level_instance)
app_state.set_param("last_level", current_level_instance)
current_level_instance = null
......
func setup_level():
if app_state:
var last_level = app_state.get_param("last_level")
...
current_level_instance = last_level
...
if current_level_instance:
current_level_instance.set("app_state", app_state)
add_child(current_level_instance)
Game.gd cache unfinished level with StateMachinePlayer.set_param
, then retrieving from StateMachinePlayer.get_param
to restore it
NOTE: Always remember to manually free
Node
, when erase fromStateMachinePlayer
to avoid memory leak
Pause Game
Pausing game is just as easy as few line of codes:
func _on_AppState_transited(from, to):
match to_dir.next():
"Game":
match to_dir.next():
"Pause": # Game/Pause
if not pause_menu_instance:
pause_menu_instance = pause_menu_scn.instance()
pause_menu_instance.set("app_state", app_state)
......
add_child(pause_menu_instance)
get_tree().paused = true
"Play": # Game/Play
......
get_tree().paused = false
if pause_menu_instance:
remove_child(pause_menu_instance) # Don't free yet, save for later
Game.gd handle pause & resume
Game State
Most of the game has its own rules, like in what condition player win/lose, and this can be managed by StateMachine
as well:
...
func _on_Area_body_entered(body):
# Victory
if body is Character3D:
if app_state:
app_state.set_param("Game/End/win", true)
app_state.set_trigger("game_end")
...
KinematicLevel3D.gd make use of nested parameter "Game/End/win" to update game state
NOTE: Nested parameter("Game/End/win") is used in this case, so that it will be reset(erased) automatically on "Game/End/Exit" and you don't have to initiliaze the parameter everytime game start
Manage Character State
func _on_StateMachinePlayer_updated(state, delta):
# NOTE: It is more efficient to run directly in _physics_process, this demo is to showcase how to handle logic in updated signal
velocity += Vector3.DOWN * 9.8 * delta
match state:
"Idle":
pass
"Walk":
velocity += walk * speed * delta
walk = Vector3.ZERO
"Jump":
_jump_count = 0
jump()
smp.set_param("jump_count", _jump_count)
"Jump(n)":
jump()
smp.set_param("jump_count", _jump_count)
"Fall":
smp.set_param("jump_elapsed", OS.get_system_time_msecs() - _last_jump)
velocity = move_and_slide(velocity, Vector3.UP)
velocity.x *= pow(1.0 - damping, delta)
velocity.z *= pow(1.0 - damping, delta)
Character3D.gd update motion of KinematicBody
Note:
StateMachine
as aResource
only store static data, therefore it is highly reusable. For instance, both Character2D/3D are using the sameStateMachine
resource to control motion despite they inherit from different class
Download
Support
If you need help or have questions about this plugin, please contact the author.
Contact Author