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): # Shouldn't need this anymore! # 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?") # Not sure what should be called first here. if has_method('_state_process_' + current_state.name): call('_state_process_' + current_state.name) #TODO: Not sure I want to do modifiers this way anymore #process_state_modifier() func _on_animation_finished(): 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 # TODO: Allow a way to stop animation even if in a looped sequence # 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 change_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_state_modifier(): # 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 # change_animation(frame,animation_index) # # modifier.TYPE.REPLACE_ANIMATION: # if current_state.debug_state: # print("I don't have anything for replacements yet.") # modifier = null # change_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 ("1? got the state change signal ", new_state.name) # set current state to new_state previous_state_name = old_state_name #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 if has_method('_on_state_change_' + current_state.name): call('_on_state_change_' + current_state.name) else: change_animation() #print("It's an animated Actor state!") else: push_warning("Received non animated Actor state.") #current_state = new_state