Jump to content

Recommended Posts

This is tricky, since sprite locations and character data locations don't match up perfectly, but I think I've figured it out.

 

IF VPEEK (6144 + (spritex / 8) + ((spritey / 8) * 32)) = 205 THEN
	code
END IF

 

I've divided spritex by eight, and then divided spritey by eight and then multiplied the answer by 32, to find what data is directly beneath the sprite. This is very handy for maze games, like the one I was planning to make! Probably wouldn't hurt for pathfinding, either.

  • Like 1

All right. I've noticed that your code is dependent on Boolean operands, which probably is more efficient but also leaves me struggling to understand it. How does this work? Does the AND statement work the way a logic gate would on a motherboard? In other words, two bits are compared, and the result is 0 if they're different, but 1 if they're both the same?

 

I kind of understand the basic concept, but I don't understand how that knowledge could be practically applied in a program. Where would this bit math be useful?

1 hour ago, Jess Ragan said:

All right. I've noticed that your code is dependent on Boolean operands, which probably is more efficient but also leaves me struggling to understand it. How does this work? Does the AND statement work the way a logic gate would on a motherboard? In other words, two bits are compared, and the result is 0 if they're different, but 1 if they're both the same?

 

I kind of understand the basic concept, but I don't understand how that knowledge could be practically applied in a program. Where would this bit math be useful?

 

When working in 8-bit variables you can do these for example:

 

Y = Y AND $FE     ' Removes least-significant bit. Equivalent to divide by 2, and multiply by 2.

Y = Y AND $FC     ' Removes 2 least-significant bits. Equivalent to divide by 4, and multiply by 4.

Y = Y AND $F8     ' Removes 3 least-significant bits. Equivalent to divide by 8, and multiply by 8.

 

So ARTRAG's code helps you to avoid a hefty division operation, and your code will be faster. In special if you use the routine in several places.

 

#c = (Y AND $F8) * 4     ' Removes 3 least-significant bits. Equivalent to divide by 8, and multiply by 8, after further multiplying it by 4 (8*4=32), it is the row character of your sprite.

  • Like 1
Posted (edited)

Another case where binary logic is useful could be when you want to test a number of variables to see if any of them is eg bigger than a number power of 2. 

Assume you need to  test if any among #X,#Y,#Z - unsigned words- is bigger then or equal to eg 256

This expression 

