class_name AnimatedSprite_StateReceiver extends AnimatedSprite export var debug_component: bool = false export var callable_state_machine :NodePath onready var current_state = StateAnimatedActor.new() export var visible_when_no_state_function :bool = true var modifier: StateModifierAnimatedActor var request_state_change: FuncRef var add_state_modifier: FuncRef 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 var _frame_switch_tracker := -1 var _index_tracker := -1 # 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') add_state_modifier = funcref(get_node(callable_state_machine),'push_state_modifier') get_node(callable_state_machine).connect("state_changed", self,"_on_state_change") get_node(callable_state_machine).connect("modifiers_updated",self,"_on_modifiers_updated") 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 #state_machine_modifiers = get_node(callable_state_machine).state_modifiers ## Not doing it this way anymore modifier is applied when one arrives by signal. #modifier = get_node(callable_state_machine).merged_animation_state_modifiers # Sprites should only have a process function # but if I have this will the sprite still animate? func _process(delta): current_state.animation_frame = frame ##TODO: Put in to try to buffer animation switches on frame change if _frame_switch_tracker != -1 and frame == _frame_switch_tracker: print ("time to switch", _frame_switch_tracker) change_animation(_frame_switch_tracker, _index_tracker) # Not sure what should be called first here. if has_method('_state_process_' + current_state.name): call('_state_process_' + current_state.name) func _on_animation_finished(): if debug_component: var foo = 2+2 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 else: change_animation(0,animation_index) ##TODO: Allow a way to stop animation even if in a looped sequence # 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 modifier: #print("hey you got one! -> ", modifier.animation_name) match modifier.modifier_type: StateModifier.TYPE.ANIMATION_SUFFIX: print("hey you got one! -> ", modifier.animation_suffix) _frame_switch_tracker = -1 _index_tracker = -1 # 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 ## TODO: this runs everytime since the modifier will apply once and stay referenced. if modifier: ##TODO: Apply the animation starting frame #modifier.animation_starting_frame match modifier.modifier_type: modifier.TYPE.ANIMATION_SUFFIX: # Check that this animation actually exists if frames.has_animation(mod_animation_sequence[animation_index] + '-' + modifier.animation_suffix): animation_suffix = modifier.animation_suffix else: push_warning("Modifier attempting to apply suffix that doesn't exist" + (mod_animation_sequence[animation_index] + '-' + modifier.animation_suffix)) modifier.TYPE.REPLACE_ANIMATION: if frames.has_animation(modifier.animation_name): mod_animation_sequence.clear() mod_animation_sequence.push_back(modifier.animation_name) enter_frame = modifier.animation_starting_frame #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) if animation_suffix != '': play(mod_animation_sequence[animation_index] + '-' + animation_suffix) else: play(mod_animation_sequence[animation_index]) ##TODO: maybe check current animation has this frame if enter_frame != 0: print ("alternate starting frame:", enter_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 before? Firgure out why? # 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 frame subscriptions like 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 # 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 theres no need to keep resetting the state ## because it is always a reference to the state machine's current_state. ## this has been working fine but could cause issues if I assume otherwise. ###### State machine if new_state is StateAnimatedActor: #Testing this. Update: It works ## Confirmed that I do neet to update the current_state with the passed state. 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.") func _on_modifiers_updated(_modifier_type :int, _modifier_action :int, _merged_modifier :StateModifier): ##TODO: There's so many things I could maybe do here but lets target the # current use case. ## ## If the signalled merged modifier is a Animation one set it if _merged_modifier is StateModifierAnimatedActor: modifier = _merged_modifier print("<<--- >> is active? ", modifier.is_active) if _modifier_type == StateModifierAnimatedActor.TYPE.ANIMATION_SUFFIX: print("A: ", animation, " F: ", frame, " -Modifier Changed Signal") # Wait for frame to finish before doing anything. #yield(self, "frame_changed") if _modifier_action == StateModifierAnimatedActor.EVENT_ID.DEACTIVATED: if frame != 0 and frame != frames.get_frame_count(animation): print ("lets change the animation suffix frame:", frame) var current_frame = frame #yield(self, "frame_changed") #while current_frame == frame: # print("waiting...") #change_animation(frame + 1 ,animation_index) _frame_switch_tracker = frame + 1 _index_tracker = animation_index