1

I've been attempting to make a system in which you can use an ability with 3 charges. Once you use one, Only that one will recharge, When you use another, The recharge progress from the first will go to the second one, etc. I, However, Have not been able to accomplish this.

Attempted: Using conditionals and awaits to create cooldowns based off of the amount of charges currently left

Result: Charges going above the maximum wanted amount when using charges before full recharge.

extends RigidBody2D

@export var RotationSpeed = 4.2
@export var JumpPower = 1000
@onready var jumpcount: int = 3
@onready var timerRunning: bool = false
var animationTime: float
var continue1: bool = true
var continue2: bool = true


func _ready():
    Gwobaw.Player = self
    $Sprite2D/GPUParticles2D.z_index = -5
    $Sprite2D/GPUParticles2D.emitting = true

func Jump():
    if(jumpcount > 0):
        if $RayCast2D.is_colliding():
                var enemy = $RayCast2D.get_collider()
                enemy.Health -= 100
        linear_velocity = -transform.y * JumpPower
        $Sprite2D/GPUParticles2D.emitting = true
        $Sprite2D/GPUParticles2D.z_index = -1
        jumpcount -= 1

func _process(delta):
    
    $CanvasLayer/Label.text = str(jumpcount)
    
    if Input.is_action_pressed("ui_right"):
        angular_velocity = RotationSpeed

    if Input.is_action_pressed("ui_left"):
        angular_velocity = -RotationSpeed

    if Input.is_action_just_pressed("Boost"):
        if(jumpcount == 3):
            Jump()
            await get_tree().create_timer(5).timeout
            if(continue1 == true):
                jumpcount -= 1
        elif(jumpcount == 2):
                Jump()
                continue1 = false
                await get_tree().create_timer(5).timeout
                if(continue2 == true):
                    jumpcount += 1
                    await get_tree().create_timer(5).timeout
                    jumpcount += 1
                continue1 = true
        elif(jumpcount == 1):
            continue2 = false
            Jump()
            await get_tree().create_timer(5).timeout
            jumpcount += 1
            await get_tree().create_timer(5).timeout
            jumpcount += 1
            await get_tree().create_timer(5).timeout
            jumpcount += 1
            continue2 = true

2 Answers 2

0

An alternative approach, that I often use, would be to do the bookkeeping manually with Time.get_ticks_msec() (or ..._usec() if you need it to be ultra precise).

get_ticks_msec returns how long your game has been running, in milliseconds, and maxes out at 500 million years (according to the docs). The basic idea here would be to record the time of your jump/boost, and use how long it has been since then to perform some logic like recharging in _process().

An implementation of this idea for your many-jumps mechanic could look like the following. I have set up a simple Control scene with 2 child labels, Label and Label2, for visualization. This should be very straight forward to port to your specific problem. What I've done is create an array, times_of_jumps, of length max_jumps, that keeps track of when last your 3 jumps were taken. Once a jump is ready, we change that value to a zero. This gives us the ability to then just look for a zero to decide if we can jump. In _process(), we can then check each nonzero number to see if it has been enough time to cool down.


extends Control

var max_jumps:int = 3
var jump_cooldown_ms:float = 1000
var times_of_jumps:Array = []

func _ready() -> void:
   fill_jump_array()
   displaystuff()
   
func _process(delta: float) -> void:
   if Input.is_action_just_pressed("ui_up"):
       jump()
   refill_jumps()
   displaystuff()

func fill_jump_array() -> void:
   for i in range(max_jumps):
       times_of_jumps.append(0)
   
func displaystuff() -> void:
   $Label.text = "Jump times: "+str(times_of_jumps)
   var available = 0
   for t in times_of_jumps:
       if t == 0:
           available+=1
   $Label2.text = "Jumps remaining: "+str(available)
   
func jump() -> void:
   for i in range(times_of_jumps.size()):
       if times_of_jumps[i] < 1:
           times_of_jumps[i] = Time.get_ticks_msec()
           # put your non-time-related jumping logic here
           displaystuff()
           return

func refill_jumps() -> void:
   for i in range(times_of_jumps.size()):
       if times_of_jumps[i] != 0 and (Time.get_ticks_msec() - times_of_jumps[i]) > jump_cooldown_ms:
           times_of_jumps[i] = 0
           displaystuff()

This keeps an updated track on jump times, and solves the problem of having more than allowed jumps available. Plus it does so without any of the inherent ambiguity from await.

Sign up to request clarification or add additional context in comments.

Comments

-1

If the charges are identical (I suppose?), you could just do this:

extends RigidBody2D

@export var RotationSpeed = 4.2
@export var JumpPower = 1000
@onready var maxCharges:int = 3
@onready var jumpcount: int = 3
@onready var timerRunning: bool = false
var animationTime: float
var continue1: bool = true
var continue2: bool = true

var chargeCooldownTimer:Timer = Timer.new()
var chargeCooldownDuration:float = 5.0  #  seconds


func _ready():
    Gwobaw.Player = self
    $Sprite2D/GPUParticles2D.z_index = -5
    $Sprite2D/GPUParticles2D.emitting = true
    chargeCooldownTimer.connect("timeout", self._on_recharge_jump)
    chargeCooldownTimer.one_shot = true

func _on_recharge_jump():
    if (jumpcount < maxCharges):
        jumpcount += 1

    #  check if we need to increase charges
    if (jumpcount >= maxCharges):
        #  we already have max amount of charges
        chargeCooldownTimer.stop()
    else:
        #  continue recharging
        chargeCooldownTimer.start(chargeCooldownDuration)
        

func Jump():
    if(jumpcount > 0):
        if $RayCast2D.is_colliding():
                var enemy = $RayCast2D.get_collider()
                enemy.Health -= 100
        linear_velocity = -transform.y * JumpPower
        $Sprite2D/GPUParticles2D.emitting = true
        $Sprite2D/GPUParticles2D.z_index = -1
        jumpcount -= 1

func _process(delta):
    
    $CanvasLayer/Label.text = str(jumpcount)
    
    if Input.is_action_pressed("ui_right"):
        angular_velocity = RotationSpeed

    if Input.is_action_pressed("ui_left"):
        angular_velocity = -RotationSpeed

    if Input.is_action_just_pressed("Boost"):
        if (jumpcount > 0):
            Jump();
            
            #  if this is first jump, start recharging process
            if (jumpcount == maxCharges-1):
                chargeCooldownTimer.start(chargeCooldownDuration)
        

1 Comment

How does this address the issue? Please edit your answer and explain the changes you've made to solve the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.