(#X or #Y or #Z) and $FF00 

will be non zero if any of them is equal or larger than 256

Edited by artrag
  • Like 1

Wait, it divides by eight, then multiplies by eight? What's the point of that? That would just return you to the number you had before you processed it. Or did you mean that AND multiplies while OR divides?

Posted (edited)

You need to get rid of the lower 3 bits of your variable.

When you divide by 2 you shift right the binary representation of the number of one bit. As your variable is integer, the bits representing the fractional part are lost.

 

Look at your original formula

(spritey / 8  ) * 32

You divide by 8 before multiplying by 32 because you need to remove the last 3 bits.

Should you invert the operations you would get the correct result

(spritey / 8) * 32 != spritey * 32 /8

 

 

Edited by artrag
7 hours ago, Jess Ragan said:

Wait, it divides by eight, then multiplies by eight? What's the point of that? That would just return you to the number you had before you processed it. Or did you mean that AND multiplies while OR divides?

For getting the screen row on the VRAM memory we need to multiply the row by 32.

 

But you don't have a row, you have a pixel coordinate. So you need to divide that pixel coordinate by 8 to get the row.

 

Instead of dividing by 8, we simply clear the lower 3 bits using AND $F8. Now it is a row number multiplied by 8. We only need to multiply by 4 (8*4 = 32) to get the same effect as x/8*32.

 

For example, your pixel y-coordinate is 93, and you want to get the byte for the row in the VRAM in this way 93 / 8 * 32 = final result.

    93 in binary is 01011101

The standard method is 93 / 8 * 32.

    93 / 8 = 11, binary is 00001011

Technically we could have seen the division as shifting to the right bit by bit.

   01011101 = 93
   00101110 = one bit shift to the right.
   00010111 = one bit shift to the right.
   00001011 = one bit shift to the right, 11

However, CVBasic currently isn't so smart to do it as shifting bit by bit, so it does a full division subroutine for this.

Now, it multiplies it by 32, CVBasic is smart enough to implement it as shifting to the left bit by bit using ADD HL,HL.

   00010110 = x2
   00101100 = x4
   01011000 = x8 multiplication
   10110000 = x16
  101100000 = x32

Notice how in all this mumble-jumble the basic bit pattern for eleven is preserved (1011).

Now it becomes logical the AND $f8 operator for optimization, doing this (93 AND $F8) * 4 = final result.

   01011101 = $5D = 93
   11111000 = $F8 = 248
   -------- = AND operation
   01011000 = The row already multipled by x8 !!! (the value is the same as in the above x8 multiplication)

So you need only to multiply by 4 to get the same value.

   10110000 = x2
  101100000 = x4

And this way you saved a very heavy division subroutine and speed up the multiplication pass.

 

Posted (edited)

Okay, so just to be absolutely sure...

 

IF VPEEK (6144 + (shotx AND $F8) + (shoty AND $F8) * 4)  = 127 THEN
    code
END IF

 

This would yield the results I'm looking for, right? Whatever is directly behind the bullet will be read, and if the character is 127, the code will be executed. shotx AND $F8 would be division by eight, and (shoty AND $F8) * 4 would be division by eight, multiplied by thirty two?

Edited by Jess Ragan
Missed a parenthesis!

This video is helping me understand how bitshifting works. It's an odd concept, but I could see how it could be useful. Also, if you put the value of the least significant bit in the position of the most significant bit after you bitshift, it works a bit like scrolling, which explains why ArtRag used Boolean math in his scrolling examples.

 

 

Still not totally getting this, I'm afraid. Using AND doesn't shift the bits over in this example; it merely removes them.
 

bitsy = 255
CLS

PRINT AT 0, "A variable that is ", bitsy
PRINT AT 64, "Becomes ", bitsy AND $FE, " bitshifted by 2"
PRINT AT 128, "Becomes ", bitsy AND $FC, " bitshifted by 4"
PRINT AT 192, "Becomes ", bitsy AND $F8, " bitshifted by 8"
PRINT AT 256, "Becomes ", (bitsy AND $F8) * 4, " with ArtRags formula"

' This just seems to remove bits, not shift the remainder over. What gives?
' Also, it's 992 with ArtRag's formula, which makes absolutely no sense

WHILE 1
WEND

 

The output is 254, 252, and 248, with 992 (!?) for the final formula. So it's doing something, but not the division I wanted.

Posted (edited)

Doing more research on this. You can shift a byte by one bit by either multiplying by 2 (the remaining bits move left), or dividing by 2 (the remaining bits move right). ArtRag's formula works in the game, but I'm still not sure how to divide shotx by eight without actually dividing shotx by eight.

Edited by Jess Ragan

Oh. Okay, see, I didn't know that. I figured there was some Boolean or Modulo or electronics math trick to make execution faster. What I decided to do was use ArtRag's code, but assign the answers to two variables to have them handy as references for the rest of the loop. I mean, yeah, it's more variables and more bytes out of the RAM, but I think I've got enough room to spare. It's like 812 bytes in total... it'd take some real work to run out of variables in a scenario like that.

  • Like 1
  • 3 months later...
On 7/3/2024 at 5:23 AM, Jess Ragan said:

This is tricky, since sprite locations and character data locations don't match up perfectly, but I think I've figured it out.

 

IF VPEEK (6144 + (spritex / 8) + ((spritey / 8) * 32)) = 205 THEN
	code
END IF

 

I've divided spritex by eight, and then divided spritey by eight and then multiplied the answer by 32, to find what data is directly beneath the sprite. This is very handy for maze games, like the one I was planning to make! Probably wouldn't hurt for pathfinding, either.

What is 205 a reference to? I thought it was the character number at that location but that doesn't seem to be it?

11 minutes ago, Lillapojkenpåön said:

What is 205 a reference to? I thought it was the character number at that location but that doesn't seem to be it?

I called that Tile ID number.  It's what picture it is pulling from out of 256 to print a 8x8 picture on the screen.

21 minutes ago, Kiwi said:

I called that Tile ID number.  It's what picture it is pulling from out of 256 to print a 8x8 picture on the screen.

I don't get it? At first I only had two characters, empty (0) and solid (1) checking if vpeek returned 1 worked fine, but now I have more characters, and checking for 1 also gives collision results for other characters, maybe it's because I'm using "or"?

 

IF cont1.down THEN
    player_y = player_y + 5
        #tile1 = VPEEK (6144 + left  + (bellow * 32))
        #tile2 = VPEEK (6144 + right + (bellow * 32))
        IF #tile1 or #tile2 = 1 THEN
            player_y = player_y - overlapDown
        END IF
END IF


EDIT:
I see it..
If #tile1 = 1
🤦‍♂️

Edited by Lillapojkenpåön

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...