What types are those variables? I don't think any cast is necessary.

In fact, you are dividing by the same value. It works the same if you do this:

if global.score > prevScore:

But actually the logic is incorrect, you probably want to do this:

if global.score - prevScore > global.extraLifeEvery:

flossythesheep Wouldn't it be simpler to just explicitly declare your score tracking variable(s) as float? Then you needn't worry about any of this.

They shouldn't be float, it's just logic that makes no sense.

  • xyz replied to this.

    cybereality The logic looks fine to me assuming it's part of the code that increments the score and prevScore holds the score before the increment. It checks if score went over a threshold for the next extra life. It's sill somewhat bug prone because it doesn't properly handle the edge case of large increments where you can get multiple extra lives at once.

    Imho it's always better to keep the score as a float value (and only display it as an integer) because you never know what type of scoring calculations you may need to implement down the line. For example, if something is initially worth 1 point and you later decide to add some mechanic that can give the player a temporary +75% score boost, that score is now 1.75 and integer score tracking wouldn't accumulate the score properly.

    So to make this bulletproof, I'd track the score in an explicitly declared float variable, display it as a rounded int and do the extra life check like this:

    var extra_lives = int(global.score/global.extraLifeEvery) - int(prevScore/global.extraLifeEvery)
    while extra_lives > 0:
    	# add extra life here
    	extra_lives -= 1

    Handles multiple extra lives properly and no integer division warnings.

    Ok I withdraw my previous post, the int() casting is needed, I just got lost in a type conversion sprial of doom 🙂

    So the comparison is a threshold detection. So every X points it is awarding an extra life. It is called every time the player scores anything.

    So given the following and say the player scores 10 points:
    global.extraLifeEvery = 1000
    prevScore = 999 # The score before the points were added
    global.score = 1009 # The current score (prevScore plus the 10 points scored)

    current factor = 1009 / 1000 = 1.009 int(1)
    previous factor = 999 / 1000 = 0.999 int(0)

    I cant use just the float value because current factor will always be greater than previous factor. So casting it to an integer gives it in steps of global.extraLifeEvery.

    int(currentFactor) > int(previousFactor)
    AddExtraLife

    As Godot loses any fractional part of an integer division naturally I could just do no casting, however that presents exactly the problem of the OP. Godot will flag two warning messages.
    To avoid the warnings (because the ignore doesn't work) casting to a float is required, but then I need to cast back to int to get the stepping type value.

    if int(float(global.score) / global.extraLifeEvery)) > int(float(prevScore) / global.extraLifeEvery)):

    Hope this all makes sense.

    • xyz replied to this.

      This still makes no sense. Let's say you have an equation:

      A / X < B / X

      That's the same as:

      A < B

      The X on both sides cancel out.

        cybereality This still makes no sense. Let's say you have an equation:
        A / X < B / X
        That's the same as:
        A < B
        The X on both sides cancel out.

        Strictly mathematically speaking it's not an equation but an inequality. You can't cancel inequalities the same way as equations because if X is a negative number then dividing both sides by X switches the inequality around.

        In this specific case it's not the same when you round/cast both sides to integers (or do integer divisions). This is exactly the point here, as @flossythesheep elaborated in their last post, to determine if X goes into A more times than it goes into B.

        cybereality Your right if you have that equation and they are all floats, but it is ignoring what godot does with an integer division (loses its fractional component) which creates the equivalent of:

        int(A/X) < int(B/X)
        Which is not the same as
        A < B

        I think I confused the situation in my type casting rabbit hole when I mistakenly thought I could get rid of the int cast in that line.

        @xyz That is a good call there, although I hadn't planned on the niche case of crossing multiple thresholds, ya never know

        Thanks all for your help here, much appreciated. At least I can move on without those warnings and a better system, happy times.

        Do whatever you want if you don't want help. Still makes no sense.

        Okay, so I'm kind of upset that neither of you are actually reading any of my posts, when I'm trying to help. But I'll try to explain this for a 5 year old and then I'm done here.

        My understanding is that global.extraLifeEvery is a value that indicated how many points you need to get an extra life (like 100 coins in Mario). So let us say that value is 100.

        The global.score is your current score, and prevScore is the last score since you last got an extra life. Let's say that the current score is 350 and the previous score is 200 (since we are giving extra lives every 100 points).

        Your logic is this:

        if int(float(global.score) / global.extraLifeEvery)) > int(float(prevScore) / global.extraLifeEvery)):

        If we plug in the numbers, it makes this:

        if int(float(350) / 100)) > int(float(200) / 100)):

        Now if we do the cast and division (since a float and an int will promote to float:

        if int(350.0 / 100.0)) > int(200.0 / 100.0)):
        if int(3.5) > int(2.0)):

        Cast to int:

        if 3 > 2:

        So, it's true, which is technically correct. But it's confusing and obtuse logic.

        What you are describing is a score that is above a threshold, which is the amount you need for an extra life above the previous score. Which is easily described with this inequality:

        if global.score - prevScore > global.extraLifeEvery:
        if 350 - 200 > 100:
        if 150 > 100:

        Which is true and more accurate describes what you are meaning to check for, with no unneeded division or multiple casts. Hope that makes sense.

        Please don't get upset I am reading your replies, I am just trying to explain why I don't think what you are saying will work and in this I have been quite humble in saying that hey that might be my fault. I do appreciate the time and effort you are putting into replying.

        But to respond: previous score is not the score when a life was last awarded
        So:
        Every time any points are scored (1, 10, 20 etc..) it calls addScore( points )

        Which does

        prevScore = global.score
        global.score += points
        
        if(the offending condition):
          awardExtralife

        That is called every time 'any' points are awarded, so prevScore tracks one point award behind global.score

        So the check is to track a score as it increases and add an extra life everytime it goes over a factor of global.extraLifeEvery (100, 200, 300, 400 etc.)

        If that doesn't make any more sense then please don't get stressed over it. The problem is solved and the actual routine improved so all is good.

        Okay, no problem. But you can save the previous score when you add the life, and use my logic.

        Actually, I think I thought of an easier way:

        if global.score % global.extraLifeEvery < prevScore % global.extraLifeEvery:

        @flossythesheep You should have posted the whole addScore() function so the context of your code snippet would have been apparent. With that little code we had to resort to guessing about what the prevScore actually stores. I happen to have guessed it "right" while @cybereality had a different (but also legitimate) guess so that was the point of confusion.

        flossythesheep I did try multiple ignore statements, and @warning_ignore("integer_division", "integer_division") but they still persisted.

        You're correct. I verified that in 4.0.3-stable and 4.1-rc2. It works in 3.5.2-stable, so it's a regression bug.
        I submitted it on the tracker: #78957

        @"cybereality" Yes tracking the previous 'threshold' step could work and yes your new solution will also work in my usage (small increments), nice, Is there still the issue of significant point jumps (more than the threshold itself) could cause it to miss the extra life? eg. life every 100 points. At 50 points score 110 points.

        @xyz The original did work (although not pretty) and the OP was purely about the warnings so didn't think I needed to, but should have done as the thread progressed to changing the actual code. My bad.

        @DaveTheCoder Thanks for confirming that

        You can use a while loop rather than an if so you can account for multiple extra lives in one frame. Or save the difference between the values before the if (so you know if it's 2 extra lives) and add that rather than 1.