• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

Imprecision of timers and working around it (Lua)

Status
Not open for further replies.

Uncle

Warcraft Moderator
Level 76
Joined
Aug 10, 2018
Messages
8,351
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:
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.
 
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.
 
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.
Back
Top