From a591d9d94b17dac5a2ec546b481c1d42b3292537 Mon Sep 17 00:00:00 2001 From: Dustin Date: Sat, 8 Mar 2025 09:54:01 -0800 Subject: [PATCH] Setup project, bring over some source files as libraries --- Main.tscn | 3 + assets | 0 icon.png | Bin 0 -> 3305 bytes icon.png.import | 35 ++ lib/classes/actor.gd | 84 ++++ lib/classes/state.gd | 34 ++ lib/classes/state_animated_actor.gd | 453 ++++++++++++++++++ lib/classes/state_machine.gd | 50 ++ lib/classes/state_machine_animated_actor.gd | 126 +++++ lib/classes/state_modifier.gd | 133 +++++ lib/classes/state_modifier_properties.gd | 28 ++ lib/components/GenericReceiver.gd | 26 + lib/components/GenericReceiver.tscn | 6 + lib/components/GenericSender.gd | 41 ++ lib/components/GenericSender.tscn | 11 + lib/components/Health_Component.gd | 26 + lib/components/Health_Component.tscn | 6 + lib/components/Hitbox_Component.gd | 18 + lib/components/Hitbox_Component.tscn | 10 + lib/components/Hurtbox_Component.gd | 45 ++ lib/components/Hurtbox_Component.tscn | 6 + lib/components/Modifier_Component.gd | 52 ++ lib/components/Modifier_Component.tscn | 9 + lib/components/Modifier_Receiver.gd | 53 ++ lib/components/Modifier_Receiver.tscn | 6 + lib/singleton_autoloads/LevelInfo.gd | 13 + lib/singleton_autoloads/PlayerInfo.gd | 17 + lib/singleton_autoloads/UIManager.gd | 26 + lib/templates/Actor/ActorTemplate.tscn | 99 ++++ lib/templates/Actor/resources/Smiley.png | Bin 0 -> 508 bytes .../Actor/resources/Smiley.png.import | 35 ++ lib/templates/Actor/states/fall.gd | 19 + lib/templates/Actor/states/idle.gd | 30 ++ lib/templates/Actor/states/move.gd | 21 + .../Interactable/Interactable_Component.gd | 48 ++ .../Interactable/Interactable_Component.tscn | 9 + .../Interactable/Interactable_Receiver.gd | 48 ++ project.godot | 145 ++++++ 38 files changed, 1771 insertions(+) create mode 100644 Main.tscn create mode 100644 assets create mode 100644 icon.png create mode 100644 icon.png.import create mode 100644 lib/classes/actor.gd create mode 100644 lib/classes/state.gd create mode 100644 lib/classes/state_animated_actor.gd create mode 100644 lib/classes/state_machine.gd create mode 100644 lib/classes/state_machine_animated_actor.gd create mode 100644 lib/classes/state_modifier.gd create mode 100644 lib/classes/state_modifier_properties.gd create mode 100644 lib/components/GenericReceiver.gd create mode 100644 lib/components/GenericReceiver.tscn create mode 100644 lib/components/GenericSender.gd create mode 100644 lib/components/GenericSender.tscn create mode 100644 lib/components/Health_Component.gd create mode 100644 lib/components/Health_Component.tscn create mode 100644 lib/components/Hitbox_Component.gd create mode 100644 lib/components/Hitbox_Component.tscn create mode 100644 lib/components/Hurtbox_Component.gd create mode 100644 lib/components/Hurtbox_Component.tscn create mode 100644 lib/components/Modifier_Component.gd create mode 100644 lib/components/Modifier_Component.tscn create mode 100644 lib/components/Modifier_Receiver.gd create mode 100644 lib/components/Modifier_Receiver.tscn create mode 100644 lib/singleton_autoloads/LevelInfo.gd create mode 100644 lib/singleton_autoloads/PlayerInfo.gd create mode 100644 lib/singleton_autoloads/UIManager.gd create mode 100644 lib/templates/Actor/ActorTemplate.tscn create mode 100644 lib/templates/Actor/resources/Smiley.png create mode 100644 lib/templates/Actor/resources/Smiley.png.import create mode 100644 lib/templates/Actor/states/fall.gd create mode 100644 lib/templates/Actor/states/idle.gd create mode 100644 lib/templates/Actor/states/move.gd create mode 100644 lib/templates/Interactable/Interactable_Component.gd create mode 100644 lib/templates/Interactable/Interactable_Component.tscn create mode 100644 lib/templates/Interactable/Interactable_Receiver.gd create mode 100644 project.godot diff --git a/Main.tscn b/Main.tscn new file mode 100644 index 0000000..70a653e --- /dev/null +++ b/Main.tscn @@ -0,0 +1,3 @@ +[gd_scene format=2] + +[node name="Main" type="Node2D"] diff --git a/assets b/assets new file mode 100644 index 0000000..e69de29 diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c98fbb601c83c81ec8c22b1dba7d1d57c62b323c GIT binary patch literal 3305 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 literal 0 HcmV?d00001 diff --git a/icon.png.import b/icon.png.import new file mode 100644 index 0000000..a4c02e6 --- /dev/null +++ b/icon.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +process/normal_map_invert_y=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/lib/classes/actor.gd b/lib/classes/actor.gd new file mode 100644 index 0000000..5e14cc1 --- /dev/null +++ b/lib/classes/actor.gd @@ -0,0 +1,84 @@ +class_name Actor +extends KinematicBody2D + +#var velocity = Vector2(0,0) +#var direction = Vector2(-1,0) + +export(String, "Player", "Enemy", "NPC", "Object") var actor_type +#export var sprite_facing_right: bool = true +export(Array, Resource) var SoundEffects +export var debug_actor: bool = false + + +onready var movement_animations: AnimatedSprite = $AnimatedSprite + +onready var sound_effect_player: AudioStreamPlayer = $SE_Player + +onready var movement_component: MovementComponent = $movement_component + +onready var movement_state_machine: StateMachineAnimatedActor = $movement_state_machine + +var sound_effects_dict: Dictionary + +##TODO: +# Can't seem to implement the ready and process node functions +# without causing a double run somehow. Not sure why. +# not a huge deal because this is mostly to help with +# interfaces for the state machines. + +func _ready() -> void: + movement_state_machine.init_animated_actor(self, movement_animations, movement_component) + movement_component.attack_function = funcref(self, "attack") +# movement_component.player_number = player_number + + # Experimenting with sound based resources I did this and it worked + #sound_effect_player.stream = sound_effects.sounds["pew"] + #print(sounds.sounds["pew"]) + #sound_effects.play() + + # Trying something new with a custom resourse. + for i in SoundEffects: + sound_effects_dict[i.animation_name + str(i.frame_number)] = i.sound + print (sound_effects_dict) + +func _unhandled_input(event: InputEvent) -> void: + if actor_type == "Player": + movement_component.process_input(event) + movement_state_machine.process_input(event) + +func _physics_process(delta: float) -> void: + movement_component.process_physics(delta) + movement_state_machine.process_physics(delta) + +func _process(delta: float) -> void: + if actor_type == "NPC" or actor_type == "Enemy": + movement_component.process(delta) + movement_state_machine.process_frame(delta) +# PlayerInfo.player_position = global_position + play_sound_frame(movement_animations.animation , movement_animations.frame) + + +var last_sound_frame_animation: String = '' +var last_sound_frame: int = -1 +func play_sound_frame(animation: String, frame: int ): + ##DEBUG: + #if animation == 'run' and frame == 6: + # print("Do the thign! (", animation + str(frame), ")", " (", last_sound_frame_animation + str(last_sound_frame), ")") + if animation != last_sound_frame_animation or frame != last_sound_frame: + last_sound_frame = frame + last_sound_frame_animation = animation + var sound_index = animation + str(frame) + if sound_effects_dict.has(sound_index): + sound_effect_player.stream = sound_effects_dict[sound_index] + sound_effect_player.play() + print(self.name, " Playing SE: ", sound_index) + +func attack(): + #print(self.name, ": It's not inheritence, it's funcrefs") + if movement_state_machine.current_state.name != 'attack': + if($movement_state_machine/attack): + movement_state_machine.change_state($movement_state_machine/attack) + if ($Hitbox_Component/CollisionShape2D): + #print(self.name, ": Found a hitbox") + var hit_box = $Hitbox_Component + hit_box.set_hitbox(true) diff --git a/lib/classes/state.gd b/lib/classes/state.gd new file mode 100644 index 0000000..640d7c1 --- /dev/null +++ b/lib/classes/state.gd @@ -0,0 +1,34 @@ +class_name State +extends Node + +export var debug_state: bool = false +export var timeout_seconds: float = 0.0 + +signal state_entered() +signal state_exited() + +# Declare member variables here. Examples: +#var modifier_stack_ref: Array # Well this didn't work +var state_timeout: Timer +var state_ready: bool = true + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +func enter() -> void: + pass + + +func exit() -> void: + pass + +func process_input(_event: InputEvent) -> State: + return null + +func process_frame(_delta: float) -> State: + return null + +func process_physics(_delta: float) -> State: + return null diff --git a/lib/classes/state_animated_actor.gd b/lib/classes/state_animated_actor.gd new file mode 100644 index 0000000..4305a91 --- /dev/null +++ b/lib/classes/state_animated_actor.gd @@ -0,0 +1,453 @@ +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) diff --git a/lib/classes/state_machine.gd b/lib/classes/state_machine.gd new file mode 100644 index 0000000..3e4a6c2 --- /dev/null +++ b/lib/classes/state_machine.gd @@ -0,0 +1,50 @@ +class_name StateMachine extends Node + +export (NodePath) var starting_state +export var debug_state_machine: bool = false + +var current_state: State +#var state_modifiers: Array + +# Initialize the state machine by giving each child state a reference to the +# parent object it belongs to and enter the default starting_state. +func init() -> void: + for child in get_children(): + if child is State: + if debug_state_machine: + print("Initializing State Node: ", child.name) +# child.modifier_stack_ref = state_modifiers + if debug_state_machine: + child.debug_state = true + + # Initialize to the default state + change_state(get_node(starting_state)) + +# Change to the new state by first calling any exit logic on the current state. +func change_state(new_state: State) -> void: + if current_state: + current_state.exit() + + current_state = new_state + current_state.enter() +# if(state_modifiers.size() > 0 and debug_state_machine): +# print("Active Modifiers:") +# for mods in state_modifiers: +# print(mods.name) + +# Pass through functions for the Player to call, +# handling state changes as needed. +func process_physics(delta: float) -> void: + var new_state = current_state.process_physics(delta) + if new_state: + change_state(new_state) + +func process_input(event: InputEvent) -> void: + var new_state = current_state.process_input(event) + if new_state: + change_state(new_state) + +func process_frame(delta: float) -> void: + var new_state = current_state.process_frame(delta) + if new_state: + change_state(new_state) diff --git a/lib/classes/state_machine_animated_actor.gd b/lib/classes/state_machine_animated_actor.gd new file mode 100644 index 0000000..cc7cf30 --- /dev/null +++ b/lib/classes/state_machine_animated_actor.gd @@ -0,0 +1,126 @@ +class_name StateMachineAnimatedActor extends StateMachine + +#var physics_modifier : StateModifier + +func change_state(new_state: State) -> void: + if new_state.state_ready == false: + # Don't transition to unready state + return + if current_state: + current_state.exit() + # Set parameters for information + if new_state is StateAnimatedActor and current_state is StateAnimatedActor: + set_previous_animation( current_state, new_state) + if current_state.modifier: # Current state has a modifier + new_state.transfer_modifiers(current_state.modifier) + current_state.modifier = null + if current_state.physics_modifier: # Current state has a physics modifier + new_state.physics_modifier = current_state.physics_modifier + current_state.physics_modifier = null + + current_state = new_state + current_state.enter() +# if(state_modifiers.size() > 0 and debug_state_machine): +# print("Active Modifiers:") +# for mods in state_modifiers: +# print(mods.name) + +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 + +# Initialize the state machine by giving each child state a reference to the +# parent object it belongs to and enter the default starting_state. +func init_animated_actor(parent: KinematicBody2D, animations: AnimatedSprite, move_component: MovementComponent) -> void: + animations.connect("animation_finished", self, "_on_AnimatedSprite_animation_finished") + for child in get_children(): + if child is StateAnimatedActor: + if debug_state_machine: + print("Initializing State Node for ", parent.name, ": ", child.name) + child.parent = parent + child.animations = animations + child.move_component = move_component +# child.modifier_stack_ref = state_modifiers + if debug_state_machine: + child.debug_state = true + + # Initialize to the default state + change_state(get_node(starting_state)) + + +func process_frame(delta: float) -> void: + # Check the state modifiers for timeouts, and maybe more conditions later + # If the modifier is no longer valid, pop it from the stack. + # We could iterate through a whole list of states but I'm not sure i want + # states to be that complex. +# var current_anim_state :StateAnimatedActor = current_state +# if state_modifiers.empty() == false: +# for i in range(state_modifiers.size()): +# # if this modifer is a timer based one +# if state_modifiers[i].state_timeout.time_left == 0 and state_modifiers[i].timeout_seconds !=0: +# # Need to do extra stuff if it's an animation based one +# if state_modifiers[i].modifier_type == "Animation Suffix": +# if debug_state_machine: +# print("State Modifier Timeout: ", state_modifiers[i].name, " -> ", state_modifiers[i].animation_name) +# # Reset animation suffix +# current_anim_state.animation_suffix = '' +# # Get the current frame of animation +# var current_frame = current_anim_state.animations.frame +# +# # Set the animation index to the current one +# current_anim_state.animation_index = current_anim_state.current_animation_sequence +# #current_anim_state.current_animation_sequence +# #current_anim_state.animations.play() +# +# current_anim_state.animations.play( +# current_anim_state.mod_animation_sequence[current_anim_state.animation_index]) +# # Try to set the current frame to the same as before. +# current_anim_state.animations.frames.frames.size() >= current_frame +# current_anim_state.animations.frame = current_frame +# +# if debug_state_machine: +# print("Pop State Modifier: ", state_modifiers[i].name) +# state_modifiers.pop_at(i) + if current_state is StateAnimatedActor: + current_state.process_animations() + var new_state = current_state.process_frame(delta) + if new_state: + change_state(new_state) + + +func _on_AnimatedSprite_animation_finished(): +# if debug_state_machine: +# print("Stop!!!!!") + ##TODO: + # It's hard to pop an exit animation off when it's stacked with another kind of animation. +# for i in state_modifiers.size(): +# if state_modifiers[i].modifier_type == "Exit Animation": +# #print("Time to pop state modifer: ", state_modifiers[i].animation_name, current_state.animation_suffix, " <-> ", current_state.animations.animation + current_state.animation_suffix) +# if (state_modifiers[i].animation_name + current_state.animation_suffix) == current_state.animations.animation: +# print("Time to pop state modifer: ", state_modifiers[i].animation_name, current_state.animation_suffix, " <-> ", current_state.animations.animation ) +# print(current_state.mod_animation_sequence) +# state_modifiers.pop_at(i) +# current_state.animation_index += 1 +# break + +# if current_state is StateAnimatedActor: +# current_state.animation_finished = true + if current_state.animations.frames.get_animation_loop( + current_state.animations.animation) == false: + #print("Stop!!!!!", current_state.animation_sequence.size(), " - ", current_state.animation_index) + if current_state.animation_sequence.size() > 0: + #print("<-- next anim.") + current_state.animation_index += 1 + if current_state.animation_index >= current_state.animation_sequence.size(): + #print("Stop!!!!!") + current_state.animation_finished = true + + + + diff --git a/lib/classes/state_modifier.gd b/lib/classes/state_modifier.gd new file mode 100644 index 0000000..a4f4761 --- /dev/null +++ b/lib/classes/state_modifier.gd @@ -0,0 +1,133 @@ +class_name StateModifier +extends Reference +## State modification +## +## A state modifier doesn't have any direct control of a game object. +## They are transfered from the enter and exit of other states and +## influence the movement or animation of their parent states. +## Rather than going full into paralell state machines I hope that this +## modifier will be suitable for a basic state machine. +## +## @WIP + +enum TYPE {NONE,EXIT_ANIMATION, ANIMATION_SUFFIX, REPLACE_ANIMATION} + +var debug_state: bool = false + +## These should be the original properties set when the modifier is created. +# property changes can be applied over time but these are the instantiated values. +var modifier_properties: ModifierProperties + +## Animation modifier variables +## The name of the animation that could be applied and starting frame +var animation_name: String +var starting_frame: int = 0 +##TODO: Animation speed + +## Modification Type +## if an animation is specified, the default behavior will be just to override +## the state animation. Or perform a 'Replace Animation' +var modifier_type = TYPE.NONE + +var name :String = '' + +# Move Speed in Pixels Per Second +# These should only apply if Modification Type Set to None. +# (But I'm not sure if I like that model.) +#var move_speed: float +#var move_speed_modifier: float = 0 +#var move_speed_modifier_decay: float = 0 + +var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity") + + +# Attempting to use this as an animation suffix that can linger after +# state transition like 'run-fire' to 'idle-fire' 'jump-fire' etc. +#var animation_suffix: bool = false +#var pre_append_animation: bool = false + +# not sure if I can do the array thing from state change. Maybe? +# disabling this sequencing for now. +# export(Array, String) var animation_sequence +# var animation_index: int = 0 +# var current_animation_sequence: int = 0 + + +#var animation_sequence_timer: Timer + +var state_timeout: Timer +var timeout_seconds: float = 0.0 + +# Meant to be called on timeout or other counters this modifier may have. +# Should be updated whenever modifier owner transfers +var state_call_function: FuncRef + +## Can't do it this way. +#func copy_modifier() -> StateModifier: +# var new_modifier = StateModifier.new() +# new_modifier.ready(animation_name, modifier_type, timeout_seconds) +# +# return StateModifier.new() +# +func merge_modifier(merging_mod: ModifierProperties): + if merging_mod.modifier_type != TYPE.NONE: + print("Warning Merging modifier types that aren't set to 'none' is not supported!") + return + # Can't support timeouts or animation stuff right now. + #timeout_seconds = merging_mod.timeout_seconds +# move_speed = merging_mod.move_speed +# gravity = merging_mod.gravity +# move_speed_modifier = merging_mod.move_speed_modifier +# move_speed_modifier_decay = merging_mod.move_speed_modifier_decay + + +func get_modifier_properties() -> ModifierProperties: + #( p_move_speed:float, p_gravity:int , p_move_acceleration , p_move_speed_modifier:float, + # p_move_modifier_move_acceleration:float, p_jerk_factor: float): + var mp = ModifierProperties.new( modifier_properties.move_speed, + modifier_properties.gravity, + modifier_properties.move_acceleration, + modifier_properties.move_speed_modifier, + modifier_properties.move_modifier_move_acceleration, + modifier_properties.jerk_factor) + mp.directional_modifier = modifier_properties.directional_modifier + return mp + +func ready(modifier_name:String, anim_name:String = '', type = TYPE.NONE, timeout : float = 0, parent:Node = null, function_name : String = "") -> Timer: + name = modifier_name + # If somebody forgot to specify the type + if anim_name != '' and type == TYPE.NONE: + modifier_type = TYPE.REPLACE_ANIMATION + animation_name = anim_name + modifier_type = type +# if parent != null and function_name != "": +# state_call_function = funcref(parent, function_name) + + modifier_properties = ModifierProperties.new(0,0,0,0,0,0) + + if timeout > 0: + state_timeout = Timer.new() + state_timeout.wait_time = timeout + state_timeout.one_shot = true + state_timeout.autostart = false + return state_timeout + #add_child(state_timeout) + #ModifierProperties.new() + return null + + +## Transfer and callback related methods. These sort of worked but I didn't end up using them +## They're an interesting idea though. +func transfer_owner(parent:Node): + print("Modifier owner will now be: ", parent.name) + state_call_function = funcref(parent, 'update_animation') + +func _on_Timer_timeout(): + #print("Oh Crap! I can't beleive it worked") + if state_call_function: + if state_call_function.is_valid(): + state_call_function.call_func() + else: + print("Warning! Modifier timed out with no callback to alert.") + else: + print("Warning! no function applies.") diff --git a/lib/classes/state_modifier_properties.gd b/lib/classes/state_modifier_properties.gd new file mode 100644 index 0000000..f90385b --- /dev/null +++ b/lib/classes/state_modifier_properties.gd @@ -0,0 +1,28 @@ +class_name ModifierProperties +extends Reference + +var modifier_type: int = 0 +#var timeout_seconds: float = 0.0 + +var move_speed: float = 0.0 +var move_acceleration: float = 0.0 +var move_speed_modifier: float = 0.0 +var move_modifier_move_acceleration: float = 0.0 +var jerk_factor: float = 0 + +var gravity:int = 0 + +# Bad name. Just means that it is intended to apply in a certain direction +# (Positive or negative) not an offset of the existing values. +var directional_modifier: bool = false + + +func _init( p_move_speed:float, p_gravity:int , p_move_acceleration , p_move_speed_modifier:float, + p_move_modifier_move_acceleration:float, p_jerk_factor: float): + #timeout_seconds = p_timeout_seconds + move_speed = p_move_speed + move_acceleration = p_move_acceleration + gravity = p_gravity + move_speed_modifier = p_move_speed_modifier + move_modifier_move_acceleration = p_move_modifier_move_acceleration + jerk_factor = p_jerk_factor diff --git a/lib/components/GenericReceiver.gd b/lib/components/GenericReceiver.gd new file mode 100644 index 0000000..3c887a4 --- /dev/null +++ b/lib/components/GenericReceiver.gd @@ -0,0 +1,26 @@ +extends Node + +export(String) var body_entered_function = "" + +var call_function: FuncRef + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + if body_entered_function: + call_function = funcref(owner, body_entered_function) + #call_function.call_func() + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + +func on_body_entered(sender): + print("Receiving call from " + sender.name) + if body_entered_function: + call_function.call_func(sender) + diff --git a/lib/components/GenericReceiver.tscn b/lib/components/GenericReceiver.tscn new file mode 100644 index 0000000..487ea0b --- /dev/null +++ b/lib/components/GenericReceiver.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/components/GenericReceiver.gd" type="Script" id=1] + +[node name="GenericReceiver" type="Node"] +script = ExtResource( 1 ) diff --git a/lib/components/GenericSender.gd b/lib/components/GenericSender.gd new file mode 100644 index 0000000..eac4802 --- /dev/null +++ b/lib/components/GenericSender.gd @@ -0,0 +1,41 @@ +extends Area2D + +export(String) var receiver_node_name = "" + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +## Called when the node enters the scene tree for the first time. +#func _ready(): +# pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + +##TODO: maybe guarantee type with receiver node type instead of just the name. +# The the name helps keep the receiver type generic. + +func _on_GenericSender_body_entered(body): + if body.has_node(receiver_node_name): + body.get_node(receiver_node_name).on_body_entered(self) + + +#func _on_Hurtbox_Component_area_shape_entered(area_rid, area, area_shape_index, local_shape_index): +# #print(area.get_parent().name, "hit", owner.name) +## if area.get_parent().has_method("gotcha"): +# print(area.get_parent().name, " you can do it.", owner.name) +# +# if owner.has_method("_on_Hurtbox_area_entered"): +# owner.call("_on_Hurtbox_area_entered") +# print(area.get_parent().name, " just hit me: ", owner.name) + + + +func _on_GenericSender_area_shape_entered(area_rid, area, area_shape_index, local_shape_index): + if area.get_parent().has_node(receiver_node_name): + area.get_parent().get_node(receiver_node_name).on_body_entered(self) + diff --git a/lib/components/GenericSender.tscn b/lib/components/GenericSender.tscn new file mode 100644 index 0000000..efbdbd8 --- /dev/null +++ b/lib/components/GenericSender.tscn @@ -0,0 +1,11 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/components/GenericSender.gd" type="Script" id=1] + +[node name="GenericSender" type="Area2D"] +collision_layer = 0 +collision_mask = 32768 +script = ExtResource( 1 ) + +[connection signal="area_shape_entered" from="." to="." method="_on_GenericSender_area_shape_entered"] +[connection signal="body_entered" from="." to="." method="_on_GenericSender_body_entered"] diff --git a/lib/components/Health_Component.gd b/lib/components/Health_Component.gd new file mode 100644 index 0000000..4090114 --- /dev/null +++ b/lib/components/Health_Component.gd @@ -0,0 +1,26 @@ +class_name HealthComponent +extends Node + +export var max_health: int = 0 +onready var health :int = max_health + + +signal health_depleted() + +func take_damage(damage_amount :int): + if damage_amount < 0: + print("ERROR: Only positive numbers in health component functions.") + health -= damage_amount + + if health <= 0: + emit_signal("health_depleted") + health = 0 + +func heal(heal_amount :int): + if heal_amount < 0: + print("ERROR: Only positive numbers in health component functions.") + return + health += heal_amount + + if health > max_health: + health = max_health diff --git a/lib/components/Health_Component.tscn b/lib/components/Health_Component.tscn new file mode 100644 index 0000000..9baee23 --- /dev/null +++ b/lib/components/Health_Component.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/components/Health_Component.gd" type="Script" id=1] + +[node name="Health_Component" type="Node"] +script = ExtResource( 1 ) diff --git a/lib/components/Hitbox_Component.gd b/lib/components/Hitbox_Component.gd new file mode 100644 index 0000000..9a50b28 --- /dev/null +++ b/lib/components/Hitbox_Component.gd @@ -0,0 +1,18 @@ +extends Area2D + +export(int) var damage_amount = 0 + +func set_hitbox(enabled: bool): + for child in get_children(): + if child is CollisionShape2D: + child.set_deferred("disabled", !enabled) + ## TODO: This breaks now I guess because I moved the process functions out to parent class + #player_hurtbox.set_deferred("disabled", !enabled) #WTF Apparently this is how to do it + + +func _on_Hitbox_Component_area_shape_entered(area_rid, area, area_shape_index, local_shape_index): + var colliding_node = area.get_parent() + if colliding_node.has_node("Hurtbox_Component"): + colliding_node.get_node("Hurtbox_Component").on_hit(self) + else: + print(owner.name, ": Attempted to Hit an unready node, no Hurtbox_Component reciever node in ", colliding_node.name) diff --git a/lib/components/Hitbox_Component.tscn b/lib/components/Hitbox_Component.tscn new file mode 100644 index 0000000..740633b --- /dev/null +++ b/lib/components/Hitbox_Component.tscn @@ -0,0 +1,10 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/components/Hitbox_Component.gd" type="Script" id=1] + +[node name="Hitbox_Component" type="Area2D"] +collision_layer = 128 +collision_mask = 0 +script = ExtResource( 1 ) + +[connection signal="area_shape_entered" from="." to="." method="_on_Hitbox_Component_area_shape_entered"] diff --git a/lib/components/Hurtbox_Component.gd b/lib/components/Hurtbox_Component.gd new file mode 100644 index 0000000..7c2a198 --- /dev/null +++ b/lib/components/Hurtbox_Component.gd @@ -0,0 +1,45 @@ +extends Area2D + +export(String) var hurtbox_entered_function = "" + +var call_function: FuncRef + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + if hurtbox_entered_function: + call_function = funcref(owner, hurtbox_entered_function) + else: + print("Warning: No hurtbox function defined on ", owner.name) + +func set_hurtbox(enabled: bool): + for child in get_children(): + if child is CollisionShape2D: + child.set_deferred("disabled", !enabled) + +# Switching to a new model that starts with Hitbox +func on_hit(sender): + print("Received hit from: " + sender.owner.name) + if hurtbox_entered_function: + call_function.call_func(sender.damage_amount) + +# This one doesn't seem to work +#func _on_Hurtbox_Component_body_entered(body): +# print(body.name, "hit", owner.name) +# if owner.has_method("gotcha"): +# print(body.name, " you can do it.", owner.name) + + +# well this one works. +#func _on_Hurtbox_Component_area_shape_entered(area_rid, area, area_shape_index, local_shape_index): +# #print(area.get_parent().name, "hit", owner.name) +## if area.get_parent().has_method("gotcha"): +# print(area.get_parent().name, " you can do it.", owner.name) +# +# if owner.has_method("_on_Hurtbox_area_entered"): +# owner.call("_on_Hurtbox_area_entered") +# print(area.get_parent().name, " just hit me: ", owner.name) diff --git a/lib/components/Hurtbox_Component.tscn b/lib/components/Hurtbox_Component.tscn new file mode 100644 index 0000000..ce0b294 --- /dev/null +++ b/lib/components/Hurtbox_Component.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/components/Hurtbox_Component.gd" type="Script" id=1] + +[node name="Hurtbox_Component" type="Area2D"] +script = ExtResource( 1 ) diff --git a/lib/components/Modifier_Component.gd b/lib/components/Modifier_Component.gd new file mode 100644 index 0000000..0e7c15a --- /dev/null +++ b/lib/components/Modifier_Component.gd @@ -0,0 +1,52 @@ +extends Area2D + + +var modifier_type = 0 + +export var modifier_name :String = '' +var animation_name: String = '' # Not using this one +var timeout_seconds: float = 0.0 # Not doing timeout based ones yet either. + +export var directional_modifier: bool = false + +export var move_speed: float = 0.0 +export var move_acceleration: float = 0.0 +export var move_speed_modifier: float = 0.0 +export var move_modifier_move_acceleration: float = 0.0 +export var jerk_factor: float = 0 + +export var gravity_modifier: int = 0 + +#var state_timeout: Timer + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +var modifier :StateModifier +#var modifier_properties: ModifierProperties + + +# Called when the node enters the scene tree for the first time. +func _ready(): + modifier = StateModifier.new() + modifier.ready( modifier_name, animation_name , modifier.TYPE.NONE, timeout_seconds) + modifier.modifier_properties = ModifierProperties.new( move_speed, + gravity_modifier, + move_acceleration, + move_speed_modifier, + move_modifier_move_acceleration, + jerk_factor) + print("Debug Direction property shy are you stopid?! ", directional_modifier) + modifier.modifier_properties.directional_modifier = directional_modifier + +func _on_Modifier_Component_body_entered(body): + var colliding_node = body + if colliding_node.has_node("Modifier_Receiver"): + colliding_node.get_node("Modifier_Receiver").register_modifier(modifier) + + +func _on_Modifier_Component_body_exited(body): + var colliding_node = body + if colliding_node.has_node("Modifier_Receiver"): + colliding_node.get_node("Modifier_Receiver").remove_modifier(modifier) diff --git a/lib/components/Modifier_Component.tscn b/lib/components/Modifier_Component.tscn new file mode 100644 index 0000000..cd6c7d0 --- /dev/null +++ b/lib/components/Modifier_Component.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/components/Modifier_Component.gd" type="Script" id=1] + +[node name="Modifier_Component" type="Area2D"] +script = ExtResource( 1 ) + +[connection signal="body_entered" from="." to="." method="_on_Modifier_Component_body_entered"] +[connection signal="body_exited" from="." to="." method="_on_Modifier_Component_body_exited"] diff --git a/lib/components/Modifier_Receiver.gd b/lib/components/Modifier_Receiver.gd new file mode 100644 index 0000000..f70a652 --- /dev/null +++ b/lib/components/Modifier_Receiver.gd @@ -0,0 +1,53 @@ +class_name Modifier_Receiver +extends Node2D + +# This may be stupid but we're going to have two kinds of callbacks here. +# It's going to be up to the parent/actor/kinematicbody2d/whatever to know +# what conditions have to be met before being able to call that interactible's +# function. +# This is a nice and generic interface that I might be able to use for +# things like opening doors in a level, opening chests/flipping switches etc. + +# This node can keep an array of various interactibles within a level +# and provide several helper functions for managing them perhaps. + +export(String) var modifier_parent_callback = "" +export var debug_receiver :bool = false + +var call_function: FuncRef + +#var interactable_function_callables = [] + +var modifier_collection = [] + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +##NOTE: +## Call function should be implemented as two parameters, one expecting a modifier +## and the other expecting a boolean as to whether its being added + +# Called when the node enters the scene tree for the first time. +func _ready(): + if modifier_parent_callback: + call_function = funcref(owner, modifier_parent_callback) + else: + print("Warning: No modifier receiver function defined on ", owner.name) + +# Switching to a new model that starts with Hitbox +func register_modifier(modifier: StateModifier): + if modifier_collection.has(modifier) == false: + print("New Modifier Registered " + modifier.name) + modifier_collection.append(modifier) + if call_function.is_valid(): + call_function.call_func(modifier, true) + +func remove_modifier(modifier): + print("Modifier Removal " + modifier.name) + if modifier_collection.has(modifier): + var modifier_index = modifier_collection.rfind(modifier) + if modifier_index != -1: + modifier_collection.remove(modifier_index) + if call_function.is_valid(): + call_function.call_func(modifier, false) diff --git a/lib/components/Modifier_Receiver.tscn b/lib/components/Modifier_Receiver.tscn new file mode 100644 index 0000000..6e0c4a3 --- /dev/null +++ b/lib/components/Modifier_Receiver.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/components/Modifier_Receiver.gd" type="Script" id=1] + +[node name="Modifier_Receiver" type="Node2D"] +script = ExtResource( 1 ) diff --git a/lib/singleton_autoloads/LevelInfo.gd b/lib/singleton_autoloads/LevelInfo.gd new file mode 100644 index 0000000..87d2e4c --- /dev/null +++ b/lib/singleton_autoloads/LevelInfo.gd @@ -0,0 +1,13 @@ +extends Node + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" +var player_start_position: Position2D + + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/lib/singleton_autoloads/PlayerInfo.gd b/lib/singleton_autoloads/PlayerInfo.gd new file mode 100644 index 0000000..c65333b --- /dev/null +++ b/lib/singleton_autoloads/PlayerInfo.gd @@ -0,0 +1,17 @@ +extends Node + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" +var player_position: Vector2 +var player_health: int + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/lib/singleton_autoloads/UIManager.gd b/lib/singleton_autoloads/UIManager.gd new file mode 100644 index 0000000..171e11d --- /dev/null +++ b/lib/singleton_autoloads/UIManager.gd @@ -0,0 +1,26 @@ +extends Node + +## This singleton sits in the middle allowing multiple game areas to call and +# manipulate the UI + +enum UI_PANES {OFF, HUD, DIALOG} + +var dialog_text = 'foo' +var dialog_portrait = preload("res://icon.png") +var current_pane = UI_PANES.OFF + +var debug_text :String + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/lib/templates/Actor/ActorTemplate.tscn b/lib/templates/Actor/ActorTemplate.tscn new file mode 100644 index 0000000..f8c863b --- /dev/null +++ b/lib/templates/Actor/ActorTemplate.tscn @@ -0,0 +1,99 @@ +[gd_scene load_steps=17 format=2] + +[ext_resource path="res://src/components/Hurtbox_Component.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/state_machine_animated_actor.gd" type="Script" id=2] +[ext_resource path="res://src/templates/Actor/states/fall.gd" type="Script" id=3] +[ext_resource path="res://src/templates/Actor/states/idle.gd" type="Script" id=4] +[ext_resource path="res://src/movement_component.gd" type="Script" id=5] +[ext_resource path="res://src/templates/Actor/resources/Smiley.png" type="Texture" id=6] +[ext_resource path="res://src/templates/Actor/states/move.gd" type="Script" id=7] +[ext_resource path="res://src/actor.gd" type="Script" id=8] + +[sub_resource type="AtlasTexture" id=76] +atlas = ExtResource( 6 ) +region = Rect2( 0, 0, 32, 32 ) + +[sub_resource type="AtlasTexture" id=77] +atlas = ExtResource( 6 ) +region = Rect2( 32, 0, 32, 32 ) + +[sub_resource type="AtlasTexture" id=78] +atlas = ExtResource( 6 ) +region = Rect2( 64, 0, 32, 32 ) + +[sub_resource type="AtlasTexture" id=79] +atlas = ExtResource( 6 ) +region = Rect2( 0, 32, 32, 32 ) + +[sub_resource type="AtlasTexture" id=80] +atlas = ExtResource( 6 ) +region = Rect2( 32, 32, 32, 32 ) + +[sub_resource type="AtlasTexture" id=81] +atlas = ExtResource( 6 ) +region = Rect2( 64, 32, 32, 32 ) + +[sub_resource type="SpriteFrames" id=75] +animations = [ { +"frames": [ SubResource( 76 ), SubResource( 77 ), SubResource( 78 ), SubResource( 79 ), SubResource( 80 ), SubResource( 81 ) ], +"loop": true, +"name": "default", +"speed": 5.0 +} ] + +[sub_resource type="CircleShape2D" id=82] + +[node name="ActorTemplate" type="KinematicBody2D"] +collision_layer = 2 +script = ExtResource( 8 ) + +[node name="AnimatedSprite" type="AnimatedSprite" parent="."] +frames = SubResource( 75 ) +frame = 3 +playing = true +flip_h = true +__meta__ = { +"_aseprite_wizard_config_": { +"layer": "", +"o_ex_p": "", +"o_folder": "res://assets", +"o_name": "", +"only_visible": true, +"op_exp": false, +"slice": "", +"source": "E:/Godot/Art/MegaMan.aseprite" +} +} + +[node name="movement_component" type="Node" parent="."] +script = ExtResource( 5 ) + +[node name="movement_state_machine" type="Node" parent="."] +script = ExtResource( 2 ) +starting_state = NodePath("idle") + +[node name="idle" type="Node" parent="movement_state_machine"] +script = ExtResource( 4 ) +animation_sequence = [ "default" ] +fall_node = NodePath("../fall") +move_node = NodePath("../move") + +[node name="fall" type="Node" parent="movement_state_machine"] +script = ExtResource( 3 ) +animation_sequence = [ "default" ] +idle_node = NodePath("../idle") + +[node name="move" type="Node" parent="movement_state_machine"] +script = ExtResource( 7 ) +animation_sequence = [ "default" ] +fall_node = NodePath("../fall") +idle_node = NodePath("../idle") + +[node name="Hurtbox_Component" parent="." instance=ExtResource( 1 )] + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Hurtbox_Component"] +modulate = Color( 1, 0, 0, 1 ) +position = Vector2( -1, 1 ) +shape = SubResource( 82 ) + +[node name="SE_Player" type="AudioStreamPlayer" parent="."] diff --git a/lib/templates/Actor/resources/Smiley.png b/lib/templates/Actor/resources/Smiley.png new file mode 100644 index 0000000000000000000000000000000000000000..88a0ca8bdfb9e5473ebfbaade72a6116f219f191 GIT binary patch literal 508 zcmVPx$wn;=mRCt{2o6T{BDuT3)hq`Qb+no1HSqoUnGyl!|ww61b*)- zi3jX}1{O{y00000fZdr2zMUJC`Evf;%08q&|KH9RE?>VTn0<}*v2@0v{i&79?);TXLC9|WN~It)^QTnI-1#eoK`=Ldr7#Fh{ckb3 ztMi}c`RMbd4Bt;H=yx^#X`YQfU&=V7KNbLJOeg@wQ_mK|C@3EKTMVOM7e6CF3;_^h z3P5aXsyTJJh)oSOr;gTsMt~RsAcg>l2?bz^Ex2+ptcIu9f+q*VYS`rWedF`LXB#$n zR=m65YiR2qaBV+(L1I6;;Ma=H1Xyb|cmP ztbD+T`|)ajaz<>_jFj4+loK8~C#&{H?+1*2K40zUV3wHR{eV|EpRe{a0>lsiF{S{F zbUt70X9S2L0AiX1pysjiqxn?bGOuO9#aI_C}r*le~xXlL&L0000 State: + #parent.velocity.y += gravity * delta + move_component.velocity.y += gravity * delta + + move_component.velocity.x = move_component.desired_movement_vector.x * move_speed + move_component.velocity = parent.move_and_slide(move_component.velocity, Vector2(0, -1)) + + if move_component.get_movement_direction() != 0.0: + parent.transform.x.x = move_component.get_movement_direction() + + if parent.is_on_floor(): + return idle_state + return null diff --git a/lib/templates/Actor/states/idle.gd b/lib/templates/Actor/states/idle.gd new file mode 100644 index 0000000..250c59c --- /dev/null +++ b/lib/templates/Actor/states/idle.gd @@ -0,0 +1,30 @@ +extends StateAnimatedActor + +export (NodePath) var fall_node +export (NodePath) var move_node + +onready var fall_state: State = get_node(fall_node) +onready var move_state: State = get_node(move_node) + +func enter() -> void: + .enter() +# parent.set_hurtbox(true) + move_component.velocity.x = 0 + if debug_state: + print(owner.name, " Move Component: ", move_component.desired_movement_vector.x) + +func process_physics(delta: float) -> State: + +# parent.velocity.y += gravity * delta +# #parent.velocity = parent.move_and_slide(parent.velocity, Vector2(0, -1)) +# parent.velocity.x = move_component.desired_movement_vector.x * move_speed +# parent.velocity = parent.move_and_slide(parent.velocity, Vector2(0, -1)) + + move_actor_as_desired(delta) + + if move_component.velocity.x != 0.0: + return move_state + + if !parent.is_on_floor(): + return fall_state + return null diff --git a/lib/templates/Actor/states/move.gd b/lib/templates/Actor/states/move.gd new file mode 100644 index 0000000..f93dab5 --- /dev/null +++ b/lib/templates/Actor/states/move.gd @@ -0,0 +1,21 @@ +extends StateAnimatedActor + +export (NodePath) var fall_node +export (NodePath) var idle_node + +onready var fall_state: State = get_node(fall_node) +onready var idle_state: State = get_node(idle_node) + +func process_physics(delta: float) -> State: + + move_actor_as_desired(delta) + + if move_component.velocity.x == 0.0: + return idle_state + + #Flip the character before tha actual move maybe. + parent.transform.x.x = move_component.get_movement_direction() + + if !parent.is_on_floor(): + return fall_state + return null diff --git a/lib/templates/Interactable/Interactable_Component.gd b/lib/templates/Interactable/Interactable_Component.gd new file mode 100644 index 0000000..32116bd --- /dev/null +++ b/lib/templates/Interactable/Interactable_Component.gd @@ -0,0 +1,48 @@ +class_name Interactable +extends Area2D + +## I'm not quite sure what to do with this yet but the idea is having an +# area2d that detects not just a body entering a certain zone but triggering an +# interract status. For a player this would probably be pressing a button. +# the component can perhaps have a prompt of some sort to indicate what they're +# supposed to do. Additionaly the interraction could perhaps trigger some +# sort of animation when the action is performed. + +# This may have to be implemented as a bi-directional mediator pattern where +# the player node is given some sort of call back upon entering the region and +# when it happens it fires off that call back. +# This means that whatever entity that is supposed to interract with these +# objects should also have a receiver function of some kind. + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +export var type_name :String + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +func trigger_interaction(): + # This is something that should maybe be extended for every differant interactible. + # They could inherit from this base class and implement this function. +# sprite.frame = 1 + pass + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + +# When a body enters this area +# We want to give that body (a player I assume) a callback or a reference to this +# Node. +func _on_Interactable_Component_body_entered(body): + var colliding_node = body + if colliding_node.has_node("Interactable_Receiver"): + colliding_node.get_node("Interactable_Receiver").register_interactable(self) + +func _on_Interactable_Component_body_exited(body): + var colliding_node = body + if colliding_node.has_node("Interactable_Receiver"): + colliding_node.get_node("Interactable_Receiver").remove_interactable(self) diff --git a/lib/templates/Interactable/Interactable_Component.tscn b/lib/templates/Interactable/Interactable_Component.tscn new file mode 100644 index 0000000..c114073 --- /dev/null +++ b/lib/templates/Interactable/Interactable_Component.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/templates/Interactable/Interactable_Component.gd" type="Script" id=2] + +[node name="Interactable_Template" type="Area2D"] +script = ExtResource( 2 ) + +[connection signal="body_entered" from="." to="." method="_on_Interactable_Component_body_entered"] +[connection signal="body_exited" from="." to="." method="_on_Interactable_Component_body_exited"] diff --git a/lib/templates/Interactable/Interactable_Receiver.gd b/lib/templates/Interactable/Interactable_Receiver.gd new file mode 100644 index 0000000..d0846aa --- /dev/null +++ b/lib/templates/Interactable/Interactable_Receiver.gd @@ -0,0 +1,48 @@ +class_name Interactable_Receiver +extends Node2D + +# This may be stupid but we're going to have two kinds of callbacks here. +# It's going to be up to the parent/actor/kinematicbody2d/whatever to know +# what conditions have to be met before being able to call that interactible's +# function. +# This is a nice and generic interface that I might be able to use for +# things like opening doors in a level, opening chests/flipping switches etc. + +# This node can keep an array of various interactibles within a level +# and provide several helper functions for managing them perhaps. + +export(String) var interactable_parent_callback = "" + +var call_function: FuncRef + +var interactable_function_callables = [] + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + if interactable_parent_callback: + call_function = funcref(owner, interactable_parent_callback) + else: + print("Warning: No interactable receiver function defined on ", owner.name) + +# Switching to a new model that starts with Hitbox +func register_interactable(sender): + print("Interactable Registered " + sender.name) + if call_function.is_valid(): + var should_register: bool = call_function.call_func(sender) + if should_register: + interactable_function_callables.append(sender) + else: + print("Interactable handled by Player") + +func remove_interactable(sender): + print("Interactable Removal " + sender.name) + if interactable_function_callables.has(sender): + var sender_index = interactable_function_callables.rfind(sender) + if sender_index != -1: + interactable_function_callables.remove(sender_index) + diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..f05cb2d --- /dev/null +++ b/project.godot @@ -0,0 +1,145 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=4 + +_global_script_classes=[ { +"base": "", +"class": "GitAPI", +"language": "NativeScript", +"path": "res://addons/godot-git-plugin/git_api.gdns" +} ] +_global_script_class_icons={ +"GitAPI": "" +} + +[application] + +config/name="Attempt 2" +run/main_scene="res://Main.tscn" +run/delta_sync_after_draw=true +run/delta_smoothing=false +boot_splash/show_image=false +config/icon="res://icon.png" + +[aseprite] + +animation/layers/exclusion_pattern="_+" +animation/layers/only_include_visible_layers_by_default=true + +[autoload] + +PlayerInfo="*res://src/singleton_autoloads/PlayerInfo.gd" +UiManager="*res://src/singleton_autoloads/UIManager.gd" +LevelInfo="*res://src/singleton_autoloads/LevelInfo.gd" + +[debug] + +shapes/collision/shape_color=Color( 1, 1, 1, 0.419608 ) + +[display] + +window/size/width=320 +window/size/height=180 +window/size/resizable=false +window/size/test_width=960 +window/size/test_height=540 +window/stretch/mode="viewport" +window/stretch/aspect="keep" + +[editor_plugins] + +enabled=PoolStringArray( "res://addons/AsepriteWizard/plugin.cfg" ) + +[gui] + +common/drop_mouse_on_gui_input_disabled=true + +[importer_defaults] + +texture={ +"flags/filter": false +} + +[input] + +ui_accept={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777221,"physical_scancode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777222,"physical_scancode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"physical_scancode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null) + ] +} +move_left_1={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"physical_scancode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null) + ] +} +move_right_1={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"physical_scancode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":15,"pressure":0.0,"pressed":false,"script":null) + ] +} +jump_1={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"physical_scancode":32,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null) + ] +} +move_left_2={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +move_right_2={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +jump_2={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":74,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +shoot_1={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":77,"physical_scancode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":2,"pressure":0.0,"pressed":false,"script":null) + ] +} +shoot_2={ +"deadzone": 0.5, +"events": [ ] +} +dash_1={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":78,"physical_scancode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"pressure":0.0,"pressed":false,"script":null) + ] +} + +[layer_names] + +2d_physics/layer_1="World" +2d_physics/layer_2="Player" +2d_physics/layer_3="Enemies" +2d_physics/layer_5="PlayerHurtbox" +2d_physics/layer_6="EnemyHurtbox" +2d_physics/layer_7="PlayerHitbox" +2d_physics/layer_8="EnemyHitbox" +2d_physics/layer_11="Climbable" +common/enable_pause_aware_picking=true +2d/default_gravity=600 + +[rendering] + +quality/driver/driver_name="GLES2" +vram_compression/import_etc=true