class_name AnimatedSprite_StateReceiver extends AnimatedSprite # Declare member variables here. Examples: # var a = 2 # var b = "text" export var callable_state_machine :NodePath onready var current_state = StateAnimatedActor.new() var animation_finished: bool = false var request_state_change: FuncRef # 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 previous_animation_name : String var previous_state_frame_number : int var previous_state_name: String var previous_speed_multiplier: float # Called when the node enters the scene tree for the first time. func _ready(): request_state_change = funcref(get_node(callable_state_machine), 'change_to_known_state') get_node(callable_state_machine).connect("state_changed", self,"_on_state_change") self.connect("animation_finished",self,"_on_animation_finished") #set current state since State machine might have set state before this # processed current_state = get_node(callable_state_machine).current_state # Sprites should only have a process function # but if I have this will the sprite still animate? func _process(delta): if current_state.state_timeout != null: if current_state.state_timeout.time_left == 0: print("You're out of time! I saw it!") request_state_change.call_func('idle') #play() else: print("what, no current_state?") if has_method('_state_process_' + current_state.name): call('_state_process_' + current_state.name) process_animations() func _on_animation_finished(): #Disabling for now: if frames.get_animation_loop(animation) == false: #print("Stop!!!!!", current_state.animation_sequence.size(), " - ", current_state.animation_index) if current_state.animation_sequence.size() > 0: #print("<-- next anim.") animation_index += 1 if animation_index >= current_state.animation_sequence.size(): #print("Stop!!!!!") current_state.animation_finished = true # Called every frame. 'delta' is the elapsed time since the previous frame. #func _process(delta): # pass # If called, this will attempt to make the most appropriate animation change # would likely be triggered from an animation sequence finishing or a # modifier being applied/removed outside of enter/exit transitions. func update_animation(enter_frame := 0, index := 0, suffix := ''): ## TODO: # Need to find a way to attempt to keep and transfer the Index or frame # # if clear_modifier: # print("Goodbye Modifiers!") # modifier = null # if modifier: # if modifier.state_timeout and modifier.timeout_seconds == 0: # modifier = null # By Default, we build an animation sequence off of this state's before checking # for modifiers var animation_sequence = current_state.animation_sequence #var animations = current_state mod_animation_sequence.clear() mod_animation_sequence.append_array(animation_sequence) # Reset animation suffix in case there isn't one animation_suffix = suffix animation_index = index current_animation_sequence = animation_index #var enter_animation = '' #var enter_frame = 0 var modifier :StateModifier = current_state.modifier if modifier != null: # if modifier.modifier_type == modifier.TYPE.EXIT_ANIMATION: # #print("OHHH Modifier Applies! ", modifier.animation_name) # mod_animation_sequence.push_front(modifier.animation_name) # enter_frame = modifier.starting_frame match modifier.modifier_type: modifier.TYPE.EXIT_ANIMATION: mod_animation_sequence.push_front(modifier.animation_name) enter_frame = modifier.starting_frame modifier.TYPE.ANIMATION_SUFFIX: if frames.has_animation(mod_animation_sequence[animation_index] + modifier.animation_name): animation_suffix = modifier.animation_name else: print("Warning!: Modifier attempting to apply suffix that doesn't exist ", mod_animation_sequence[animation_index] + modifier.animation_name) modifier.TYPE.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.animation_name) enter_frame = modifier.starting_frame # Some safety checks with supplied update parameters if animation_index != 0: if mod_animation_sequence.size() < animation_index + 1: if current_state.debug_state: print("Warning!: attempting to set to non-existant index ") animation_index = 0 current_animation_sequence = animation_index if frames.has_animation(mod_animation_sequence[animation_index] + animation_suffix) == false: if current_state.debug_state: print("Warning!: Animation doesn't exist! ") if enter_frame != 0: if frames.get_frame_count(animation) != frames.get_frame_count(mod_animation_sequence[animation_index] + animation_suffix): if current_state.debug_state: print("Warning!: attempting to set a mismatched frame ") enter_frame = 0 if mod_animation_sequence.size() > 0: if current_state.debug_state: print("Starting Animation: " , mod_animation_sequence[animation_index] + animation_suffix) play(mod_animation_sequence[animation_index] + animation_suffix) #TODO: maybe check current animatio has this frame frame = enter_frame else: print("Error! Resolved to empty animation sequence!?") return func process_animations(): var modifier :StateModifier = current_state.modifier if modifier != null: if modifier.state_timeout and modifier.state_timeout.time_left == 0: print("Expired Modifier, updating animation.") #modifier = null match modifier.modifier_type: modifier.TYPE.ANIMATION_SUFFIX: # Attempt to seemlessly transition animations. modifier = null update_animation(frame,animation_index) modifier.TYPE.REPLACE_ANIMATION: if current_state.debug_state: print("I don't have anything for replacements yet.") modifier = null update_animation() _: modifier = null return # We have no more sequence animations and the current one doesn't loop # we do this to prevent the default idle animation from playing. ##TODO: between this and the signal based iterator I get some really strange behavior if animation_index >= mod_animation_sequence.size() and frames.get_animation_loop( animation) == false: #print(animations.animation, " Animation Stopped") stop() #animation_finished = true elif 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. play(mod_animation_sequence[animation_index] + animation_suffix) if current_state.debug_state: print("An animation sequence: ", mod_animation_sequence[animation_index - 1], " -> ", animation , " (", animation_index, ")") current_animation_sequence = animation_index ##TODO: Could probably add some more checks here. # Singal based frame call. #TODO: reimplement this later. # 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 func set_previous_animation( old_state: StateAnimatedActor, new_state: StateAnimatedActor ) -> void: # added this to help prevent nul index crashes. (Usually because of signal based state changes.) if old_state.mod_animation_sequence: 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 new_state.previous_speed_multiplier = old_state.speed_multiplier #animation_name :String, frame_number : int, animation_sequence :Array return # Handle state change from subscribed state machine. #From signal state_changed(old_state_name, new_state) func _on_state_change(old_state_name:String, new_state :State): print ("got the state change signal ", new_state.name) # set current state to new_state #TODO: Confirm that this is a reference to the state in the ###### State machine if new_state is StateAnimatedActor: #Testing this. Update: It works current_state = new_state update_animation() print("It's an animated Actor state!") else: push_warning("Received non animated Actor state.") #current_state = new_state