Unclear % operation for counting

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Hadrombolac
Prole
Posts: 6
Joined: Wed Feb 08, 2023 2:18 pm

Unclear % operation for counting

Post by Hadrombolac »

Hi there,

Finally gathered courage to enter the LÖVE comms. Been steadily learning this great framework but hit a wall and its totally destroying me.

In one of my demo projects Im trying to write a debug log for a var from update() every 3 seconds. If I try this

Code: Select all

counter = counter + dt
if (counter % 3 == 0 then
                  Print(myValue)
                  end
nothing gets printed to the console. But if I write :

Code: Select all

counter = counter + dt
If (counter % 3 >=1 & counter % 3 <=2) then
     Print(myValue)
     end
myValue gets printed to console every tick for one second.

Can someone please breake the mindbend Im in? :x
gcmartijn
Party member
Posts: 144
Joined: Sat Dec 28, 2019 6:35 pm

Re: Unclear % operation for counting

Post by gcmartijn »

I don't know if this is correct, I just copy/past your question in chatgpt.
So I can't say it is correct :(

The issue is that you're using counter % 3 == 0 which means the print statement will only be executed when counter is an exact multiple of 3. This is why it's not printing anything to the console.

However, when you use counter % 3 >= 1 & counter % 3 <= 2, you're checking if counter modulo 3 is in the range [1, 2], which happens every tick, so myValue is printed every tick for one second.

To achieve your desired behavior of printing myValue every 3 seconds, you can use a different approach like storing the time when myValue was last printed and checking if the difference between the current time and the last print time is greater than or equal to 3.
User avatar
BrotSagtMist
Party member
Posts: 657
Joined: Fri Aug 06, 2021 10:30 pm

Re: Unclear % operation for counting

Post by BrotSagtMist »

This is a floating value, you cannot extract a fixed point out of a float.
check if the timer is above 3, then print and RESET the timer to zero.
obey
User avatar
GVovkiv
Party member
Posts: 685
Joined: Fri Jan 15, 2021 7:29 am

Re: Unclear % operation for counting

Post by GVovkiv »

like this?:

Code: Select all

counter = counter + dt
if counter > 3 then
    print(myValue)
    counter = 0
end
Last edited by GVovkiv on Wed Feb 08, 2023 3:48 pm, edited 1 time in total.
User avatar
BrotSagtMist
Party member
Posts: 657
Joined: Fri Aug 06, 2021 10:30 pm

Re: Unclear % operation for counting

Post by BrotSagtMist »

Yes obviously. Maybe make it just >, the extra >= doesnt make sense.

Well i actually did extract fixed values out of floats in the past, your checking window just needs to match the delta time.
Thats a pretty hackery tho and makes only sense if you else would need 50 counters.
obey
User avatar
darkfrei
Party member
Posts: 1197
Joined: Sat Feb 08, 2020 11:09 pm

Re: Unclear % operation for counting

Post by darkfrei »

GVovkiv wrote: Wed Feb 08, 2023 3:11 pm like this?:

Code: Select all

counter = counter + dt
if counter > 3 then
    print(myValue)
    counter = 0
end

Code: Select all

local value = 3
counter = counter + dt
if counter > value then
    print(myValue)
    counter = counter - value 
end
Or with cycle if the dt is higher than value.
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
BrotSagtMist
Party member
Posts: 657
Joined: Fri Aug 06, 2021 10:30 pm

Re: Unclear % operation for counting

Post by BrotSagtMist »

Right, better catch it in case the game runs with 0.3FPS
obey
Hadrombolac
Prole
Posts: 6
Joined: Wed Feb 08, 2023 2:18 pm

Re: Unclear % operation for counting

Post by Hadrombolac »

Wow thanks a lot for such detailed responses.

I understand the counter solution without the % and have it in the code working nicely. Im just intrigued from an understanding point of view because I still dont get why the first % == 0 example doesnt print anything but the interval one does. I mean there definitely is a moment in time where the % of the counter var % 3 == 0?

@BrotSagtMist : you say above that one cant extract fixed values out of floats, but then say its a hacky solution. I presume a hacky solution would still print something to the console?

Really appreciate all the help!!
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Unclear % operation for counting

Post by pgimeno »

Hadrombolac wrote: Fri Feb 10, 2023 3:05 pmIm just intrigued from an understanding point of view because I still dont get why the first % == 0 example doesnt print anything but the interval one does. I mean there definitely is a moment in time where the % of the counter var % 3 == 0?
Very rarely, if ever. You're missing that dt is a fractional number, in the order of 0.0166667 for a 60 Hz mode, and with slight variations due to different factors. So, you depend on luck in order to hit exactly 3.0. The precision of the timer may vary from system to system, but in the worst case, the probability of hitting exactly 3.0 after 3 seconds would be in the order of 1 in ten billions.

As for the modulo operator applied to fractional numbers, it works like in these examples:

3.5 % 2 = 1.5
17.12 % 3 = 2.12
3.7 % 1 = 0.7
-0.1 % 1 = 0.9
-0.9 % 1 = 0.1
-4.9 % 1 = 0.1

Then on floats it may have additional precision problems, e.g. 17.12 % 3 is not equal to 2.12 but to 2.120000000000001. Try this for example:

Code: Select all

for t = 0, 20000, 1/60 do
  if t % 3 == 0 then print(t) end
end
That loop only prints 0.
User avatar
soulmata
Prole
Posts: 31
Joined: Sat Jan 26, 2013 8:14 am
Contact:

Re: Unclear % operation for counting

Post by soulmata »

You can use modulo like this if you are getting os.time() instead of dt, because os.time() (at least on windows and linux) returns an INT. You can also, alternatively, floor the return of love.timer.getTime(), which I think would be more compatible with other platforms where what os.time() returns may not be consistent. I use it all over the place for simple animations (things that pulse on a frequency of 0.5 or 0.33hz, for instance). For anything that needs a frequency outside of that, use a timer instead.

You don't need the function to be aware of dt in this case as it can be using only local vars, but I tend to have a ton of timers that are all global anyway all over the place.

For instance, in my current game, here is a simple piece of a minimap drawing function that makes the player's icon blink 1 time per second by using os.time() or math.floor(love.timer.getTime():

Code: Select all

            if ((mmx == smx + 1) and (mmy == smy + 1)) then -- player is here
              local t = math.floor(love.timer.getTime())
              if (t % 2 ~= 0) then
                local poX = (global.game.player.r_x * 64) - 64
                local poY = (global.game.player.r_y * 64) - 64
                love.graphics.setColor(1,1,1,1)
                love.graphics.draw(images.yellow64, mmox+poX, mmoy+poY, 0, 1, 1)
              end
            end


Another way you can do it is with a heartbeat timer. I have a global dt timer that simply flaps between 0-1 at all times, and I know that any function can read the heartbeat to do simple timing stuff:

Code: Select all

  if (heartbeatrise) then
    heartbeat = heartbeat + dt
    if (heartbeat >= 1) then 
      heartbeat, heartbeatrise = 1, false
    end
  else
    heartbeat = heartbeat - dt
    if (heartbeat <= 0) then 
      heartbeat, heartbeatrise = 0, true
    end 
  end

I use it to do things like these pulsing bars here:
https://love2d.org/imgmirrur/PLgl6C2.mp4
Endless Dark: An existential horror game written in LOVE in which you are tasked with keeping a sleeper colony ship intact.
Post Reply

Who is online

Users browsing this forum: No registered users and 9 guests