• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Imprecision of timers and working around it (Lua)

Status
Not open for further replies.

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,596
The problem is that the Reals aren't precise. Here's a simple code I made in Lua:
Lua:
local duration = 5.00

TimerStart(SomeTimer, 0.05, true, function()
    duration = duration - 0.05
    print("Duration = ", duration)
    if duration <= 0 then
        --End the timer
    end
end
end)
When I print out duration it starts out precise displaying "Duration = 5.00, 4.95, 4.90, etc..." but eventually it starts to lose precision and I begin to see "Duration = 3.999" instead of "Duration = 4.0". This is a problem if say I wanted to check when duration was equal to exactly "0.50". So how exactly would you recommend working around this?

Lua:
local counter = 100

TimerStart(SomeTimer, 0.05, true, function()
    counter = counter - 1
    print("Duration = ", counter)
    if counter == 0 then
        --End the timer
    end
end
end)
I know I can rely on Integers like in the example above but I'd rather not do this since it complicates things (especially if I want the duration to change depending on different variables).

Am I missing something? Can I get precise Reals or am I stuck with using <= and booleans and all sorts of weird tricks to check how much time has elapsed in my repeating timer?
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,208
The solution is to not use reals to meter time. Either use integers to meter ticks/cycles or use timer callbacks which run after the full duration.

Reals are 32 bit software emulated floating point numbers. They are subject to floating point error like all floating point numbers. Nothing stops one from implementing fixed point numbers using integers to meter fractional time in a way that is not subject to floating point error.
 
Level 12
Joined
Feb 22, 2010
Messages
1,115
Never accumulate real values like that. When I am making spells with some kind of duration using timers, I calculate how many timer ticks will occur first and store that value in an integer variable. For example period of your timer is 0.05 and duration of your spell is calculated as 3.42. This means 68 ticks will occur. I accumulate elapsed ticks in timer callback and finish the timer when it reaches 68.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,596
Thanks for the replies. I'll probably end up using two timers for some things.
Anyway, I realized I could still use Integers and achieve what I was trying to do:

A Damage over Time ability with a Duration that differs based on the casting unit's "Skill Duration" stat. As seen in a lot of games like Path of Exile.
Lua:
SkillDuration[source] = GetRandomReal(1.0, 2.0) 

function Ignite()
    --Configure
    local source = GetTriggerUnit()
    local target = GetSpellTargetUnit()
    local duration = 5.00 * SkillDuration[source]
    local totaldamage = 300.00 * SkillDuration[source]
    local intervals = 10

    local timerinterval = duration / intervals
    local damage = totaldamage / intervals

    TimerStart(CreateTimer(), timerinterval, true, function()
        intervals = intervals - 1
        UnitDamageTarget(source, target, damage, false, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, nil)
        if intervals == 0 then
            --destroy timer
        end
    end)     
end
end
 
Status
Not open for further replies.
Top