0 votes

Hey there !
I'm working on a tower defense game.
One my my tower apply a "burn" effect (Damage over a few seconds after hit)

I made a function that starts when the projectile hit the enemy, and it's working wonderful.
Custom damage, custom time, only one "debuff" at a time.
It does everything i need it to do but ONE thing :
Restart itself when hit while already having it started

I have been stuck on this for most of the day yesterday... So today i give up.
Could you help me out ?

Here is my function :

if effect_type == 1:#Debuff type 1 = damage over time
    #If hhe ALREADY affected by this debuff ?
    if statuts_1 == 0: #he is not
        var total_damage = effect_amount / effect_time #how much dmg per tick.
        for i in range(effect_time): #effect time is in "second" 10s = 10 yield 1s.
            statuts_1 = 1 #say that it's now affected.
            yield(get_tree().create_timer(1), "timeout") #our fake timer
            if i == effect_time-1: # i = end of timer. this is last tick
                statuts_1 = 0 #not affected
                print("THE END")  #done.
                #Apply dmg
                break
            else:
                print(total_damage) ### apply dmg
                #apply dmg

    else:

        print("already burning")

Im really happy with the way it works. I just can't figure out how to "restart" the process.
Should i implement a timer node ? But then if i have a "poison" debuff i'd need one timer per debuff right ?

in Engine by (184 points)

1 Answer

0 votes

So -- the design you've chosen is to have this method run continuously and never terminate until the player is done being burned. You can probably find a way to make this design work using something called the "Method Object Refactoring" but, I wouldn't recommend it

A more traditional way to handle logic like this would be something like this:

func apply_burn() -> void:
  $BurnTimer.start()

func on_BurnTimer_timeout() -> void:
  effect_time -= 1
  if effect_time <= 0:
    $BurnTimer.stop()
    print("THE END")  #done.
    # apply dmg

You only really need two small pieces of code; one to say, "Start this timer," and the other to say, "Here's what should happen once a second." Godot will handle all of the other things you wrote -- the idea of 'the timer is running' or 'the timer is not running', the idea of waiting a second, the idea of tracking the amount of milliseconds which have elapsed. The state variable you created is also encapsulated within the timer; you can just check if the timer is running. Godot does all of this, you do not need to code it.

With that said, you might be able to have a short-term band-aid fix by just doing something like effect_time += 5, right? Then if it's already in the loop, it'll stay in the loop longer?

by (176 points)

hey !
Thx for your reply. I see how the timer function is cleaner.
You explained it well.

Regarding the effect +=5 would only make it longer 5s.
So if the same tower hits the target. 5 times. thats 25s of poising.
I'd want the poison to simply "restart from 0" either by canceling the previous one and starting a new one or by updating the time ?

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.