IGNORED

Teach me how to shorten this code if possible..

Recommended Posts

I am working on collision detection.. my game has 10 columns that it needs to check player position:

```coldet
if player0x=21 then gosub coldet2
if player0x=33 then gosub coldet2
if player0x=45 then gosub coldet2
if player0x=57 then gosub coldet2
if player0x=69 then gosub coldet2
if player0x=81 then gosub coldet2
if player0x=93 then gosub coldet2
if player0x=105 then gosub coldet2
if player0x=117 then gosub coldet2
if player0x=129 then cosub coldet2
return otherbank```

Is there a way to shorten that? Only if your player0x is one of those coordinates does it need to continue to the second part.

Share on other sites

43 minutes ago, Words Fail said:

I am working on collision detection.. my game has 10 columns that it needs to check player position:

```coldet
if player0x=21 then gosub coldet2
if player0x=33 then gosub coldet2
if player0x=45 then gosub coldet2
if player0x=57 then gosub coldet2
if player0x=69 then gosub coldet2
if player0x=81 then gosub coldet2
if player0x=93 then gosub coldet2
if player0x=105 then gosub coldet2
if player0x=117 then gosub coldet2
if player0x=129 then cosub coldet2
return otherbank```

Is there a way to shorten that? Only if your player0x is one of those coordinates does it need to continue to the second part.

I am assuming this will work

on player0x goto coldet21 coldet33 coldet45 coldet57 coldet69 coldet81 coldet93 coldet105 coldet117 coldet129
return otherbank

So if it's one of those values it'll goto something, otherwise it'll return?

Share on other sites

11 minutes ago, Words Fail said:

I am assuming this will work

on player0x goto coldet21 coldet33 coldet45 coldet57 coldet69 coldet81 coldet93 coldet105 coldet117 coldet129
return otherbank

So if it's one of those values it'll goto something, otherwise it'll return?

No, this won't work. on ... goto expects a value between 0 and whatever number, and it will goto one of the labels you provide after the "goto" depending on the value starting from 0.

One other approach to shorten the code would be to put the values it is looking for in a data statement, then loop through them to look for a match. If one is found, then do your gosub.

Something like:

```    for temp5 = 0 to 9
if player0x = my_numbers[temp5] then gosub coldet2
next

return otherbank

[...]

data my_numbers
21,33,45,57,69,81,93,105,117,129
end```

Share on other sites

9 hours ago, Words Fail said:

I am working on collision detection.. my game has 10 columns that it needs to check player position:

```coldet
if player0x=21 then gosub coldet2
if player0x=33 then gosub coldet2
if player0x=45 then gosub coldet2
if player0x=57 then gosub coldet2
if player0x=69 then gosub coldet2
if player0x=81 then gosub coldet2
if player0x=93 then gosub coldet2
if player0x=105 then gosub coldet2
if player0x=117 then gosub coldet2
if player0x=129 then cosub coldet2
return otherbank```

Is there a way to shorten that? Only if your player0x is one of those coordinates does it need to continue to the second part.

Are you sure you want to keep on checking the player0x value after one of the previous conditions has matched? It will always be false! This will only take cycles.

I haven't checked, but maybe this will be smaller and faster?

```coldet
if player0x < 21 || player0x > 129 then coldet_return
tempX = player0x - 21
coldet_check
if tempx = 0 then gosub coldet2 : goto coldet_return
tempX = tempX - 12
if tempx >= 0 then coldet_check

coldet_return
return otherbank```

Share on other sites

1 hour ago, Karl G said:

No, this won't work. on ... goto expects a value between 0 and whatever number, and it will goto one of the labels you provide after the "goto" depending on the value starting from 0.

One other approach to shorten the code would be to put the values it is looking for in a data statement, then loop through them to look for a match. If one is found, then do your gosub.

Something like:

```    for temp5 = 0 to 9
if player0x = my_numbers[temp5] then gosub coldet2
next

return otherbank

[...]

data my_numbers
21,33,45,57,69,81,93,105,117,129
end```

Thanks! Good to know I can do that for y also. I tried entering it, but it keeps giving me an error..

I see things need to be indented.. but not end statements. It says "Syntax Error: The "end" command appears to be indented."

``` data pxn
21,33,45,57,69,81,93,105,117,129
end

data pyn
18,26,34,42,50,58,66,74,82
end```

It does it no matter if I put one or two data statements. I also have it at the very end of my code in bank 3 if that's fine.

Share on other sites

1 minute ago, Al_Nafuur said:

Are you sure you want to keep on checking the player0x value after one of the previous conditions has matched?  It will always be false! This will only take cycles.

I haven't checked, but maybe this will be smaller and faster?

