Jump to content
IGNORED

bB questions..


yuppicide

Recommended Posts

Yes, I was thinking I could write a small custom kernel that could be used in the program, probably using something like "gosub drawscreen2" to draw the screen with the second kernel. In fact, I was thinking I could write it using bB commands instead of assembly-- less efficient in terms of timing and ROM usage, but it will be easier to understand (and could always be rewritten as pure assembly later on). But I'll need to have a clear concept of what the screen should look like. I can do a simple kernel first, with an example of how to use it, and then it could be modified as needed.

Okay, here it is. Since it's written entirely in batari Basic to (hopefully) make it easier to understand, it isn't as efficient as it could be in terms of ROM or cycles-- but it works! :) The lines of the grid are drawn with the playfield, and the blocks in the grid are drawn with the background. The colors in each block are stored in a RAM table that's located where the playfield is kept in the standard kernel (unless the Superchip is used, in which case the standard kernel relocates the playfield to Superchip RAM). This is possible because the playfield never changes in the new kernel. The color table uses 25 bytes, so that leaves 23 bytes free in the playfield RAM area (var25 through var47), and of course you also have the 26 user variables (a through z). The players, missiles, and ball aren't being used in the new kernel (yet), so they're available for other things-- a cursor to show you where you are on the grid, for example, as well as a score or status display at the top or bottom of the screen. Of course, until I add the code to position and draw the sprites, they won't show up if you try to use them! :D The screen looks a little bit squashed in an emulator, but it should look closer to a square on a TV. I'm not going to try to explan it now, except I'll point out that I had to use a mirror of COLUBK in some places to get the timing to come out correctly, which is why there's a "dim COLUBKw = $2009."

 

Michael

grid_mike.bas

grid_mike.bas.bin

post-7456-1188455286_thumb.png

Link to comment
Share on other sites

I took a look at your code and am trying to understand it. Maybe I'm asking too much too early? But I thought maybe could answer some questions so I understand:

 

 

in my_drawscreen you have:

 

What is INTIM <> 0 for? I'm guessing it stands for Internal Timer or something, but I find no mention of it on the

Random Terrain website and why you should wait for it to not equal 0.

 

After that line you do:

 

WSYNC = on : VSYNC = on : WSYNC = on : WSYNC = on : WSYNC = on

VSYNC = off

 

The website states to use WSYNC at the beginning of your kernal to start at the beginning of a line. Why do you use it 4 times in this line and 2 times for

VSYNC? What does VSYNC do? I guess it stands for Vertical Sync, but there's no mention of it on the Random Terrain website. If the V in VSYNC is Vertical what

does the W in WSYNC stand for?

 

After that you have TIM64T = 46

 

What exactly does the interval timer do? Is it like a wait statement or something?

 

You have a command that says gosub my_vblank but when I goto my_Vblank the only statement after it is return?

 

Why gosub something if you're not doing anything or is it planned to have something else in that routine in the future?

 

I haven't totally understood the grid and colors drawing yet. I tried to figure it out on my own, but so far haven't got the gist (sp?) of it. I see it

draws 28 lines of something before it moves on. I see there's no drawscreen command and I thought it was required to draw a screen.

Link to comment
Share on other sites

Okay, here it is. Since it's written entirely in batari Basic to (hopefully) make it easier to understand, it isn't as efficient as it could be in terms of ROM or cycles-- but it works! :) The lines of the grid are drawn with the playfield, and the blocks in the grid are drawn with the background. The colors in each block are stored in a RAM table that's located where the playfield is kept in the standard kernel (unless the Superchip is used, in which case the standard kernel relocates the playfield to Superchip RAM). This is possible because the playfield never changes in the new kernel. The color table uses 25 bytes, so that leaves 23 bytes free in the playfield RAM area (var25 through var47), and of course you also have the 26 user variables (a through z). The players, missiles, and ball aren't being used in the new kernel (yet), so they're available for other things-- a cursor to show you where you are on the grid, for example, as well as a score or status display at the top or bottom of the screen. Of course, until I add the code to position and draw the sprites, they won't show up if you try to use them! :D The screen looks a little bit squashed in an emulator, but it should look closer to a square on a TV. I'm not going to try to explan it now, except I'll point out that I had to use a mirror of COLUBK in some places to get the timing to come out correctly, which is why there's a "dim COLUBKw = $2009."

 

Michael

 

Nice work! You've got me beat. ;) :D

Link to comment
Share on other sites

I'll probably be home tonight to do some more work on the game, but Sat/Sun/possibly Mon I might not be around.

Gonna go visit my Grandfather in the nursing home.. he's getting rehab done and hopefully will be out before

Thanksgiving. Gonna stay at my Grandmother's and we're going shopping one day.

 

Once I get things worked out and get a few levels completed I'll make an official post about it and have a test

bin for download.

Link to comment
Share on other sites

I took a look at your code and am trying to understand it. Maybe I'm asking too much too early? But I thought maybe could answer some questions so I understand:

Sure thing!

 

in my_drawscreen you have:

 

What is INTIM <> 0 for? I'm guessing it stands for Internal Timer or something, but I find no mention of it on the Random Terrain website and why you should wait for it to not equal 0.

