class_name StateMachineAnimatedActor extends StateMachine func change_state(new_state: State) -> void: if current_state: current_state.exit() # Set parameters for information if new_state is StateAnimatedActor and current_state is StateAnimatedActor: set_previous_animation( current_state, new_state) current_state = new_state current_state.enter() if(state_modifiers.size() > 0 and debug_state_machine): print("Active Modifiers:") for mods in state_modifiers: print(mods.name) func set_previous_animation( old_state: StateAnimatedActor, new_state: StateAnimatedActor ) -> void: new_state.previous_animation_name = old_state.mod_animation_sequence[old_state.current_animation_sequence] new_state.previous_state_frame_number = old_state.animations.frame new_state.previous_state_name = old_state.name #animation_name :String, frame_number : int, animation_sequence :Array return # Initialize the state machine by giving each child state a reference to the # parent object it belongs to and enter the default starting_state. func init_animated_actor(parent: KinematicBody2D, animations: AnimatedSprite, move_component: MovementComponent) -> void: animations.connect("animation_finished", self, "_on_AnimatedSprite_animation_finished") for child in get_children(): if child is StateAnimatedActor: if debug_state_machine: print("Initializing State Node for ", parent.name, ": ", child.name) child.parent = parent child.animations = animations child.move_component = move_component child.modifier_stack_ref = state_modifiers if debug_state_machine: child.debug_state = true # Initialize to the default state change_state(get_node(starting_state)) func process_frame(delta: float) -> void: # Check the state modifiers for timeouts, and maybe more conditions later # If the modifier is no longer valid, pop it from the stack. # We could iterate through a whole list of states but I'm not sure i want # states to be that complex. var current_anim_state :StateAnimatedActor = current_state if state_modifiers.empty() == false: for i in range(state_modifiers.size()): # if this modifer is a timer based one if state_modifiers[i].state_timeout.time_left == 0 and state_modifiers[i].timeout_seconds !=0: # Need to do extra stuff if it's an animation based one if state_modifiers[i].modifier_type == "Animation Suffix": if debug_state_machine: print("State Modifier Timeout: ", state_modifiers[i].name, " -> ", state_modifiers[i].animation_name) # Reset animation suffix current_anim_state.animation_suffix = '' # Get the current frame of animation var current_frame = current_anim_state.animations.frame # Set the animation index to the current one current_anim_state.animation_index = current_anim_state.current_animation_sequence #current_anim_state.current_animation_sequence #current_anim_state.animations.play() current_anim_state.animations.play( current_anim_state.mod_animation_sequence[current_anim_state.animation_index]) # Try to set the current frame to the same as before. current_anim_state.animations.frames.frames.size() >= current_frame current_anim_state.animations.frame = current_frame ##TODO: # no longer needed this way maybe. way to overengineer man. # if current_anim_state.animation_sequence.size() >= current_anim_state.mod_animation_sequence.size(): # print("Change sequence!: ", current_anim_state.mod_animation_sequence) # print("Origin sequence!: ", current_state.mod_animation_sequence) # current_anim_state.animations.play( # current_anim_state.mod_animation_sequence[current_anim_state.animation_index]) # # Try to set the current frame to the same as before. # current_anim_state.animations.frames.frames.size() >= current_frame # current_anim_state.animations.frame = current_frame # else: # current_anim_state.animations.play( # current_anim_state.animation_sequence[0]) if debug_state_machine: print("Pop State Modifier: ", state_modifiers[i].name) state_modifiers.pop_at(i) # if state_modifiers[-1].state_timeout.time_left == 0 and state_modifiers[-1].pre_append_animation == false: # if debug_state_machine: # print("Pop State Modifier: ", state_modifiers[-1].name) # state_modifiers.pop_back() # # Reset animation suffix # current_state.animation_suffix = '' # var current_frame = current_state.animations.frame # #current_state.animations.play(current_state.animation_sequence[current_state.animation_index]) # #TODO: Bodge to fix crash # current_state.animation_index = 0 # current_state.current_animation_sequence = 0 # current_state.animations.play(current_state.animation_sequence[0]) # current_state.animations.frame = current_frame; var new_state = current_state.process_frame(delta) if new_state: change_state(new_state) func _on_AnimatedSprite_animation_finished(): ##TODO: # It's hard to pop an exit animation off when it's stacked with another kind of animation. for i in state_modifiers.size(): if state_modifiers[i].modifier_type == "Exit Animation": #print("Time to pop state modifer: ", state_modifiers[i].animation_name, current_state.animation_suffix, " <-> ", current_state.animations.animation + current_state.animation_suffix) if (state_modifiers[i].animation_name + current_state.animation_suffix) == current_state.animations.animation: print("Time to pop state modifer: ", state_modifiers[i].animation_name, current_state.animation_suffix, " <-> ", current_state.animations.animation ) print(current_state.mod_animation_sequence) state_modifiers.pop_at(i) current_state.animation_index += 1 break # if state_modifiers.empty() == false: # if state_modifiers[-1].pre_append_animation == true: # if debug_state_machine: # print("Pop State Modifier: ", state_modifiers[-1].name) # state_modifiers.pop_back() if current_state.animations.frames.get_animation_loop( current_state.animations.animation) == false: if current_state.animation_sequence.size() > 0: print("<-- next anim.") current_state.animation_index += 1