```coldet
if player0x < 21 || player0x > 129 then coldet_return
tempX = player0x - 21
coldet_check
if tempx = 0 then gosub coldet2 : goto coldet_return
tempX = tempX - 12
if tempx >= 0 then coldet_check

coldet_return
return otherbank```

Why would it always be false? What I have currently works.. just the chunky code I wrote takes up almost a whole 4k of code to do and a bunch of cycles.

My current code first uses a bunch (10) if then statements to check if you're at one of the possible x coordinates. Based on that it goes to another subroutine (10 of them) which each have 9 if then statements! So it looked what x pos you were at, then looks at what y pos you were at and based on that removes a pixel.

Share on other sites

7 minutes ago, Al_Nafuur said:

Are you sure you want to keep on checking the player0x value after one of the previous conditions has matched?  It will always be false! This will only take cycles.

I haven't checked, but maybe this will be smaller and faster?

```coldet
if player0x < 21 || player0x > 129 then coldet_return
tempX = player0x - 21
coldet_check
if tempx = 0 then gosub coldet2 : goto coldet_return
tempX = tempX - 12
if tempx >= 0 then coldet_check

coldet_return
return otherbank```

Also I don't think your statement would work? It's not if it's greater than 21 or less than 129.. it's if it is exactly 21, 33, 45, 57, 69, 81 93, 105, 117, or 129 is when it goes to the next subroutine.

Someone else pointed me towards data statements, which seem like a good way to go, I just haven't got it to compile with them yet.

Edited by Words Fail
Share on other sites

if you gosub in the middle of a bunch of if statements
and do a bunch of if statements you don't need to do

your numbers are (n * 12) + 21
you can subtract 21 and test for a multiple of 12
that is in range
any multiple of 12 will be a multiple of 4
you can test for a multiple of 4 by testing
for bits 0 and 1 being 0
that will immediately eliminate 3/4 of possible numbers
if you subtract 21 from a number 0..20 you get a result
in the range (256 - 21) to 255
so you can eliminate numbers > 129 - 21
divide by 4 and look for multiples of 3 (12 = 3 * 4)
you could look for numbers that are n mod 3 = 0
but probably simpler and faster to just use a lookup table

something like this (untested)

[code]
temp1 = player0x - 21

if temp1 & 3 || temp1 > 108 then skip
temp1 = temp1 / 4
if x3tbl[temp1] then gosub coldet2
skip

data x3tbl
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1
end
[/code]

edit: fixed the table

edit: Crap! ok, this time I really fixed the table..

Edited by bogax
Share on other sites

20 hours ago, Words Fail said:

Thanks! Good to know I can do that for y also. I tried entering it, but it keeps giving me an error..

I see things need to be indented.. but not end statements. It says "Syntax Error: The "end" command appears to be indented."

``` data pxn
21,33,45,57,69,81,93,105,117,129
end

data pyn
18,26,34,42,50,58,66,74,82
end```

It does it no matter if I put one or two data statements. I also have it at the very end of my code in bank 3 if that's fine.

Yes, that is correct. Everything except labels and end statements need to be indented.

Also, I think @Al_Nafuur meant to reply to me, and he is right: my suggested code should jump out of the for loop after executing the subroutine unless it's possible for there to be more than one match with your subroutine potentially getting called multiple times. If there can be only one match, then this would be better:

```    for temp5 = 0 to 9
if player0x = my_numbers[temp5] then gosub coldet2 : goto ____done_coldet2
next

____done_coldet2```

Share on other sites

Just for ROM size comparison I compiled the different variants:

• Unrolled loop is the biggest (but fastest) with only 2760 bytes of ROM space left
• @Karl G's FOR loop variant is the smallest with 2840 bytes of ROM space left
• My bB loop has 2833 bytes of ROM space left
• @bogax's variant has 2805 bytes of ROM space left

```    set smartbranching on
set optimization noinlinedata

coldet2
return

rem 2760 bytes of ROM space left
if player0x=21 then gosub coldet2 : goto coldet_skip
if player0x=33 then gosub coldet2 : goto coldet_skip
if player0x=45 then gosub coldet2 : goto coldet_skip
if player0x=57 then gosub coldet2 : goto coldet_skip
if player0x=69 then gosub coldet2 : goto coldet_skip
if player0x=81 then gosub coldet2 : goto coldet_skip
if player0x=93 then gosub coldet2 : goto coldet_skip
if player0x=105 then gosub coldet2 : goto coldet_skip
if player0x=117 then gosub coldet2 : goto coldet_skip
if player0x=129 then gosub coldet2
coldet_skip
return

rem 2840 bytes of ROM space left
for temp5 = 0 to 9
if player0x = my_numbers[temp5] then gosub coldet2 : goto coldet1_return
next
coldet1_return
return

data my_numbers
21,33,45,57,69,81,93,105,117,129
end

rem 2833 bytes of ROM space left
if player0x < 21 || player0x > 129 then coldet_return
temp1 = player0x - 21
coldet_check
if temp1 = 0 then gosub coldet2 : goto coldet_return
temp1 = temp1 - 12
if temp1 >= 0 then coldet_check

coldet_return
return

rem 2805 bytes of ROM space left
temp1 = player0x - 21

if temp1 & 3 || temp1 > 108 then skip
temp1 = temp1 / 4
if x3tbl[temp1] then gosub coldet2
skip
return

data x3tbl
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1
end

```