INTIM is the interval timer. It's on the RIOT chip (RAM/Input/Output/Timer). In this case we're actually waiting for it to *equal* 0 (we keep looping-- twiddling our thumbs-- as long as it *isn't* 0). Normally you don't need to worry about using the timer in bB, although bB uses it "behind the curtains" in its canned kernels. And even if you write your own kernels (like we're doing), you don't necessarily need to use the timer. But using the timer has an important benefit, because it lets us set the timer to a certain value, then go do something else that will take an unknown length of time. When we're done doing our stuff, we come back into the kernel, watch the timer until it counts down to 0 (if that's how we want to check it-- there are actually different ways we can check it, but that's more than I want to cover right now), and then when the timer reaches 0 (or whatever) we know it's time to go onto the next part of the kernel.

 

In our new kernel (and in bB's canned kernels), there are two places where the timer is used: (1) after we finish drawing at the bottom of the screen, before it's time to do the vertical sync; and (2) after we finish the vertical sync, before it's time to start drawing at the top of the screen. The first period is called the "overscan" in Atari programming, and the second period is called the "vblank." For the most part, these two periods are when we do all of our own stuff in the program. In bB, every statement you use-- except "drawscreen," which tells bB to run the kernel subroutine-- normally runs during the "overscan." But you can also write a "vblank" subroutine, and bB will run it when it gets to the "vblank" period in the kernel. So that's why we use the timer in our new kernel-- to let us write and run our code just like normal, and then draw the screen using the new kernel, just like we would do when using one of bB's canned kernels.

 

After that line you do:

 

WSYNC = on : VSYNC = on : WSYNC = on : WSYNC = on : WSYNC = on

VSYNC = off

 

The website states to use WSYNC at the beginning of your kernal to start at the beginning of a line. Why do you use it 4 times in this line and 2 times for VSYNC? What does VSYNC do? I guess it stands for Vertical Sync, but there's no mention of it on the Random Terrain website. If the V in VSYNC is Vertical what does the W in WSYNC stand for?

"WSYNC" stands for "Wait for horizontal SYNChronization," and as you said, it causes the Atari to start at the beginning of a scan line. Actually, what it does is tell to Atari to stop the CPU from running any more code until the Atari finishes drawing the current line, and then start the CPU again as soon as the horizontal blanking begins. So let's say you have some assembly code that looks like the following:

 

; let's say the scan line is only halfway across the screen

  LDA color1; load the value that's in the color1 variable
  STA COLUBK; store it in the background color register

; the scan line is still about halfway across the screen

  STA WSYNC; this stops the CPU until the scan line finishes

; the next command will be at the start of the next line,
; instead of halfway across the line we were just drawing

  LDA color2
  STA COLUPF

I find it helpful to think of WSYNC as the video equivalent of a carriage return and line feed. It ends the current line (although the Atari and the TV will of course continue to draw the rest of the current line), and whatever comes after it will be at the beginning of the next line. So if you do a bunch of WSYNCs one after the other, it's equivalent to pressing the ENTER key several times to skip a bunch of lines before you continue typing.

 

Note that WSYNC is a "strobe" register, meaning it doesn't matter what we write to it-- the mere act of writing *anything* to it will cause it to do its thing.

 

"VSYNC" stands for "Vertical SYNChronization," which is totally different than WSYNC. VSYNC doesn't make the CPU wait for anything the way WSYNC does. And VSYNC is *not* a "strobe" register like WSYNC is. Instead, VSYNC is used to turn the vertical synchronization pulse on and off. In the NTSC video signal, the VSYNC pulse needs to be turned on and *left* on for 3 lines, then turned back off. In the PAL video signal, the VSYNC pulse needs to be turned on for 2.5 lines, then turned back off. But that's for interlaced TV signals, and for our non-interlaced Atari displays we can just turn VSYNC on for 3 lines regardless of whether we're writing an NTSC, PAL, or SECAM game. Anyway, to turn the VSYNC pulse on, we write a value of 2 to the VSYNC register. To turn VSYNC off, we write a 0 to it. It turns out that these are the same values used to turn VBLANK on and off, so I defined "on" and "off" as constants in the program to (hopefully) help make the code easier to understand:

 

   const on = 2
  const off = 0

Let's briefly take a closer look at the code you mentioned:

 

   WSYNC = on : VSYNC = on : WSYNC = on : WSYNC = on : WSYNC = on
  VSYNC = off

This tells the Atari to finish drawing whichever line it's on, then turn on the VSYNC pulse at the beginning of the next line. Then we want it to draw 3 lines while VSYNC is on, so we use three WSYNCs (like pressing ENTER 3 times). Then we can turn off VSYNC. Note that I plan on performing some other code during this time-- namely, positioning some of the sprites on the screen-- but I left that code out for now, since I'm not displaying the sprites yet.

 

As I said, WSYNC is a strobe register, so it doesn't matter what we write to it-- we could say "WSYNC=0," or "WSYNC=1," or "WSYNC=2," or "WSYNC=3," etc., all the way up to "WSYNC=255," and it would do exactly the same thing. However, if we're going to set two or more variables to the same value in bB, the code will take up less ROM and run in fewer cycles if we put them all together on the same line, so that's why I used "WSYNC=on" followed by "VSYNC=on," etc. Actually, now that I think about it, I really should have done it the following way instead:

 

   WSYNC = on : VSYNC = on : WSYNC = on : WSYNC = on
  WSYNC = off : VSYNC = off

But I'm not worried about that right now, since this code will eventually get changed, anyway, when I add the sprite positioning.

 

After that you have TIM64T = 46

 

What exactly does the interval timer do? Is it like a wait statement or something?

That's part of the INTIM stuff. The interval timer can be set to count backwards from some value X down to 0. We can set the timer using four different registers in the RIOT chip, and the register we use will determine how long each interval is, as follows:

 

TIM1T: 1 interval = 1 cycle

TIM8T: 1 interval = 8 cycles

TIM64T: 1 interval = 64 cycles

T1024T: 1 interval = 1024 cycles

 

For example, if we say "TIM8T=100," it will set the timer to a value of 100, and it will take 800 cycles (8*100) to finish counting down. It's actually a little more compilicated than that, because there are a number of factors that affect how long we'll actually end up waiting; but I won't try to explain right now.

 

For Atari programming purposes, we generally set the timer when we want to go do some things in our program while the Atari and the TV draw a certain number of lines (usually blank lines) on the screen. In the NTSC video signal, a line has 227.5 "color clocks" on it, but the Atari uses 228 color clocks per line. The Atari's CPU (the 6507) runs at a speed of 1 cycle for every 3 color clocks, so if we divide 228 color clocks per line by 3 color clocks per cycle, we get 76 cycles per line. Note that 76 cycles isn't equal to 64 cycles, but a 64-cycle interval is the closest thing the timer has to a scan line. So if we want to tell the Atari to wait for a certain number of scan lines while we go off for a while and do our own thing, we can multiple the number of lines by 76, then divide the result by 64, and that will tell us what we need to set TIM64T to. This might not be the ideal value-- we may have to adjust it by plus or minus 1, or possibly 2-- but it gives us a good approximate value to start with.

 

For an NTSC game screen, the "Stella Programmer's Guide" says to draw 3 VSYNC lines, 37 vblank lines, 192 picture lines, and 30 overscan lines. For reasons I won't try to explain, I prefer to use 3 VSYNC lines, 39 vblank lines, 192 picture lines, and 28 overscan lines. To get the 28 overscan lines, I set TIM64T to 33 (28*76/64=33.25). For 39 vblank lines, I set TIM64T to 46 (39*76/64=46.3125). Then I check my display in the z26 emulator, with the line count option turned on, to see if I'm right at 262 lines, or if I need to add or subtract any lines.

 

You have a command that says gosub my_vblank but when I goto my_Vblank the only statement after it is return?

 

Why gosub something if you're not doing anything or is it planned to have something else in that routine in the future?

That's to give you another place where you can put code if you run out of cycles in the overscan period. Any code that you put in the my_vblank subroutine will be performed automatically during each frame, without using up any of your overscan cycles. If you're using bB's canned kernels, you can do this same sort of thing, but your suroutine would be called simply "vblank" rather than "my_vblank."

 

I haven't totally understood the grid and colors drawing yet. I tried to figure it out on my own, but so far haven't got the gist (sp?) of it. I see it draws 28 lines of something before it moves on. I see there's no drawscreen command and I thought it was required to draw a screen.

I used "my_..." in all of the line label names with this kernel, so you can use one of bB's canned kernels in your program (e.g., for a title screen), but still be able to use this custom kernel as well. bB's "drawscreen" statement simply does a "JSR" (the assembly equivalent of "gosub") to the kernel, so if we want to be able to use two or more kernels, then they need to have different names than each other, and we have to use different statements to call them. So if you use the "drawscreen" statement in your program, it will call one of bB's canned kernels-- either the standard kernel or the multisprite kernel, depending on which one you've compiled with. But if you use "gosub my_drawscreen," it will call this new kernel to draw the game's grid screen.

 

As for the grid itself, I draw 7 lines of playfield for a divider, then 27 lines of mid-line background color changes for a row of blocks, then 7 more lines for the next divider, etc.

 

Michael

Link to comment
Share on other sites

program. In bB, every statement you use-- except "drawscreen," which tells bB to run the kernel subroutine-- normally runs during the "overscan." But you can also write a "vblank" subroutine, and bB will run it when it gets to the "vblank" period in the kernel. So that's why we use the timer in our new kernel-- to let us write and run our code just like normal, and then draw the screen using the new kernel, just like we would do when using one of bB's canned kernels.

 

 

So it's faster and more efficient that we can do stuff during overscreen as we as vblank as opposed to only overscan?

 

I thought today was Friday! So I'll be experimenting tonight also. Saturday is when I leave for Grandmother's.

 

What's good is in the past I had another game idea that uses a grid. This kernal might be adoptable for that also.

Edited by yuppicide
Link to comment
Share on other sites

So it's faster and more efficient that we can do stuff during overscreen as we as vblank as opposed to only overscan?

There are more lines available in vblank (39 lines) than in overscan (28 lines), so it would be a real shame to waste vblank by not doing anything. :)

 

What's good is in the past I had another game idea that uses a grid. This kernal might be adoptable for that also.

That's good!

 

I'm about to add player0 as the cursor, but if this is a one-player puzzle game, then I don't see any use for player1, the missiles, or the ball. However, I *am* going to put a score or other 6-character display at the bottom.

 

Michael

Link to comment
Share on other sites

What's good is in the past I had another game idea that uses a grid. This kernal might be adoptable for that also.
That's good!

 

My other game idea came a long time ago. Not sure how it'll play. It's called Reversi Attack. It's played like normal Reversi.. white and black player, but when you flip over a certain amount of chips in one turn your opponent gets an "attack" piece. Like maybe if you flip over 4 of your opponents pieces in one move he gets a piece. The attack piece you get is randomly given out. You must use them as soon as you get them.

 

Some attack pieces would be:

 

Tornado - place this somewhere on the board and a tornado sweeps across that line on the board randomly messing up the pieces. Some white could flip over in the tornado and turn black, some black white, some could be carried off the board by the tornado. So, this could help or hurt you.

 

Lightning - zaps one piece off the board where you specify.

 

Bomb - similar to lighting. The piece you specify will blow up, but some of the surrounding pieces could blow up also.

 

.. the last piece I thought of is Rock. I am not sure about using this one. You place it down and nobody can use that spot for the rest of the game. For instance if your opponent has a good spot or a corner you can put the Rock down and he will no longer have that spot, but from then on nobody else can use that spot. Only one Rock Attack Piece would be given out per game whereas the Tornado, Lightning, and Bomb could keep coming.

 

.. I'd have to get the game working and then play it to see if it would even be any good. It could be a one or two player game.. one player having a few computer skill levels.

 

I'm about to add player0 as the cursor, but if this is a one-player puzzle game, then I don't see any use for player1, the missiles, or the ball. However, I *am* going to put a score or other 6-character display at the bottom.

 

It's just a one player puzzle game. There's no score in the game, so I was going to use the display on the bottom to display what level you are on.

Edited by yuppicide
Link to comment
Share on other sites

Damn you are good Michael. I bow to your skillz!

No need for you to bow. :) But thank you for the compliment!

 

Here's an update. It's still not finished-- I haven't added the score display yet-- but it now has a cursor that's drawn with player0, and I rewrote it in assembly code.

 

The kernel uses a number of variables which are defined within the program via "dim" statements, and which can be set with the bB program:

 

cursorcolor -- Specifies the color of the cursor that's drawn with player0; can be 0-255.

 

gridcolor -- Specifies the color of the grid lines that are drawn with the playfield; can be 0-255.

 

backgroundcolor -- Specifies the color of the background (but note that the blocks inside the grid are *not* transparent, so backgroundcolor does *not* set the "default" color of the blocks); can be 0-255.

 

block00color through block44color -- Specify the colors of the blocks at each row and column (e.g., block23color is for the block at row 2, column 3); can be 0-255.

 

cursorx -- Specifies the column number of the cursor within the grid; should be 0-4.

 

cursory -- Specifies the row number of the cursor within the grid; should be 0-4.

 

The kernel also uses some variables which *cannot* be set in the bB program, since the kernel sets them itself and will overwrite any values that the bB program tries to set them to:

 

cursorline0

cursorrow0

cursorline1

cursorrow1

cursorline2

cursorrow2

cursorline3

cursorrow3

cursorline4

cursorrow4

cursorline5 -- Used to draw the cursor; they define the shape data as a sort of 11-line sprite, but each data byte is for either a gridline or a block. For example, if cursory were 3, then the cursor's shape data would be as follows:

%00000000

%00000000

%00000000

%00000000

%00000000

%00000000

%11111100

%10000100

%11111100

%00000000

%00000000

 

Some additional variables are also defined, but are not referenced by the kernel (at least, not yet); they're intended to be used in the bB program:

 

blockcolor, and row0color through row4color -- These redefine specific block color variables (e.g., blockcolor and row0color are the same memory location as block00color, and row3color is the same memory location as block30color). The purpose is to make it easier to set or read the block colors in a loop using as index. Use blockcolor[index] to reference a specific block, where index is 0-24 (i.e., index=5*row+column, so the block at row 2, column 4 would be referenced using blockcolor[14], since 5*row+column=5*2+4=10+4=14). Or you can use row0color[index] through row4color[index] to reference the blocks in a particular row, where index is the column number, 0-4 (e.g., row2color[4] would reference the block in the 4th column of row2).

 

row, column, and block -- These are temporary variables intended for specifying a particular block within the color array, such as row=3:column=2:block=5*row+column:blockcolor[block]=green.

 

There are also some NTSC Atari color values which are defined as constants, to help make it easier for yuppicide to set a block to one of the colors that he'd said he wants to use.

 

As I said, I still need to add the score display. There are 21 lines remaining (out of 192) just below the grid, and I intend to have 2 rows of score characters-- 3 blank lines after the grid, then 8 lines for the first row of score characters, then 2 blank lines, then 8 lines for the second row of score characters. The two score rows could be anything-- e.g., the first row might say "Level 14," and the second row could be the name of the game, or a copyright message, etc. (where both rows are 48 pixels wide).

 

I may eventually move the kernel into a custom include file, and move the variable equates into a custom header file.

 

The current version includes some sample code to show how the kernel could be used; it flashes the cursor using color cycling, moves the cursor around using the joystick, lets you change the color of the selected block by pressing the fire button, lets you change the background color using the RESET switch, and lets you change the grid color using the SELECT switch.

 

Michael

post-7456-1188711275_thumb.png

grid_mike_3.bas

grid_mike_3.bas.bin

Link to comment
Share on other sites

Just got home and it looks awesome! I'll download and run it after I eat some dinner.

 

My only fears is that this is more of a "you" project than a "me" project. I hope I'll get to the point one day where I can make something and not hardly have to ask any questions. :)

 

Looks great, though.. I like the variables and how easy it will be to make the cursor move.

 

Thanks again.. will post more in an hour or two once I've got a chance to fool with it.

Edited by yuppicide
Link to comment
Share on other sites

My only fears is that this is more of a "you" project than a "me" project.

Don't worry-- I'll finish the custom kernel, but I wasn't planning on writing your puzzle game for you! ;) Of course, if you have questions about how to do something in bB in your puzzle game, I'll be happy to answer them if I can. It's still your game; the kernel just draws the screen as you'd described.

 

Michael

Link to comment
Share on other sites

My only fears is that this is more of a "you" project than a "me" project.

Don't worry-- I'll finish the custom kernel, but I wasn't planning on writing your puzzle game for you! ;) Of course, if you have questions about how to do something in bB in your puzzle game, I'll be happy to answer them if I can. It's still your game; the kernel just draws the screen as you'd described.

 

Michael

 

I am sorry if I came across as a "dick". I didn't mean to sound like that. I thought about it after I posted. I do appreciate all the help.

Link to comment
Share on other sites

My only fears is that this is more of a "you" project than a "me" project.

Don't worry-- I'll finish the custom kernel, but I wasn't planning on writing your puzzle game for you! ;) Of course, if you have questions about how to do something in bB in your puzzle game, I'll be happy to answer them if I can. It's still your game; the kernel just draws the screen as you'd described.

 

Michael

 

I am sorry if I came across as a "dick". I didn't mean to sound like that. I thought about it after I posted. I do appreciate all the help.

Wow, not at all! That never even crossed my mind, and I understood exactly what you meant.

 

My main reason for doing the kernel (aside from helping you) was to demonstrate that it's pretty easy to create a custom kernel for bB-- maybe even one written using bB commands-- and that it's possible for two or more kernels to coexist in a bB game. Ever since bB was born a couple of years ago, people have occasionally asked about creating custom kernels for bB, or having two or more kernels in a bB program, so I thought this was a great opportunity to show these things. The only drawback is that this kernel is much too specialized to be of any general use.

 

Of course, if you aren't going to use either the standard or multisprite kernels in your game, it would make more sense (and save a good bit of ROM) to compile your game without them, using a custom includes file and the "includesfile" statement-- in which case the main line label for the custom kernel could be changed, and the vblank routine could be renamed, so you could call the custom kernel using the "drawscreen" statement instead of "gosub my_drawscreen."

 

Michael

Link to comment
Share on other sites

You wrote in your latest code:

 

for row = 0 to 4

for column = 0 to 4

block = 5 * row + column

blockcolor[block] = black

next

next

 

The Random Terrain website states next will go to the nearest for statement based on distance. So in the above code wouldn't the first next always make the program keep going back to the second for?

 

Either way I've went ahead and added a color purple. Right where you had all the rem statements (after the code above) I've went ahead and started level1. I've set the colors the blocks should be for level 1. Now when you press a button you're supposed to be able to pick up a piece and move it. I am trying to write a subroutine that checks if there is a piece under your cursor and am having difficulty figuring it out. Basically if there is any color besides black or red under your cursor you can pick it up and drop it somewhere else on the board.

 

I made it so when joy0fire is pressed it gosub's checkblock

 

under checkblock I am doing something like

 

checkblock
  if cursorx = 1 and cursory = 1 and block00color = 0 then goto buzzer
  if cursorx = 1 and cursory = 1 and block00color notequal 0 then

 

Is this how I will go about checking each square to see if there is a block color under it? What I am trying to do there is if your cursor is in the first square and the block is empty then it'll make a buzzing noise meaning you can't pick up an empty square. If the block has color in it you can pick it up and move it. I didn't know the symbol for notequal.

 

Also, is there a more efficient way to do this in bB:

 

levelcomplete

  block00color = purple
  gosub my_drawscreen
  
  block00color = black
  block01color = purple
  gosub my_drawscreen
  
  block01color = black
  block02color = purple
  gosub my_drawscreen
  
  block02color = black
  block03color = purple
  gosub my_drawscreen
  
  block03color = black
  block04color = purple
  gosub my_drawscreen

  block04color = black
  block14color = purple   
  gosub my_drawscreen
  
  block14color = black
  block24color = purple
  gosub my_drawscreen
  
  block24color = black
  block34color = purple
  gosub my_drawscreen
  
  block34color = black
  block44color = purple
  gosub my_drawscreen

  block44color = black
  block43color = purple
  gosub my_drawscreen

  block43color = black
  block42color = purple
  gosub my_drawscreen

  block42color = black
  block41color = purple
  gosub my_drawscreen
	 
  block41color = black
  block40color = purple
  gosub my_drawscreen

  block40color = black
  block30color = purple
  gosub my_drawscreen

  block30color = black
  block20color = purple
  gosub my_drawscreen

  block20color = black
  block10color = purple
  gosub my_drawscreen

  block10color = black
  block11color = purple
  gosub my_drawscreen

  block11color = black
  block12color = purple
  gosub my_drawscreen

  block12color = black
  block13color = purple
  gosub my_drawscreen
	 
  block13color = black
  block23color = purple
  gosub my_drawscreen
		
  block23color = black
  block33color = purple
  gosub my_drawscreen

  block33color = black
  block32color = purple
  gosub my_drawscreen

  block32color = black
  block31color = purple
  gosub my_drawscreen
	 
  block31color = black
  block21color = purple
  gosub my_drawscreen

  block21color = black
  block22color = purple
  gosub my_drawscreen
  
  block22color = black
  gosub my_drawscreen

  return

 

That makes the blocks flash purple one by one as sort of a level completion animation. I would like to do it, but hopefully use up less ROM because I'd like to fit as many levels into the game as possible.

Edited by yuppicide
Link to comment
Share on other sites

You wrote in your latest code:

 

for row = 0 to 4

for column = 0 to 4

block = 5 * row + column

blockcolor[block] = black

next

next

 

The Random Terrain website states next will go to the nearest for statement based on distance. So in the above code wouldn't the first next always make the program keep going back to the second for?

Yes, but only until the second "for" is all finished, then the program will go back to the first "for." It will be as follows:

 

row = 0, column = 0

row = 0, column = 1

row = 0, column = 2

row = 0, column = 3

row = 0, column = 4 (second "for" is all done, so now do the "next" for the first "for")

 

row = 1, column = 0

row = 1, column = 1

row = 1, column = 2

row = 1, column = 3

row = 1, column = 4 (second "for" is all done, so now do the "next" for the first "for")

 

row = 2, column = 0

row = 2, column = 1

row = 2, column = 2

row = 2, column = 3

row = 2, column = 4 (second "for" is all done, so now do the "next" for the first "for")

 

row = 3, column = 0

row = 3, column = 1

row = 3, column = 2

row = 3, column = 3

row = 3, column = 4 (second "for" is all done, so now do the "next" for the first "for")

 

row = 4, column = 0

row = 4, column = 1

row = 4, column = 2

row = 4, column = 3

row = 4, column = 4 (second "for" is all done, and now so is the first "for")

 

Actually, the code I posted is not terribly efficient; it would be simpler (and better) to do it as follows:

 

   for block = 0 to 24
  blockcolor[block] = black
  next

However, I wanted to give an example of calculating the block number when you happen to know the row and column. But I guess I did that further down anyway, where I used the following code to get the color of the block where the cursor is positioned:

 

   b = 5 * cursory + cursorx
  c = blockcolor[b]

 

Either way I've went ahead and added a color purple. Right where you had all the rem statements (after the code above) I've went ahead and started level1. I've set the colors the blocks should be for level 1.

You can take out all those "rem" statements; they were where I set the block colors in the first "demo" of the kernel, in which all five colors were used (in different orders) on each row of blocks, to show that each block could be a different color.

 

I don't know how you're setting the block colors for level 1, but the most efficient way would be to put the block colors for each level in a data table, and then load the desired level using a common routine, perhaps more or less as follows:

 

   const black = $00
  const white = $0E
  const yellow = $1A
  const orange = $28
  const red = $44
  const purple = $66
  const blue = $94
  const green = $C6

  dim new_level = a
  rem * flag to indicate that we need to load a new level

  dim level = b
  rem * the new (or current) level number

  dim which_table = c
  rem * which table we need to read the level from

  dim which_row = d
  rem * which row of the table we need to read from

  dim first_block = e
  rem * which byte of the table is the first block on the row

  dim row_block = f
  rem * which block of the row we need to read

  dim color = g
  rem * which color to set the block to

  level = 1 : rem * start at level 1
  new_level = 1 : rem * yes, we need to load the level

loop
  if new_level then gosub load_new_level
  gosub my_drawscreen
  goto loop

load_new_level
  which_table = (level - 1) / 10
  which_row = level - 1 - 10 * which_table
  first_block = 25 * which_row
  for block = 0 to 24
  row_block = first_block + block
  if which_table = 0 then gosub table_1
  if which_table = 1 then gosub table_2
  if which_table = 2 then gosub table_3
  if which_table = 3 then gosub table_4
  blockcolor[block] = colors_table[color]
  next
  new_level = 0 : rem * now we can clear this flag
  return

table_1
  color = levels_1_to_10[row_block]
  return

table_2
  color = levels_11_to_20[row_block]
  return

table_3
  color = levels_21_to_30[row_block]
  return

table_4
  color = levels_31_to_40[row_block]
  return

  data colors_table
  black,yellow,orange,red,blue,green
end

  data levels_1_to_10
  1,0,0,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,4,0,0,0,0,0,5
  0,0,3,0,0,0,0,0,0,0,2,0,1,0,0,0,4,0,0,0,0,5,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
end

  data levels_11_to_20
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
end

  data levels_21_to_30
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
end

  data levels_31_to_40
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
end

This looks kind of messy, and might not be the most efficient way to do it, but it should make it easier to add more levels by simply entering the data into the appropriate table(s). The reason I grouped the levels together 10 at a time is because we're using a byte to index the tables, and a byte can be only 0 through 255, so 256 is the maximum table size-- and there are 25 blocks per level, so that's room for 10 levels (10 * 25 = 250 bytes). We could also just use a separate table for each level, but then we'd have a lot more ifs, and a lot more subroutines. As for the colors, the data in the tables should be byte values, so the easiest way to do this is to assign a number to each color, from 0 to whatever, so the rows of data don't get too long. You could also just do it as follows:

 

load_new_level
  which_table = (level - 1) / 10
  which_row = level - 1 - 10 * which_table
  first_block = 25 * which_row
  for block = 0 to 24
  row_block = first_block + block
  if which_table = 0 then gosub table_1
  if which_table = 1 then gosub table_2
  if which_table = 2 then gosub table_3
  if which_table = 3 then gosub table_4
  next
  new_level = 0 : rem * now we can clear this flag
  return

table_1
  blockcolor[block] = levels_1_to_10[row_block]
  return

  data levels_1_to_10
  yellow,black,black,black,black
  black,orange,black,black,black
  black,black,red,black,black
  black,black,black,blue,black
  black,black,black,black,green
  black,black,red,black,black
  black,black,black,black,black
  orange,black,yellow,black,black
  black,blue,black,black,black
  black,green,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
  black,black,black,black,black
end

I'll let you puzzle over those two coding examples! :)

 

Now when you press a button you're supposed to be able to pick up a piece and move it. I am trying to write a subroutine that checks if there is a piece under your cursor and am having difficulty figuring it out. Basically if there is any color besides black or red under your cursor you can pick it up and drop it somewhere else on the board.

 

I made it so when joy0fire is pressed it gosub's checkblock

 

under checkblock I am doing something like

 

checkblock
  if cursorx = 1 and cursory = 1 and block00color = 0 then goto buzzer
  if cursorx = 1 and cursory = 1 and block00color notequal 0 then

 

Is this how I will go about checking each square to see if there is a block color under it? What I am trying to do there is if your cursor is in the first square and the block is empty then it'll make a buzzing noise meaning you can't pick up an empty square. If the block has color in it you can pick it up and move it.

I would suggest something like the following:

 

checkblock
  block = 5 * cursory + cursorx
  if blockcolor[block] = black then goto buzzer : rem * can't pick up an empty block
  if blockcolor[block] = red then goto buzzer : rem * can't pick up a red block
  rem * else do the code to pick up the block and move it around

The code to actually pick up the color and move it around should be an interesting challenge! ;) Just to give you a hint or two, you'll probably want to set aside a variable to use as a flag, to indicate whether the cursor is moving around freely without carrying a colored block, or whether the player has picked up a colored block-- and you might want to use two different cursor colors so the player can tell if a block has been picked up or not. Also, when you're moving a block of color around on the grid, you'll need a variable to save the color of the block that you're hovering over, so the current color of the block doesn't get wiped out by the color of the block you're carrying. That's assuming the blocks can be picked up and carried "over" the other blocks. If the blocks are actually being slid around, such that they can only be slid into an empty spot, then you wouldn't need to woory about saving the color under the cursor. But you would need to check the block you're about to drop or slide a color into, to be sure it's empty.

 

