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 # Movement Speed in Pixels Per Second export var move_speed: float = 60 export var move_acceleration: float = 0 export var move_speed_modifier: float = 0 export var move_modifier_move_acceleration: float = 0 export var jerk_factor: float = 0 #var adjusted_move_speed: float var jerk: float var physics_modifier :StateModifier ##TODO: Deprecate this useless fool! var speed_multiplier: float = 1.0 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 var animation_finished: 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 previous_speed_multiplier: float var modifier: StateModifier #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) #modifier = StateModifier.new() # 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 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 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 animations.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 debug_state: print("Warning!: attempting to set to non-existant index ") animation_index = 0 current_animation_sequence = animation_index if animations.frames.has_animation(mod_animation_sequence[animation_index] + animation_suffix) == false: if debug_state: print("Warning!: Animation doesn't exist! ") if enter_frame != 0: if animations.frames.get_frame_count(animations.animation) != animations.frames.get_frame_count(mod_animation_sequence[animation_index] + animation_suffix): if debug_state: print("Warning!: attempting to set a mismatched frame ") enter_frame = 0 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 enter() -> void: 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 update_animation() # Reset movespeed counters #move_component.momentum.x = move_speed_modifier jerk = 0 return func exit() -> void: emit_signal("state_exited") # animations.disconnect("animation_finished", self, "_on_AnimatedSprite_animation_finished") #modifier = null return func transfer_modifiers(exiting_state_modifier : StateModifier): if modifier == null: # We have no existing modifier applied. match exiting_state_modifier.modifier_type: exiting_state_modifier.TYPE.ANIMATION_SUFFIX: if debug_state: print("Transferring Animation Suffix") modifier = exiting_state_modifier exiting_state_modifier.TYPE.EXIT_ANIMATION: if debug_state: print("Exit Animation: well this was useless.") else: print("Insert modifier merge function here...") func process_input(_event: InputEvent) -> State: return null func process_animations(): 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(animations.frame,animation_index) modifier.TYPE.REPLACE_ANIMATION: if 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 animations.frames.get_animation_loop( animations.animation) == false: #print(animations.animation, " Animation Stopped") animations.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. 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 ##TODO: Could probably add some more checks here. # 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 func process_frame(_delta: float) -> State: 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, x_move_direction_override: float = 0): var _move_speed = move_speed var _move_speed_modifier = move_speed_modifier var _move_modifier_move_acceleration = move_modifier_move_acceleration var _move_acceleration = move_acceleration var _jerk_factor = jerk_factor var _gravity = gravity if physics_modifier: #physics_modifier.modifier_properties.jerk_factor #print(physics_modifier.name) #UiManager.debug_text = physics_modifier.name + str(round(adjusted_move_speed)) var mod_props :ModifierProperties = physics_modifier.get_modifier_properties() if mod_props.move_speed != 0 and mod_props.directional_modifier == false: _move_speed = mod_props.move_speed _move_speed_modifier += mod_props.move_speed_modifier _move_acceleration += mod_props.move_acceleration _move_modifier_move_acceleration += mod_props.move_modifier_move_acceleration _jerk_factor += mod_props.jerk_factor var help_me_not_be_dumb = '' # Allow us to bump out of halt. if _move_speed == 0 and move_component.desired_movement_vector.x != 0: _move_speed = abs(move_component.desired_movement_vector.x) # Determine or physics movement direction var current_x_velocity = move_component.velocity.x #move_component.velocity.x var move_direction = 0.0 # Determine movement direction if we have momentum if move_component.momentum.x != 0: if x_move_direction_override == 0: move_direction = sign(current_x_velocity) # if move_component.desired_movement_vector.x != 0: # # set the move direction to the desired direction # move_direction = move_component.desired_movement_vector.x # else: # # Set move direction to the transform direction # move_direction = parent.transform.x.x else: move_direction = x_move_direction_override else: # No current momentum in place if x_move_direction_override == 0: move_direction = move_component.desired_movement_vector.x else: move_direction = x_move_direction_override ## TODO: I hate that I have to do this check again. if physics_modifier: var mod_props :ModifierProperties = physics_modifier.get_modifier_properties() if mod_props.move_speed != 0 and mod_props.directional_modifier == true: # Since move_direction is always positive if sign(move_direction) == sign(mod_props.move_speed): _move_speed += mod_props.move_speed else: _move_speed -= mod_props.move_speed if sign(move_direction) == 0: move_direction = sign(mod_props.move_speed) * -1 #print("doing this? ") # Determine the maximum move speed var MAX_SPEED :float = 0 var MIN_SPEED :float = 0 if sign(_move_speed_modifier) == -1: # decreased speed modifier help_me_not_be_dumb += '-SpeedMod' # Move speed cannot go below zero with modifier applied MIN_SPEED = _move_speed + _move_speed_modifier # Poor man's clamp if MIN_SPEED < 0: MIN_SPEED = 0 MAX_SPEED = _move_speed elif sign(_move_speed_modifier) == +1: # increased speed modifier help_me_not_be_dumb += '+SpeedMod' MIN_SPEED = _move_speed MAX_SPEED = _move_speed + _move_speed_modifier else: # physics won't apply here help_me_not_be_dumb += '_Speed' # Neutral Speed MIN_SPEED = _move_speed MAX_SPEED = _move_speed # get the latest aggregate acceleration # If we have any acceleration applying if (_move_modifier_move_acceleration + _move_acceleration) != 0: # The acceleration is differant # Perhaps it would be better to trigger this on a difference in modifier but they usually go together. if abs(move_component.acceleration.x) != abs(_move_modifier_move_acceleration + _move_acceleration): if move_direction: print("Acceleration changed.", abs(move_component.acceleration.x), "-", (_move_modifier_move_acceleration + _move_acceleration)) move_component.acceleration.x = _move_modifier_move_acceleration + _move_acceleration # If we're no longer tryingg to move int the direction of our movement and momentum. if sign(current_x_velocity) != sign(move_component.desired_movement_vector.x) and move_component.momentum.x != 0: if sign(_move_speed_modifier) == -1 : # decreased speed modifier # Maybe we can compare the direction of the acceleration # The direction of the acceleration should usually be positive at this point. # when the modifier is negative. if sign(move_direction) == sign(current_x_velocity): if sign(move_component.acceleration.x) == sign(move_component.momentum.x): print("Whoh Woah") # Flip the direction of the acceleration move_component.acceleration.x *= -1 if (sign(move_component.desired_movement_vector.x) == -1 and sign(current_x_velocity) == 1) or (sign(move_component.desired_movement_vector.x) == -1 and sign(current_x_velocity) == -1): print("be more opposite") # if sign(_move_speed_modifier) == 1: # increased speed modifier # print("faster faster.") elif sign(move_component.desired_movement_vector.x) == sign(current_x_velocity) and move_component.momentum.x != 0: if sign(move_component.acceleration.x) != sign(move_component.momentum.x) and x_move_direction_override == 0: print("Step it up!") # Flip the direction of the acceleration move_component.acceleration.x *= -1 # Apply momentum and acceleration if a modifer exists if move_component.momentum.x <= 0 and _move_speed_modifier !=0: #if we're trying to move but we have no momentum applied currently #if move_component.desired_movement_vector.x != 0: if move_direction: move_component.acceleration.x = _move_modifier_move_acceleration + _move_acceleration ##TODO: I don't know where I should actually set the momentum. : if sign(_move_speed_modifier) == -1: # decreased speed modifier move_component.momentum.x = 0 elif sign(_move_speed_modifier) == +1: # increased speed modifier ##TODO: in most cases this should only be applied once. need to find a way to warn against this. move_component.momentum.x = abs(move_speed_modifier) print("momentum applied!") # Reverse the accelerations if we carry over momentum but the modifier no longer applies. if move_component.momentum.x > 0 and _move_speed_modifier == 0: if sign(move_component.acceleration.x) == sign(move_component.momentum.x): print("Whoh Woah your done.") # Flip the direction of the acceleration move_component.acceleration.x *= -1 # We're going to adjust our move speed only to the modifier move_component.momentum.x += move_component.acceleration.x * delta jerk += _jerk_factor * delta var new_move_speed :float = 0 if sign(_move_speed_modifier) == -1: # decreased speed modifier # MIN_SPEED = _move_speed + _move_speed_modifier # MAX_SPEED = _move_speed move_component.momentum.x = clamp(move_component.momentum.x, 0, abs(_move_speed_modifier)) # new_move_speed = (_move_speed + _move_speed_modifier ) + (sign(_move_speed_modifier) * -1 * move_component.momentum.x) # + jerk new_move_speed = MIN_SPEED + (sign(_move_speed_modifier) * -1 * move_component.momentum.x) # + jerk elif sign(_move_speed_modifier) == +1: # increased speed modifier # MIN_SPEED = _move_speed # MAX_SPEED = _move_speed + _move_speed_modifier move_component.momentum.x = clamp(move_component.momentum.x, 0, _move_speed_modifier ) new_move_speed = _move_speed + move_component.momentum.x # + jerk else: # physics won't apply here # move_component.acceleration.x = 0 # move_component.momentum.x = 0 # new_move_speed = _move_speed move_component.momentum.x = clamp(move_component.momentum.x, 0, MIN_SPEED ) new_move_speed = _move_speed + move_component.momentum.x # + jerk #new_move_speed = clamp(new_move_speed, MIN_SPEED, MAX_SPEED) var sim_move_speed = (MIN_SPEED + (sign(_move_speed_modifier) * -1 * move_component.momentum.x)) # if move_component.momentum.x != 0: if true: UiManager.debug_text = ( "Mod(" + str(sign(_move_speed_modifier)) + ") Dir(" + str(move_direction) + ") Vel(" + str(sign(current_x_velocity)) + ") Mov(" + str(sign(move_component.desired_movement_vector.x)) + ")\nNS:" + str(round(sim_move_speed)) + #" Z:" + str(sign(_move_speed_modifier) * -1 * move_component.momentum.x) + "\nS:" + str(round(_move_speed + _move_speed_modifier)) + ",M" + str(round(move_component.momentum.x)) + ",A" + str(round(move_component.acceleration.x)) + "\nVel:" + str(round(move_component.velocity.x)) + "Min:" + str(round(MIN_SPEED)) + ",Max:" + str(round(MAX_SPEED)) ) # str(round(jerk)) move_component.sim_velocity.x = move_direction * sim_move_speed #print(adjusted_move_speed, ",", new_move_speed, ",", jerk) #print(new_move_speed, " ", adjusted_move_speed) move_component.velocity.y += _gravity * delta #parent.velocity = parent.move_and_slide(parent.velocity, Vector2(0, -1)) #print(speed_multiplier) # move_component.velocity.x = move_component.desired_movement_vector.x * _move_speed move_component.velocity.x = move_direction * new_move_speed #move_component.velocity = parent.move_and_slide(move_component.velocity, Vector2.UP) var snap = Vector2.DOWN * 8 if move_component.velocity.y < -8: snap = Vector2.ZERO move_component.velocity = parent.move_and_slide_with_snap(move_component.velocity, snap , Vector2.UP, true)