Share on other sites

27 minutes ago, Al_Nafuur said:

Unrolled loop is the biggest (but fastest) with only 2760 bytes of ROM space left

you would do all 10 if statements for most numbers

Share on other sites

8 minutes ago, bogax said:

you would do all 10 if statements for most numbers

Compared to my and @Karl G's code the unrolled loop is surely faster. Your code might have a good chance to be faster in an "worse case" scenario, but on average?

I do not prevent anyone from cycle counting🤣

Share on other sites

21 minutes ago, bogax said:

After further investigation of your code, it appears to me that this is indeed the fastest solution.

Share on other sites

On 12/5/2022 at 7:51 AM, bogax said:

if you gosub in the middle of a bunch of if statements
and do a bunch of if statements you don't need to do

your numbers are (n * 12) + 21
you can subtract 21 and test for a multiple of 12
that is in range
any multiple of 12 will be a multiple of 4
you can test for a multiple of 4 by testing
for bits 0 and 1 being 0
that will immediately eliminate 3/4 of possible numbers
if you subtract 21 from a number 0..20 you get a result
in the range (256 - 21) to 255
so you can eliminate numbers > 129 - 21
divide by 4 and look for multiples of 3 (12 = 3 * 4)
you could look for numbers that are n mod 3 = 0
but probably simpler and faster to just use a lookup table

something like this (untested)

[code]
temp1 = player0x - 21

if temp1 & 3 || temp1 > 108 then skip
temp1 = temp1 / 4
if x3tbl[temp1] then gosub coldet2
skip

data x3tbl
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1
end
[/code]

edit: fixed the table

edit: Crap! ok, this time I really fixed the table..