I didn't know the symbol for notequal.

It's "<>" (e.g., "if a <> 8 then goto a_is_not_equal_to_8").

 

Also, is there a more efficient way to do this in bB:

 

levelcomplete

  block00color = purple
  gosub my_drawscreen
  
  block00color = black
  block01color = purple
  gosub my_drawscreen
  
  block01color = black
  block02color = purple
  gosub my_drawscreen
  
  block02color = black
  block03color = purple
  gosub my_drawscreen
  
  block03color = black
  block04color = purple
  gosub my_drawscreen

  block04color = black
  block14color = purple   
  gosub my_drawscreen
  
  block14color = black
  block24color = purple
  gosub my_drawscreen
  
  block24color = black
  block34color = purple
  gosub my_drawscreen
  
  block34color = black
  block44color = purple
  gosub my_drawscreen

  block44color = black
  block43color = purple
  gosub my_drawscreen

  block43color = black
  block42color = purple
  gosub my_drawscreen

  block42color = black
  block41color = purple
  gosub my_drawscreen
	 
  block41color = black
  block40color = purple
  gosub my_drawscreen

  block40color = black
  block30color = purple
  gosub my_drawscreen

  block30color = black
  block20color = purple
  gosub my_drawscreen

  block20color = black
  block10color = purple
  gosub my_drawscreen

  block10color = black
  block11color = purple
  gosub my_drawscreen

  block11color = black
  block12color = purple
  gosub my_drawscreen

  block12color = black
  block13color = purple
  gosub my_drawscreen
	 
  block13color = black
  block23color = purple
  gosub my_drawscreen
		
  block23color = black
  block33color = purple
  gosub my_drawscreen

  block33color = black
  block32color = purple
  gosub my_drawscreen

  block32color = black
  block31color = purple
  gosub my_drawscreen
	 
  block31color = black
  block21color = purple
  gosub my_drawscreen

  block21color = black
  block22color = purple
  gosub my_drawscreen
  
  block22color = black
  gosub my_drawscreen

  return

 

