class_name StateAnimatedActor extends State ## Animation and movement state class ## ## A state intended to control the movement and animation ## functions of a KinimaticBody2D node. Initialized with a ## player, movement node, and kinematicbody2d ## I think if we also had modifier states that transfered along with the enter and entrance of nodes, that would be helpful. ## ## @WIP # export (NodePath) var jump_node # onready var jump_state: State = get_node(jump_node) ## Deprecated # export var animation_name: String export var move_speed: float = 60 export(Array, String) var animation_sequence signal frame_reached(state_name, animation_name, frame_number) export(Dictionary) var emitter_frame_subscriptions var frame_signal_emitted: bool = false # this just wouldn't work well. Maybe I can try a resource # export(Array, NodePath) var transition_state_nodes #TODO: I think these two variables accidentally serve the same purpose # I think one was intended to be a string of the current animation name. var animation_index: int = 0 var current_animation_sequence: int = 0 var animation_suffix: String = ''; var mod_animation_sequence = [PoolStringArray()] var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity") var animations: AnimatedSprite var move_component: MovementComponent var parent: KinematicBody2D #animation_name :String, frame_number : int, animation_sequence :Array var previous_animation_name : String var previous_state_frame_number : int var previous_state_name: String #var animation_sequence_timer: Timer func _ready(): ##TODO: this bit me in the butt. Should add a safety or something. # Only add timout node if timer value was specified. if(timeout_seconds > 0.0): state_timeout = Timer.new() state_timeout.wait_time = timeout_seconds state_timeout.one_shot = true state_timeout.autostart = false add_child(state_timeout) func enter() -> void: # animations.connect("animation_finished", self, "_on_AnimatedSprite_animation_finished") mod_animation_sequence.clear() #mod_animation_sequence = animation_sequence.duplicate(true) mod_animation_sequence.append_array(animation_sequence) # Reset animation suffix in case there isn't one animation_suffix = '' animation_index = 0 current_animation_sequence = 0 #var enter_animation = '' var enter_frame = 0 if debug_state: print(parent.name, " entering State: ", self.name) move_component.current_movement_state = self.name emit_signal("state_entered") #modifier_stack_ref = state_modifiers # A new attempt at animation modifiers if modifier_stack_ref.empty() == false: print("nope: ") var i = modifier_stack_ref.size() - 1 ##NOTE: i apparently reverse range itteration doesn't work #for i in range(modifier_stack_ref.size(), 0): # work in reverse while (i >= 0 and modifier_stack_ref[i].modifier_type != "None"): print("Animation Modifier!: ",modifier_stack_ref[i].modifier_type) match modifier_stack_ref[i].modifier_type: "Exit Animation": mod_animation_sequence.push_front(modifier_stack_ref[i].animation_name) enter_frame = modifier_stack_ref[i].starting_frame # Gonna ty and avoid this for now #modifier_stack_ref.pop_at(i) # we're done with this modifier "Animation Suffix": if animations.frames.has_animation(mod_animation_sequence[animation_index] + modifier_stack_ref[i].animation_name): animation_suffix = modifier_stack_ref[i].animation_name else: print("Warning!: Animation suffix that doesn't exist ", mod_animation_sequence[animation_index] + modifier_stack_ref[i].animation_name) "Replace Animation": #animations.play(modifier_stack_ref[i].animation_name) #animations.frame = modifier_stack_ref[i].starting_frame mod_animation_sequence.clear() mod_animation_sequence.push_back(modifier_stack_ref[i].animation_name) enter_frame = modifier_stack_ref[i].starting_frame i -= 1 # if modifier_stack_ref.empty() == false: # a modifier is applied # if modifier_stack_ref[-1].animation_name != '': # the first one has an animation # if modifier_stack_ref[-1].animation_suffix: # it's a suffix type # if mod_animation_sequence.size() > 0: # the current animation is multipart (sequence > 0) # animation_index = 0 # current_animation_sequence = 0 # # Guess I don't need this one anymore # #if animations.frames.get_animation_names().has(animation_sequence[animation_index] + modifier_stack_ref[-1].animation_name): # if animations.frames.has_animation(mod_animation_sequence[animation_index] + modifier_stack_ref[-1].animation_name): # animation_suffix = modifier_stack_ref[-1].animation_name # elif modifier_stack_ref[-1].pre_append_animation == true: # it's a pre-append type # #animation_sequence.size() # print ("DEBUG: A prepend animation") # #mod_animation_sequence = animation_sequence # mod_animation_sequence.push_front(modifier_stack_ref[-1].animation_name) # else: # animations.play(modifier_stack_ref[-1].animation_name) # animations.frame = modifier_stack_ref[-1].starting_frame # return if mod_animation_sequence.size() > 0: if debug_state: print("Starting Animation: " , mod_animation_sequence[animation_index] + animation_suffix) animations.play(mod_animation_sequence[animation_index] + animation_suffix) #TODO: maybe check current animatio has this frame animations.frame = enter_frame else: print("Error! Resolved to empty animation sequence!?") return func exit() -> void: emit_signal("state_exited") # animations.disconnect("animation_finished", self, "_on_AnimatedSprite_animation_finished") return func process_input(_event: InputEvent) -> State: return null func process_frame(_delta: float) -> State: #if animation_sequence.size() > 0 and current_animation_sequence != animation_index: if mod_animation_sequence.size() > animation_index and current_animation_sequence != animation_index: #TODO: why was I doing this # if animation_index >= mod_animation_sequence.size(): # animation_index = 0 ##TODO: Add a safety check here. animations.play(mod_animation_sequence[animation_index] + animation_suffix) if debug_state: print("An animation sequence: ", mod_animation_sequence[animation_index - 1], " -> ", animations.animation , " (", animation_index, ")") current_animation_sequence = animation_index # We have no more sequence animations and the current one doesn't loop # we do this to prevent the default idle animation from playing. if animation_index >= mod_animation_sequence.size() and animations.frames.get_animation_loop( animations.animation) == false: animations.stop() # Singal based frame call. if emitter_frame_subscriptions.has(animations.frame): if emitter_frame_subscriptions[animations.frame] == animations.animation: if frame_signal_emitted == false: emit_signal("frame_reached", self.name, animations.animation, animations.frame) # Try to only so this once. frame_signal_emitted = true else: frame_signal_emitted = false return null func process_physics(_delta: float) -> State: move_actor_as_desired(_delta) return null #func _on_AnimatedSprite_animation_finished(): # if animations.frames.get_animation_loop(animations.animation) == false: # animation_index += 1 func move_actor_as_desired(delta: float): move_component.velocity.y += gravity * delta #parent.velocity = parent.move_and_slide(parent.velocity, Vector2(0, -1)) move_component.velocity.x = move_component.desired_movement_vector.x * move_speed move_component.velocity = parent.move_and_slide(move_component.velocity, Vector2(0, -1)) func push_animation_state_modifier(modifier: StateModifier): ## This function attempt to optimally place multiple modifiers in an array # in such a way where the first elements are modifiers without animation changes # the last elements are animation changes or animation suffixes. # there is some potential for performance issues at scale with this kinds of operations. # This function will grow in complexity as needed but the idea is that here is # where different modifier logic can be tested and developed. # First assure this modifer isn't already there. If it is, maybe I should reset it? if modifier_stack_ref.has(modifier) == false: modifier.enter() # call enter function of the modifier if modifier_stack_ref.size() > 0: # only bother with this if multiple modifers applied # Get the last modifier in the stack var last_modifer: StateModifier = modifier_stack_ref[-1] # If the modifier at the back and the new one are the same type, we have a problem. if last_modifer.modifier_type == modifier.modifier_type and last_modifer.modifier_type != 'None': print("WARNING: Multiple same type modifiers applying.") # Replace the modifier modifier_stack_ref.pop_back() modifier_stack_ref.push_back(modifier) else: match last_modifer.modifier_type: "None": # no special processing, push it to the front of a list modifier_stack_ref.push_front(modifier) "Exit Animation": if modifier.modifier_type == "Animation Suffix": # We place this at the back so we can still modify it maybe? modifier_stack_ref.push_back(modifier) "Animation Suffix": if modifier.modifier_type == "Exit Animation": # We have to place this one right before maybe? # Whoops! Forgot to actually do this #modifier_stack_ref.push_back(modifier) modifier_stack_ref.insert(modifier_stack_ref.size() - 1, modifier) # if last_modifer.animation_name != '': # and if an animation applies # if last_modifer.pre_append_animation == modifier.pre_append_animation: # They're the same type # if modifier.pre_append_animation == true and modifier_stack_ref[-1].animation_suffix == true: # modifier.animation_suffix # modifier_stack_ref.push_back(modifier) else: modifier_stack_ref.push_front(modifier)