-
Content Count
259 -
Joined
-
Last visited
Posts posted by CurtisP
-
-
This may have been mentioned once before, but I found an undocumented constant, PFmaskvalue.
If you don't like blank lines in your playfield, but don't want to lose any features by using no_blank_lines, you can use
const PFmaskvalue=255
Each byte of the playfield will be set to the given number, basically repeating the same bit pattern four times.
-
I've also found 12 cycles available if you aren't using readpaddles, playercolors, or pfcolors. Don't know what to put there, but at least I know it's available.
-
Why do you have have to use the player1colors option? I generally don't use colored sprites because those missiles come in handy.It's specifically because missile1 is not available. Usually all the cycles available to the kernel have been used up. The code for missile1 uses 15 cycles, if playercolors are used, then the missile1 code is disabled and the playercolors code takes it's place, the code for each player taking 7 cycles each. When just player1colors is used and not playercolors, then there is 8 cycles of NOPS replacing the player1 color code. This is where I stuffed the bkcolor code.
By the way, anytime using one option causes another option to no longer be usable, it may be possible to swap that second option with another one you don't need with a kernel hack.
-
I tried it with pfcolors. Neato!
I'm thinking that since this uses the same technique as pfheights and pfcolor together, and there are two bytes left in each entry of the table for those, that this should be incorporated into the standard compiler and kernel. I know what changes to make to the kernel, but the compiler code just scares me.
-
It's a DASM warning message.
I'm also attaching a batch file I use that creates a .lst file when compiling. You can look at the end of it to see how big the output file is and see if any space is being wated by aligns, etc.
-
What I still yearn for, that would be almost universally useful, is a command that splits the background color on a specific line. So that I can use the background for ie the sky and the ground, or the sky and the ocean, and still have a multicolored playfield in front of it. I would be able to use that in pretty much every project I have.I found 7 cycles free when using player1colors but not playercolors. I couldn't fit a simple split in there, but what I could fit was a seperate background color for each playfield line.
I replaced the line
sleep 7
with
lda bkcolor-84,x;4 sta COLUBK;3
The value 84 is valid only if pfres is not being used.
Now the complicated part. At the end of your program, put
asm if (<*) > (<(*+84)) repeat ($100-<*+84) .byte 0 repend endif bkcolor byte 0, 0, 0, 0 byte 2, 0, 0, 0 byte 4, 0, 0, 0 byte 6, 0, 0, 0 byte 8, 0, 0, 0 byte 10, 0, 0, 0 byte 12, 0, 0, 0 byte 14, 0, 0, 0 byte 16, 0, 0, 0 byte 18, 0, 0, 0 byte 20, 0, 0, 0 end
replacing the number after each byte with the background color for that line.
Remember you must be using kernel_option player1colors, but not playercolors. This should slso work fine with pfcolors.
-
Since 2600IDE won't tell me how many bytes I have left, I'll guess I have zero left since I added that last line. I'd like to finish this in 2K. I dunno why, I just thought I'd make a 2k game for the heckuvit, since hardly any has been made since Edtris (how many? 0?) And if anyone wants to release it on cart, I'd be glad to. First 2k game on sale since Edtris, that I'm fairly sure of. Have any bugs popped up yet?If you put a PAUSE at the end of 2600ide.bat, you can see the output in the Command Prompt window.
-
Is there a way to still set the entire playfield color at once when using the PFCOLORS kernel option?I have a game with multiple screen types, some are gradients, and some are one solid color that fades to black and back. The fade to black part takes up a lot more space with color tables though than just cycling COLUPF from 14 to 0. Is there any way to temporarily restore the playfield to it's default way of applying color?
The PFCOLORS mode is switched on at compile time. It's possible with a kernel hack, but I don't know at this time how much work it would be.
-
Good stuff. Your students had a lot of good ideas. I also agree that this is a great way to teach basic game and programming concepts.
-
Keep on working on this........
greetings Walter
Is the entire article being in the first post working for you? I think that's easier than having to scroll through mutliple replies to see all the parts of the tutorial.
-
All good points. The kernel can be quite convoluted and hard to follow, so it can take a while to figure out how to make a hack.
In this case it was reasonasbly easy: I just did a search in the file for PF0 and only found one occurence.
-
While working on the tutorial I had the idea for a hack to continue drawing PF0 into the score. I changed the code directly after the endkernel label to
; 6 digit score routine stx PF1 stx PF2 ifnconst extendborder stx PF0 endif
With this hack in place, the following line will cause the border to extend into the score.
const extendborder=1
In addition, when this option is set, PF0 does not need to set every time drawscreen is executed.
-
-
I changed all the code segments to use CODE tags, doubling up the leading spaces using Alien Bills Atari Age Batari BASIC Code Cleaner.
-
I'd like to try reworking this game using the single sprite kernal, as i think I could keep most of the functionality and have no flicker. Plus I'd like to see how small I can make it.
-
Damn you are good Michael. I bow to your skillz!
-
Is that how it's supposed to work though? As I found it quite confusing when I was experimenting with pfcolors with and without background.Thats sounds like a bug to me. You should not have to put pfcolors inside your game loop. In fact, I consider it bad style to do so.
-
It seems to me that redefining the playfield colors could eat up a lot of ROM fast.Howvever, by increasing the number of playfield colors defined and directly manipulating the playfieldcolors variable, you can achieve a color scroll.
Please note that this will NOT work if you are using both pfcolors and pfheights, since that uses a different indexing method.
So... since you brought it up...
what needs to be change to make your example work with both pfcolors and pfheights? I've been looking at the assembly, and I've tried altering the variable with no luck.... the BBasic compiler doesn't seem to want to write the extra pfcolor data into memory, making it impossible to move the pointer to a new location... I thinkAny thoughts how to make it work? Any help is greatly appreciated!
Thanks,
Mike
IIRC, you can't do it at all with pfcolors and pfheights. The reason is that each pfheight and pfcolor is stored side by side, and a single pointer is used to point to both. I'm not even sure if you can change the pointer safely, but if you could, then the height of each pf row would change along with the color.
Unfortunately, a number of thingds are hardcoded into the kernel and while some things can be tricked into working without modifying the kernal, others can not