That makes the blocks flash purple one by one as sort of a level completion animation. I would like to do it, but hopefully use up less ROM because I'd like to fit as many levels into the game as possible.

Assuming the moving block will always be purple, you could do it as follows:

 

levelcomplete
  for z = 0 to 24
  row = next_row[z]
  column = next_column[z]
  block = 5 * row + column
  blockcolor[block] = purple
  for y = 0 to 5 : rem * make this number smaller to speed it up
	 gosub my_drawscreen
  next
  blockcolor[block] = black
  next
  return

  data next_row
  0,0,0,0,0,1,2,3,4,4,4,4,4,3,2,1,1,1,1,2,3,3,3,2,2
end

  data next_column
  0,1,2,3,4,4,4,4,4,3,2,1,0,0,0,0,1,2,3,3,3,2,1,1,2
end

Michael

grid_mike_4.bas

grid_mike_4.bas.bin

Link to comment
Share on other sites

Yes, but only until the second "for" is all finished, then the program will go back to the first "for." It will be as follows:

 

Understand now.

 

You can take out all those "rem" statements; they were where I set the block colors in the first "demo" of the kernel, in which all five colors were used (in different orders) on each row of blocks, to show that each block could be a different color.

 

I did. That's where I was fooling around and placing level 1.

 

Which

