Well, sorry for the late response, I’ve been busy and breaking my noggin against this issue, so…
I’ve done something, but I have 2 issues with it, 3 if I’m to nitpick:
1.- The method I’ve implemented doesn’t work, it does everything except dash the character, I think I implemented wrong the math inside the character, it does everything else somewhat good.
2.- The recharge of dashes occurs all at once, instead of one by one, don’t know why.
3.- I have a bajillion of variables, both exported and not, and I’m open to optimization of the code.
Without further ado, here are the blocks of code:
the dash component
class_name Dash extends Node
@export var character_capable_of_dash: CharacterBody2D
@export var dash_force: float
@export var duration_time: float
@export var time_between_dashes: float
@export var cooldown_of_dashes: float
@export var max_dash_charges: int
var has_cooldown_finished: bool = true
var does_a_dash: bool = false
var is_dashing: bool = false
var can_dash: bool = false
var dash_direction: Vector2 = Vector2.ZERO
var pause_between_timer: Timer = null
var duration_of_aplication_timer: Timer = null
var recharger_dashes_timer: Timer = null
var current_dashes: int:
set(new_value):
current_dashes = maxi(0,new_value)
func _ready():
if character_capable_of_dash == null:
return
if pause_between_timer == null:
pause_between_timer = create_timer(time_between_dashes)
if duration_of_aplication_timer == null:
duration_of_aplication_timer = create_timer(duration_time)
if recharger_dashes_timer == null:
recharger_dashes_timer = create_timer(cooldown_of_dashes)
# -> is the return tipe of the data
func create_timer( wait_time: float ) -> Timer:
var new_timer := Timer.new()
add_child(new_timer)
new_timer.wait_time = wait_time
return new_timer
func make_a_dash(_delta:float) -> void:
if is_dashing == true and current_dashes <= max_dash_charges and has_cooldown_finished == true:
check_for_dashes(_delta)
does_a_dash = true
check_for_pauses(_delta)
print("I dashed")
current_dashes += 1
dash_direction = dash_direction * dash_force
duration_of_aplication_timer.start()
await duration_of_aplication_timer.timeout
does_a_dash = false
return
func check_for_dashes(_delta:float) -> void:
if current_dashes == 0:
return
else:
while current_dashes != 0:
recharger_dashes_timer.start()
await recharger_dashes_timer.timeout
current_dashes -= 1
print("One Dash Recharged")
func check_for_pauses(_delta:float) -> void:
if does_a_dash == true:
has_cooldown_finished = false
await duration_of_aplication_timer.timeout
pause_between_timer.start()
await pause_between_timer.timeout
print("Cooldown finished")
has_cooldown_finished = true
the character code
class_name QuackyMainScript extends CharacterBody2D
#The child nodes inside
@onready var player_input = $PlayerInput
@onready var player_movement = $PlayerMovement
@onready var dash = $Dash
#A way to use the sprite to get better control,
#in this case so that the arm follows the mouse and for the flip in sprite
@export var Body: Sprite2D
@export var Arm: Sprite2D
#what happens every tick inside the program, generally 60 ticks each second
func _physics_process(delta:float) -> void:
#executes the functions in blue each tick (aprox fps)
player_input._update()
player_movement.tick(delta)
dash.make_a_dash(delta)
#conects input to velocity in Vector2
player_movement.direction = player_input.dir_movement
dash.is_dashing = player_input.dash
player_movement.direction = player_movement.direction + dash.dash_direction
#makes the arm track the mouse and rotates it so that it looks good
var mouse_position = get_global_mouse_position()
Arm.look_at(mouse_position)
Arm.rotation += deg_to_rad(270)
#flips the sprite so that it looks normal
if Body.global_position.x < mouse_position.x:
Body.flip_h = true
else:
Body.flip_h = false
movement component
class_name PlayerMovement extends Node
#it defines the character so its always != null
@export_subgroup("Character")
@export var Player: CharacterBody2D
@export var Body: Sprite2D
#our variables to adjust for the best feeling movement
@export_subgroup("Horizontal Movement")
@export var max_speed: float
@export var acceleration: float
@export var friction: float
#to match with input component and other components
var direction: Vector2 = Vector2.ZERO
#what it will send
func tick(delta : float) -> void:
#return check to avoid crashes
if Player == null:
return
#When there is input being pressed, all in Vector2 format
if direction != Vector2.ZERO:
var target_velocity = Vector2(direction * max_speed)
Player.velocity.x = move_toward(Player.velocity.x,target_velocity.x, acceleration * delta)
Player.velocity.y = move_toward(Player.velocity.y,target_velocity.y, acceleration * delta)
#When there is no input, as to simulate momentum and reduce velocity
else:
Player.velocity.x = move_toward(Player.velocity.x, 0 , friction * delta)
Player.velocity.y = move_toward(Player.velocity.y, 0, friction * delta)
Player.move_and_slide()
and input component
class_name PlayerInput extends Node
#variables for each button, meaning the variable called for each
#input, becoming true when interacted as described
#gets a vector from 0 to 1, to connect to the movement component
var dir_movement: Vector2 = Vector2.ZERO
#to connect to each component, from dashing to shooting and reloading
var start_shooting: bool = false
var stop_shoting: bool = false
var start_reloading: bool = false
var dash: bool = false
#it reads every tick if there was a change, in other words, each time
#it updates a change from false to true and viceversa it emits signal that it happened
func _update():
dir_movement = Input.get_vector("move_left","move_right","move_up","move_down")
start_shooting = Input.is_action_just_pressed("shoot")
stop_shoting = Input.is_action_just_released("shoot")
start_reloading = Input.is_action_just_pressed("reload")
dash = Input.is_action_just_pressed("dash")
Anyway, thanks for reading this beast of spaghetti code!