• Godot Help
  • How to formulate Bit mask to identify hit creatures...

I have a menagerie of unique creatures in my dungeon, each allocated a 'power of 2' ID (1, 2, 4, 8 etc...) when they are killed. This ID is cumulated in a 'hit' score at each kill. I want to find out when creature 4096 and creature 8192 have been killed, irrespective of other kills. What function could I write to extract this information from the 'hit' score..? I chose this ID method thinking that a binary mask could extract these two ID's, using a binary operation such as AND, OR, XOR, but have not found much information on this topic so far. Any suggestions of GDScript for this, please..? Thanks in advance...

  • DaveTheCoder replied to this.
  • Dad3353 If (BIT_12 AND BIT_13) are set to '1' in the Hit counter:
    The Key becomes Visible

    If the integer variable hit_counter is the Hit counter:

    # untested code
    if ((hit_counter & ((1 << 12) | (1 << 13))) != 0):
        # Bits 12 and 13 of hit_counter are set.
        print_debug("Simulating the key becoming visible.")

    This if-statement should be equivalent:
    if (hit_counter & (1 << 12 | 1 << 13) != 0):
    But I like to use extra parentheses to make the order of operations unambiguous.

    Does that answer your question?

    DaveTheCoder
    Thanks for the reply; 'll look into the link you've supplied. Here's a screenshot of the creature's scoring; it's the last two in the Level 1 list I need to identify. The 'Hit' counter is set to 0 at the start, and each bug killed adds its score to this total. I need to know when these last two die so as to release a key to continue the game. Does this help..?

    The 'Hit' counter will have a value increasing from 0 to 16383 as th game progresses, I need to know when the values '4096' and '8192' have been added (indicating that these two bugs have been slain, so key has been earned...). I thought that a bit test on the 'Hit' counter could give me this information (Bit 13 and bit 12 will be set, if both are slain...).

    4096 (decimal) is 0b1000000000000 (binary), with bit 12 set.
    8192 (decimal) is 0b10000000000000 (binary), with bit 13 set.

    const BIT_12: int = 4096 # could use 1 << 12 instead
    const BIT_13: int = 8192 # could use 1 << 13 instead
    
    func is_bit_12_set(hit_counter: int) -> bool:
        return (hit_counter & BIT_12) != 0
    
    func is_bit_13_set(hit_counter: int) -> bool:
        return (hit_counter & BIT_13) != 0

    Or more generally:

    # Untested code
    # I don't know if it works if bit_number is 0, and I don't know
    # what it will do if bit_number is out of range.
    func is_bit_set(hit_counter: int, bit_number: int) -> bool:
        var bitmask: int = 1 << bit_number
        return (hit_counter & bitmask) != 0

    I must have missed something; when I call the functions,, they return simply the 'Hit' count that they received, whatever its value. Here's the code I'm running; why do I only get '512' (in this example...) as a return value, for both functions..?

    You need to do something with the function's returned value.

    var foo: bool = is_bit_12_set(hits)
    print_debug("foo=", foo)

    or

    print_debug("here it is: ", is_bit_12_set(hits))

    Dave...
    I often have these issues. Despite my many decades of programming, in various languages and systems, there are notions which I do not recognise, until I see a 'less than one syllable' example. Obviously wrong, but I thought that the function I invoked return its value in the variable passed as a parameter. Not so, here, it seems. Could you correct the function call and return of my example, please..? Here's my code: what does it need changing to..? Apologies for being obtuse, and many thanks for your time.

    func is_bit_12_set(hit_counter: int) -> bool:
    return (hit_counter & BIT_12) != 0

    func is_bit_13_set(hit_counter: int) -> bool:
    return (hit_counter & BIT_13) != 0

    func process(delta):
    frame_count += 1
    if frame_count >= 200:
    frame_count = 0
    is_bit_12_set(hits)
    print ("Bit 12 : ", hits)
    is_bit_13_set(hits)
    print ("Bit 13 : ", hits)

      Dad3353 Despite my many decades of programming, in various languages and systems, there are notions which I do not recognise, until I see a 'less than one syllable' example.

      I depend heavily on examples myself. 🙂

      Dad3353 I thought that the function I invoked return its value in the variable passed as a parameter

      Some languages support that, but not GDScript (as far as I know). The function has to return a result using the "return" keyword, or set a variable that's declared outside the function.

      Dad3353 is_bit_12_set(hits)

      That line does nothing. It's analogous to this line of code:

      3 + 4

      The line is valid, but serves no purpose. The expression is evaluated, but the result is not saved in a variable or otherwise used.

      Didn't my previous post explain how to use the functions?

      By the way, when you post code here, if you type ~~~ on lines before and after the code, the indentation will be preserved. The </> (Insert code) icon button at the bottom is not reliable for multiple lines.

      Dave...

      Didn't my previous post explain how to use the functions?

      Yes, for someone already knowing how it's done in GDScript..! ;-)

      What should my ...

      func is_bit_12_set(hit_counter: int) -> bool:
      return (hit_counter & BIT_12) != 0

      is_bit_12_set(hits)
      print ("Bit 12 : ", hits)

      ...look like (in words of less that one syllable, for three-year old child...), please. We're so nearly there; this tiny detail is going to serve me well for a long time, once the penny has dropped.

        Dad3353 is_bit_12_set(hits)
        print ("Bit 12 : ", hits)

        Explain what you want that code to do. Forget about GDScript, just use English. You could use French, Italian, etc., but I'd need to use Google translate.

        It's a 3D Dungeon, crawling with bugs. At one point, a Door needs a Key to appear to continue the game. To have the Key appear, these two (and only these two...) bugs need to die; their demise adds 4096 and 8192 to the Hit counter. The main '_physics_process' checks a 'check_exit' function to see if the conditions are met to release the Key. Whatever other bugs have been killed (and so their 'bit' set in the 'hit counter'...) it's the 'Bit 12' and 'Bit 13' which must both be set to release the Key. A test, then, is needed, to see if these two Bits are set in the 'Hit counter'. In plain English, the test would be...

        If (BIT_12 AND BIT_13) are set to '1' in the Hit counter:
        The Key becomes Visible

        ... and the Player is able to open the Door.
        The Total Sum of all the bugs killed is tested to open another Door, allowing access to the next Dungeon Level, but I don't need Bit testing for that, only a test on the decimal sum of kills (16383...), indicating that all bugs of this Level have been killed.
        Is that what you're asking for..? Thanks for your patience.

          Dad3353 If (BIT_12 AND BIT_13) are set to '1' in the Hit counter:
          The Key becomes Visible

          If the integer variable hit_counter is the Hit counter:

          # untested code
          if ((hit_counter & ((1 << 12) | (1 << 13))) != 0):
              # Bits 12 and 13 of hit_counter are set.
              print_debug("Simulating the key becoming visible.")

          This if-statement should be equivalent:
          if (hit_counter & (1 << 12 | 1 << 13) != 0):
          But I like to use extra parentheses to make the order of operations unambiguous.

          Does that answer your question?

          Dave...

          This last 'untested code' did the trick, once I'd found where and how to put it into my function. I found that writing and reading Global Variables using a local affectation such as...

          var leve_hit_coun = GlobalVariables.hits_leve_1

          ... does not work well (for me...), but when I use the full 'GlobalVariables.hits_leve_1' everywhere, it works as expected. I seem to have some issues using this 'local' affectation pointing to Global variables, but that's another issue I'll have to think about for a while.
          To sum up, my reading of the individual binary bits of a decimal variable is now solved, and I even imagine that I understand it, too..!
          Thanks again; here's a screenshot of the Dungeon level nearing completion...

          Have a great day.

            Dad3353 I seem to have some issues using this 'local' affectation pointing to Global variables, but that's another issue I'll have to think about for a while.

            It's likely an issue with order of initialization, which can be tricky in Godot.

            GlobalVariables.hits_leve_1 might not have been initialized yet when this declaration is processed:
            var leve_hit_coun = GlobalVariables.hits_leve_1