I don't know how you're setting the block colors for level 1, but the most efficient way would be to put the block colors for each level in a data table, and then load the desired level using a common routine, perhaps more or less as follows:

 

All I had done was this for a level

 

level1
block00color = black
block01color = orange
etc. etc.

 

I knew it was most likely wrong, but knew I could do it just to have something I could fool around with today.

 

Assuming the moving block will always be purple, you could do it as follows:

 

It will be.

Edited by yuppicide
Link to comment
Share on other sites

I don't know how you're setting the block colors for level 1, but the most efficient way would be to put the block colors for each level in a data table, and then load the desired level using a common routine, perhaps more or less as follows:

 

All I had done was this for a level

 

level1
 block00color = black
 block01color = orange
etc. etc.

 

I knew it was most likely wrong, but knew I could do it just to have something I could fool around with today.

That's fine; as long as it works then it isn't "wrong," although it might not be the best way (and "best" usually depends on the criteria-- best in terms of how much ROM it takes up? best in terms of how fast it is? best in terms of how easy it is to understand? etc.). In fact, the way that I suggested might not be the best way, either.

 

Assuming that the levels will always progress in the same order, then the simplest way to do it would probably be with "sdata" and "sread," which let you read data sequentially more or less the same way that "read" works in other BASICs. I've updated my last demo, and I think it will look a lot easier to understand now, plus it now uses less ROM and less RAM. :ponder:

 

