228 lines
8.7 KiB
GDScript3
228 lines
8.7 KiB
GDScript3
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
|
|
|