Thanks. I see your comparison in the other post and it appears this one leaves with the most space left. I can compile with your code, I just can't understand the code in my head. Because that's only X checking, now I need to make up the code to check for Y as well.  Based on the player X, Y position it'll do a pfread to see if that pixel is on. If it's on it turns it off (and the one next to it) and does a PFHLINE to get rid of two pixels. It then does a c=c-1 (that's the factor that determines your level is complete).

``` .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
................................
................................
.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX..
................................
.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX..
................................
.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX..
................................
.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX..
................................
.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX..
................................
.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX..
................................
.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX..
................................
.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX..
................................
.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX..
................................
................................
.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
................................
end```

That's an example playfield.. ignore the top and bottom row of XXXXXXX's.. those are borders.. I may have them in the final game or I may not. I really wanted side borders also, but it's not possible because it needs to be a different color than the middle XX's. Unless I just chalk it up to only one color. Anyway, the XX in the middle, those are all the possible locations of what you can run over.  There's spaces between the border and the actual playfield because the two lines look stupid next to each other. So the blocks you run over are only drawn in those XX locations and only in sets of two. When you run over them they both disappear using a PFHLINE command.

For example, here's my long ass code for getting rid of the top two XX:

```coldet
if player0x=21 then gosub col1```

... etc etc for each possible X. Then:

```col1
if player0y=18 then pfhline 1 3 2 off```

.. etc etc for each possible Y and I have a Google Spreadsheet wioth all the numbers so I could easily figure out what to turn off. Basically it's y position 3, 5, 7, 9, 11, 13, 15, 17, 19.. every other line.

Then it returns to the other bank. That code takes up a whole freakin 4k bank and leaves me with 73 bytes. Which I don't need (at the moment) but would be nice to have if I need later.

I also have no code currently for pfread, which will determine if the pixel is on or off.

Share on other sites

While I have people's attention.. I forget, is there some code I should run at the beginning of my game to kind of clear shit?

Earlier when I started my game it always started with a black background.. I have COLUBK = \$00.  I don't know why, but sometimes my game starts with a random colored background. I just started the game red background, brown background, purple blackground, black FINALLY, then peach background, then peach again.

I find if I put COLUBK into my mainloop it is always black, though. So I guess that's my answer for now.

Share on other sites

25 minutes ago, Words Fail said:

While I have people's attention.. I forget, is there some code I should run at the beginning of my game to kind of clear shit?

That shouldn't be necessary. bB games do an assembly routine at the beginning to have a clean start and be in a predictable state.

26 minutes ago, Words Fail said:

Earlier when I started my game it always started with a black background.. I have COLUBK = \$00.  I don't know why, but sometimes my game starts with a random colored background. I just started the game red background, brown background, purple blackground, black FINALLY, then peach background, then peach again.

That's very odd. That shouldn't happen, and I don't have any theories offhand other than in general it's probably a case of code you added since then not doing what you intended. You can probably get an idea of when it happens though with the Stella debugger. I can give details if you want to dig into it further.

Share on other sites

The more usual way is to check for a player-playfield collision and then convert player coordinates to playfield coordinates and use pfpixel

Share on other sites

9 minutes ago, bogax said:

The more usual way is to check for a player-playfield collision and then convert player coordinates to playfield coordinates and use pfpixel

Depends on your needs. Seems like it will not work for me. It's pixel perfect, meaning the front of my player touches the block it disappears. That's wrong. In mine you have to fly over the block to make it disappear, thus if you turn around mid flight because something is shooting at you or something, then the block does not disappear. That's how I have it setup and currently working.

Share on other sites

28 minutes ago, Karl G said:

That shouldn't be necessary. bB games do an assembly routine at the beginning to have a clean start and be in a predictable state.

That's very odd. That shouldn't happen, and I don't have any theories offhand other than in general it's probably a case of code you added since then not doing what you intended. You can probably get an idea of when it happens though with the Stella debugger. I can give details if you want to dig into it further.

It all started when I tried to do this effect as seen in the attached post below. I downloaded it as a test, and ran it. Works fine. I added it to my code and it screwed things up, which I later found out you need the VBLANK function to be in the kernel bank, I guess bank1. Anyway, I removed the code and even reverted to an older version of my code. Now whenever I start the game I have no clue what the background color will be lol. Sometimes it's black 5 times in a row, sometimes multicolored and I won't see black for a few. Anyway putting COLUBK in my loop solved that.

Share on other sites

1 hour ago, Words Fail said:

It all started when I tried to do this effect as seen in the attached post below. I downloaded it as a test, and ran it. Works fine. I added it to my code and it screwed things up, which I later found out you need the VBLANK function to be in the kernel bank, I guess bank1. Anyway, I removed the code and even reverted to an older version of my code. Now whenever I start the game I have no clue what the background color will be lol. Sometimes it's black 5 times in a row, sometimes multicolored and I won't see black for a few. Anyway putting COLUBK in my loop solved that.

The kernel bank is the last bank, actually, so vblank needs to be defined there. Same goes for any included minikernels if you use any. I'm pretty confident that that is the cause of the weirdness.

Edit: I missed that you said you removed the code in question, so that may not explain why you are encountering issues now.

Share on other sites

a variant of Karl G's for loop

```  if (temp1 & 3) <> 1 then skip
for temp1 = 21 to 129 step 12
if player0x = temp1 then gosub coldet2 goto skip
next
skip```

Share on other sites

I saw someone on here had code to draw the playfield using data statements. I wonder if that is something I should look into. The data statements would define the initial level. If you run over something that has a one it would change it to zero, and also change my variable so it knows when the level is complete.

Share on other sites

5 hours ago, Words Fail said:

I saw someone on here had code to draw the playfield using data statements. I wonder if that is something I should look into. The data statements would define the initial level. If you run over something that has a one it would change it to zero, and also change my variable so it knows when the level is complete.

As it is now, the playfield is stored in RAM. The default 11 rows are in var0 - var43, and can be manipulated directly there (but see the manual for bit order). If you defined it in a data statement it would instead be in ROM and couldn't be changed.

Share on other sites

Just came back to working on this after a few days break. I have no idea how to proceed because it confuses me. I started working on trimming down my code a bit.. not sure if it all works yet,  but I still don't know how to pfread the player0x/player0y coordinate.

Someone suggested I can skip a bunch of code by not going over certain code if it doesn't need to.. good catch..

It's after midnight now, so I have to sleep, but I'll post some code tomorrow to try and figure this player0xy to pfread coordinate tomorrow.

Share on other sites

On 12/6/2022 at 9:36 PM, Words Fail said:

Depends on your needs. Seems like it will not work for me. It's pixel perfect, meaning the front of my player touches the block it disappears. That's wrong. In mine you have to fly over the block to make it disappear, thus if you turn around mid flight because something is shooting at you or something, then the block does not disappear. That's how I have it setup and currently working.

Couldn’t you just do the pfread conversions but define a temp variable depending on which direction you are going to add or subtract to the value so that the block doesn’t disappear until fully over it?

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.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.