Michael

grid_mike_5.bas

grid_mike_5.bas.bin

Link to comment
Share on other sites

I've updated my last demo, and I think it will look a lot easier to understand now, plus it now uses less ROM and less RAM. :ponder:

D'oh! I just realized I could have simplified the routine for the animation, too! Instead of reading the row and column, you can just read the *block* number, which cuts the ROM for the data in half (one table instead of two tables), and eliminates a few program statements, thereby saving 47 bytes.

 

Michael

grid_mike_6.bas

grid_mike_6.bas.bin

Link to comment
Share on other sites

Assuming that the levels will always progress in the same order, then the simplest way to do it would probably be with "sdata" and "sread," which let you read data sequentially more or less the same way that "read" works in other BASICs. I've updated my last demo, and I think it will look a lot easier to understand now, plus it now uses less ROM and less RAM. :ponder:

 

Wow! Uses a LOT less rom! That will most certaintly come in handy. Oh wait, that's because you only have two levels defined it seems when in the last version you had 40 defined.

 

Even with me adding in 40 levels and compiling it it saved 104 bytes of ROM, which is good. Version 6 squeezes in 37 bytes more even!

 

I will see if I can squeeze in title screen, some sounds, and the movement and what not. If all that fits and there's room left over I'll add in extra levels.

Edited by yuppicide
Link to comment
Share on other sites

Wow! Uses a LOT less rom! That will most certaintly come in handy. Oh wait, that's because you only have two levels defined it seems when in the last version you had 40 defined.

 

Even with me adding in 40 levels and compiling it it saved 104 bytes of ROM, which is good. Version 6 squeezes in 37 bytes more even!

 

I will see if I can squeeze in title screen, some sounds, and the movement and what not. If all that fits and there's room left over I'll add in extra levels.

If you get short on ROM, you might want to get rid of the standard kernel, because it uses up a good chunk of the ROM. Then you could create a second custom kernel to draw the title screen, which would probably be smaller than the standard kernel. In fact, I keep meaning to create a simple title screen kernel for people to be able to use in their games.

 

However, I'd say your next focus should be on the logic for picking up the blocks, moving around with them (whether sliding them or carrying them), and dropping them in new spots.

 

Michael

Link to comment
Share on other sites

If you get short on ROM, you might want to get rid of the standard kernel, because it uses up a good chunk of the ROM.

Also, I expect to rewrite the grid kernel so it uses a single loop to draw the five rows, instead of each row being draw with its own loop. That should free up some additional ROM.

 

Michael

Link to comment
Share on other sites

However, I'd say your next focus should be on the logic for picking up the blocks, moving around with them (whether sliding them or carrying them), and dropping them in new spots.

 

Already thought of that. It's about 10:30pm here so I'm gonna watch a movie and fall asleep. My labor day weekend has come to an end.

 

What you will do is click a block to select it and then move the joystick in the direction you want to slide the block. If you cannot move that way the buzzing sound will come into play. If you can move that way another sound will play and the block will slide that way.

 

I'll work on that tommorow.

Link to comment
Share on other sites

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...