-
Thanks Michael. I assume you'll keep an eye on it and point out any errors.
-
I totally recommend Atari 2600 BASIC (aka bB) 1.0. I use it to make all my games. Without it, I'd have to learn ASM, which is apparently very hard.And now there is a handy-dandy tutorial to get you started (or at least the beginning of one).
-
Here is the Hello World program.
So how is the tutorial. Should I keep working on it?
-
Here is the Hello World program.
So how is the tutorial. Should I keep working on it?
-
If someone could pin this, that would be great. I plan to add to this every few days. Comments are welcome.
Note
This tutorial assumes that you already have bAtari Basic setup on your system, and that you are able to compile and run a program. If not, then you can find instructions for doing this at http://bataribasic.com.
Introduction
The 2600 has been called one of the most difficult consoles to program. This is because of the simplicity of the hardware. Now one might think that simple hardware means simple programming, but the 2600 is almost too simple. The chips that draw the television screen only hold enough information to draw one line at a time. This means that the CPU must reload new information every time a line is different from the one before it. Many times, the information new information is loaded into the middle of a line for special effects. Not only that, but this must be done every time a screen is drawn, sixty times a second.
It is this almost constant handling of the hardware, which requires that instructions be timed to the microsecond, so that the CPU is synchronized to the electron beam in the television, that caused many to believe that a Basic Compiler for the 2600 was impossible.
The Kernel
What makes bAtari Basic possible is the kernel, a dedicated piece of machine language code, included in the compiled program, that runs once every sixtieth of a second, and draws the screen based on parameters set by the Basic code. The compiled Basic code, on the other hand, is executed during the time that a picture is not being drawn on the television.
The Screen
bAtari Basic divides the screen into two sections: the playfield and the score.
+----------------------------------------+
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....| <- Playfield
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....|
|.................999999.................| <- Score
|........................................|
+----------------------------------------+
The playfield is made up of 11 eight-pixel high lines, each of which is 32 pixels across, with a four pixel wide space on each side.
There are five objects which may be displayed in the playfield area: two players, two missiles, and a ball. These objects will be covered later.
Your First Program
Many programming tutorials begin with a Hello World program. This will no exception. Since the 2600 doesn't have a character display, we will need to draw the words hello world on the playfield.
In bAtari Basic, all lines other than labels and the "end" statement must begin with at least one space. Labels and "end", on the other hand, may not have any leading spaces. Because the forum likes to strip space, I will be using an underscore where this space should be. The leading underscores will need to be replaced with spaces before the program will compile.
The program will start with a comment, which identifies the program. Comments begin with the command "rem", which is short for remark.
rem Hello World
Next, the playfield is defined using the playfield command. The playfield consists of 12 lines, each composed of 32 pixels. Only the first 11 lines are displayed, the 12th is used for vertical scrolling. Within each line, a period reperesents a blank pixel, an X represents a filled pixel.
playfield: ................................ ......X.X.XXX.X...X...XXX....... ......X.X.X...X...X...X.X....... ......XXX.XX..X...X...X.X....... ......X.X.X...X...X...X.X....... ......X.X.XXX.XXX.XXX.XXX....... ................................ .....X...X.XXX.XX..X...XX....... .....X...X.X.X.X.X.X...X.X...... .....X.X.X.X.X.XX..X...X.X...... .....XX.XX.XXX.X.X.XXX.XX....... end
When the program first starts, all variables and registers are set to 0, which happens to be the color black. This means that the background will be black. Unfortunately, the playfield will also be black, rendering it invisible. So, the color is set to white, by setting the appropriate TIA register with the desired color value.
COLUPF = 14
Finally, we must tell the kernel to draw the screen. This must be done over and over, 60 times a second, forever (actually until the 2600 is turned off). So we have a label, "mainloop", the "drawscreen" command, which activates the kernel, and a "goto" back to the label, which causes the program to repeat the drawscreen command.
mainloop drawscreen goto mainloop
Compile the program, then load the resulting .bin file in an emulator, and you will be greeted by the words "HELLO WORLD".
The Rest of the Screen
Now let's replace the playfield in the Hello World with the following, which one might expect to draw two horizontal lines, one at the top of the screen, and one at the bottom, stretching from the far left to the far right.
playfield: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ................................ ................................ ................................ ................................ ................................ ................................ ................................ ................................ ................................ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end
When you compile and run it, however, you will see blank areas on the right and left edges of the screen and another blank area at the bottom of the screen.
The bottom of the screen is taken up by the 6 digit score. It's invisible now because the scorecolor system variable defaults to 0, which is black. So, right below the COLUPF statement, add the line
scorecolor = 14
Compile and run the program, and you will see the score below th
In addition, the playfield is actually 48 pixels wide, not 32. But, for various technical reasons, only 32 pixels of each line can be stored in memory. You can still draw in those those four left over pixels, but there are some limitations.
- Both borders will contain the same pixel patterns: You define the right border and it will be mirrored (horizontally flipped) on the left border.
- The border can only be defined once, and will be repeated on every single line.
To define the border, you set a TIA register with a binary value (of which only the first four bits will be used). Enter the following line, directly below the scorecolor line.
PF0 = %10000000
Compile and run and, wait a minute, the borders are still blank. Actually they weren't blank the first time draw screen was called, but that lasted only a sixtieth of a second. The kernel blanks the borders while drawing the score, so we need to reset it ever time we do a drawscreen. Move the above line to just below the mainloop label and compile and run again.
Player Graphics
The 2600 has two player graphics, numbered 0 and 1. The graphics are 8 pixels wide and can be any height.
They can be positioned anywhere in the playfield area, including the borders.
The player graphics are defined using the statement player#:where # is either 0 or 1. This is followed by the player data, in reverse order, and finally and end statement.
As an example, we will use the venerable smiley face, which would look something like this.
.XXXXXX.
X......X
X.X..X.X
X......X
X.X..X.X
X..XX..X
X......X
.XXXXXX.
The easiest way to enter the data is as binary numbers, with a 0 representing a blank pixel, and 1 representing a drawn pixel, as follows:
player0: %01111110 %10000001 %10011001 %10100101 %10000001 %10100101 %10000001 %01111110 end
We also need to position the player. This is done using the player#x and player#y system variables (where # is 0 or 1). The player#x variables control the horizontal position of the left-most pixel of the players, while the player#y variables control the vertical position of the bottom-most line of the players. The horizontal positions range from 1 (at the left edge of the screen) to 160 (at the right edge of the screen), and the vertical positions range from 1 (at the top of the screen) to 88 (at the bottom of the playfield).
To position player0 in the center of the screen, use the following lines.
player0x = 76 player0y = 40
The last thing we need to do is set the color of the player, since, like all settings, it defaults to 0 (black). There is no system variable for the player color so the TIA register COLUP0 will need to be set. There is one catch to using the COLUP0 and COLUP1 registers, however. Because the score routine uses the both players, it will reset both colors every frame. Therefore, you must set the player colors before every drawscreen.
So, the final code we need to make this program work is
mainloop COLUP0 = 14 drawscreen goto mainloop
Compile and run the program, and a white smiley face should appear in the center of the playfield area.
Missile Graphics
Along with the two player graphics, there are two missile graphics, one for each player. Each missile is consists of one pixel, but may be of any height. Missile0 has the same color as player0, and missile1 has the same color as player0.
Each missile is controlled by three variables: missile#height, which sets the height of the missile, missile#x, which controls the horizontal position of the missile, and missile#y, which controls the vertical position of the bottom most line of the missile. The missile height value is 1 less than the actual height of the missile, in lines. The horizontal positions range from 2, at the very left of the screen to 161 at the very right of the screen. This means that for any given horizontal location, the missile#x value is one more than the player#x value. The vertical positions range from 1 to 89 and are half a line above the equivalent player vertical positions.
As an example, take the previous example program and add the following lines before the mainloop label:
missile0height = 0 missile0x = 75 missile0y = 40
Compile and run, and a single pixel will appear to left of the smiley face.
Player and Missile Options
The appearance of the Players and Missiles may be changed using the NUSIZ0, NUSIZ1, REFP0, and REFP1 registers. TIA registers. NUSIZ0 affects Player 1 and Missile 0, while NUSIZ1 affects Player 1 and Missile 1. Otherwise the two registers are identical.
As noted previously, the screen is 160 clocks (or pixels) wide. Each pixel of the playfield is four clocks wide, while each missile and player pixel is one clock wide.
Each NUSIZ register is divided into two nybbles (groups of 4 bits). The high nybble (bits 4-7) control the width of the missile, while the low nybble (bits 0-3) control the player. The easiest way to write to the NUSIZ register is to use hexadecimal, since each hex digit refers to a nybble. Thus, in the number $12, the high nybble contains 1, while the low nybble contains 2.
Valid values for the high nybble (first hex digit) are:
- 0 Missile is 1 clock wide (default)
2 Missile is 2 clocks wide
3 Missile is 4 clocks wide
4 Missile is 8 clocks wide
Valid values for the low nybble are:
- 0 Player pixels are 1 clock wide (default)
1 Player and Missile are drawn twice with 16 clocks apart
2 Player and Missile are drawn twice with 32 clocks apart
3 Player and Missile are drawn three times 16 clocks apart
4 Player and Missile are drawn twice with 64 clocks apart
5 Player pixels are 2 clocks wide
6 Player and Missile are drawn three times, 32 clocks apart
7 Player pixels are 4 clocks wide
The distances above are from leftmost pixel to leftmost pixel, so there will be that number minus eight clocks in between each player.
The REFP0 registers are used to reflect (horizontally flip) the players. Normally the players are displayed high bit to low bit. Setting bit 3 of this register (setting the value to
causes the player to be displayed from low bit to high bit. Since the players are used by the kernal to display the score, the NUSIZ and REFP registers (along with the
COLUP registers) are reset each time draswcreen is called. NUSIZ0, NUSIZ1, REFP0, and REFP1 are all set to 0, so if you are using the defaults you won't need to do anything. Otherwisem, the registers will need to be written to before each drawscreen.
Now to put this to use. Modifying our exisitng program, we will put player 0 at horizontal position 64.
player0x = 64 player0y = 40
Then position the missiles 8 clocks to the right
missile0height = 1 missile0x = 73 missile0y = 40
Finally, we will set Missile 0 to 8 clocks wide and Player and Missile 0 to be drawn three times, 16 clocks apart.
mainloop COLUP0 = 14 NUSIZ0 = $33 drawscreen goto mainloop
Compile and run the program, and you will see three smiley faces with horizontal lines between them.
Next: Reading the Joystick
- Both borders will contain the same pixel patterns: You define the right border and it will be mirrored (horizontally flipped) on the left border.
-
Just played the game for a few minutes. I like how you have to use the diagonals to shoot at the targets, since those are a bit harder than the left, right, up, down joystick directions. Some suggestions:I am using the singleplayer kernel, and both players to achieve the multicolor player effect (which I thought looked pretty good for the 2600). I'm also using some kernel options in Bb, that limited me:
- Maybe a crosshair instead of a block when targeting?I'm using the Ball as the crosshair, since both sprites are used up, missile 0 is unavailable in no_lines mode, and missile 1 would be multicolored.
- Different color buildings?I could make the top and bottom different colors. but not the left and right. Also, the crosshair will be the same color as whatever building it's in. I could play with the foreground colors to do day and night.
- Do two or more people ever appear at once?No, it takes two sprites to make one person. In the original version, there was a part of the game where three people appeared at once and you had to shot only the good guys, but since I can only show one guy at a time, I had to leave it out.
- Fire button to start new game after game over?I didn't put that in there? That I can add easily enough.
- The game starts out slow, which is fine the first few times you play but would be nice if there was a way to start at a higher difficulty for better replay value.If you set the left difficulty to B the silhouettes move faster, if you set right to B they don't last as long. You also score higher in this mode. I made A=easy, B=hard, since this is what I found online, but I think many of the games were the opposite. Can anyone confirm this?
I also had the game crash on me once in Stella. After a new building scrolled in (a building with three windows), the game went a bit wonky and then went to a black screen. I had to reload the binary to continue.I haven't had any other reports of this. I think some more playtesting is in order.
...AlAlso I'm bumping up against the 4K limit, if I add anything else to it, I will have to go 8k, which means I won't be able to test it on my Supercharger.

Limiting Flicker using bB Multisprite Kernel with Sprite in same vertical
in batari Basic
Posted
Are you sure you mean vertical? There should be no flicker in a verticle line:
X
|
X
|
X
|
X
But in a horizontal line you would have lots
X-X-X-X
Just checking...