Created
September 19, 2024 00:00
-
-
Save Sundwell/dadb1ec05e5a057f954231af6fd1f0fa to your computer and use it in GitHub Desktop.
Godot nodeless state machine
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class_name CallableStateMachine | |
var state_dictionary = {} | |
var current_state: String | |
func add_states( | |
normal_state_callable: Callable, | |
enter_state_callable: Callable = Callable(), | |
leave_state_callable: Callable = Callable() | |
): | |
state_dictionary[normal_state_callable.get_method()] = { | |
"normal": normal_state_callable, | |
"enter": enter_state_callable, | |
"leave": leave_state_callable | |
} | |
func set_initial_state(state_callable: Callable): | |
var state_name: String = state_callable.get_method() | |
if state_dictionary.has(state_name): | |
_set_state(state_name) | |
else: | |
push_warning("No state with name " + state_name) | |
func update(delta: float): | |
if not current_state == null: | |
(state_dictionary[current_state].normal as Callable).call(delta) | |
func change_state(state_callable: Callable): | |
var state_name = state_callable.get_method() | |
if state_dictionary.has(state_name): | |
_set_state.call_deferred(state_name) | |
else: | |
push_warning("No state with name " + state_name) | |
func _set_state(state_name: String): | |
if current_state: | |
var leave_callable = state_dictionary[current_state].leave as Callable | |
if not leave_callable.is_null(): | |
leave_callable.call() | |
current_state = state_name | |
var enter_callable = state_dictionary[current_state].enter as Callable | |
if not enter_callable.is_null(): | |
enter_callable.call() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extends CharacterBody2D | |
@onready var weapon = $Weapon | |
@onready var health_component: HealthComponent = $HealthComponent | |
@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D | |
const RUN_SPEED := 125.0 | |
const BASE_MOVE_SPEED := 50.0 | |
const ACCELERATION_SMOOTHING := 15 | |
var is_shooting := false | |
var damage_rate := 10.0 | |
var health := 100.0 | |
var mutations: Dictionary = {} | |
var move_speed := 50.0 | |
var state_machine := CallableStateMachine.new() | |
func _ready(): | |
GameEvents.mutation_upgrade_selected.connect(on_mutation_upgrade_selected) | |
state_machine.add_states(state_idle, enter_state_idle) | |
state_machine.add_states(state_moving) | |
state_machine.set_initial_state(state_idle) | |
func _physics_process(delta: float): | |
state_machine.update(delta) | |
move_and_slide() | |
func shoot(): | |
if Input.is_action_pressed('fire'): | |
is_shooting = true | |
weapon.shoot() | |
else: | |
is_shooting = false | |
func flip(): | |
if velocity.x < 0: | |
sprite.flip_h = true | |
elif velocity.x > 0: | |
sprite.flip_h = false | |
func get_movement_direction() -> Vector2: | |
return Input.get_vector('move_left', 'move_right', 'move_top', 'move_down') | |
func move(delta: float): | |
var direction = get_movement_direction() | |
var speed = move_speed if is_shooting else RUN_SPEED | |
var target_velocity = direction.normalized() * speed | |
velocity = velocity.lerp(target_velocity, 1.0 - exp(-delta * ACCELERATION_SMOOTHING)) | |
func enter_state_idle(): | |
sprite.play('idle') | |
velocity = Vector2.ZERO | |
weapon.visible = true | |
func state_idle(delta: float): | |
shoot() | |
if get_movement_direction().length() > 0: | |
state_machine.change_state(state_moving) | |
func state_moving(delta: float): | |
shoot() | |
move(delta) | |
flip() | |
if get_movement_direction().length() == 0: | |
state_machine.change_state(state_idle) | |
return | |
if mutations.has("run_while_shooting"): | |
weapon.visible = true | |
sprite.play("run") | |
else: | |
if is_shooting: | |
weapon.visible = true | |
sprite.play("walk") | |
else: | |
weapon.visible = false | |
sprite.play("run") | |
func on_mutation_upgrade_selected(upgrade: MutationUpgrade, current_upgrades: Dictionary): | |
if upgrade.id == "run_while_shooting": | |
mutations["run_while_shooting"] = true | |
move_speed = RUN_SPEED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment