-
Content Count
5,587 -
Joined
-
Last visited
-
Days Won
2
Posts posted by SeaGtGruff
-
-
pfpixel (on / off / flip) works just fine in the DPC+ Kernel.Actually almost everything works just fine. There are some commands not implemented like pfscroll.
My mistake-- obviously I'm grossly ignorant about the DPC+ kernel.
I think I must have been confusing pfpixel with pfscroll, because I've seen posts from people asking whether or not pfsomethingorother works in the DPC+, and if it does then how do you use it correctly, and if it doesn't then could somebody please try to figure out how to make it work. But it makes sense that pfpixel should work since the DPC+ playfield is in RAM.From now on I'll avoid saying anything about the DPC+ kernel unless I know it to be a fact-- which sadly means I might not be saying much of anything about the DPC+ kernel for a while.
I'll try to remedy that. -
One more question! How do I set up so that when player0 touches a pixel it gets destroyed?
Assuming you mean the player gets destroyed, something like:
if collision(player0,playfield) then player0: %00000000 end

Assuming you mean the pfpixel gets destroyed, something like:
if collision(player0,playfield) then pfpixel xpos ypos off
where xpos and ypos are the coordinates of the specific playfield pixel you want to turn off. You'll probably need/want to convert the player0 coordinates to equivalent playfield coordinates to help you figure out which playfield pixel was collided with.
-
I haven't opened the package yet - just shook it to listen

What the... you shook it to listen? Oh jimminy crikey, YOU BROKE IT!

Anyhoo, thou must share all the juicy details of thy spoils with us!

-
Ah, okay. Cool! Sounds like pixels is something I want to use then! I have an experimental project where I wish to have pixels randomly placed on the screen. I'm guessing the "=rand&" command can be used for pixels? But how would I go about creating a pixel?
(1) Use the standard kernel, because the multisprite and DPC+ kernels don't support turning individual playfield pixels on and off.
(2) The command to draw or erase an individual playfield pixel is pfpixel. The syntax is pfpixel xpos ypos function, where xpos is the column number or horizontal coordinate (must be between 0 and 31), ypos is the row number or vertical coordinate (0 to 11 in the standard kernel, or more than 11 if you're using the Superchip option), and function is either on, off, or flip (flip will toggle it on if it's off, or toggle it off if it's on). Some examples are as follows:
pfpixel 14 5 on
pfpixel 21 7 off
pfpixel 3 10 flip
(3) You can also use pfhline to draw a horizontal line of pfpixels, or pfvline to draw a vertical line. The syntax is pfhline xstart ypos xstop and pfvline xpos ystart ystop. For example:
pfhline 3 4 20 - draws a horizontal line from pfpixel coordinates (3, 4) to (20, 4) - since ypos is the same in both sets of coordinates you don't list it twice
pfvline 12 3 8 - draws a vertical line from pfpixel coordinates (12, 3) to (12, 8 ) - since xpos is the same in both sets of coordinates you don't list it twice
(4) Be warned that it can take up more cycles to draw lines with pfhline and pfvline, or to use a large number of pfpixel statements on one frame. If you're drawing a large object with playfield pixels and moving it around, it might cost fewer cycles to just use the playfield statement to redraw the entire playfield at once-- although then you need more ROM for storing all the possible playfields. On the other hand, ROM is cheaper than cycles, since you can use bankswitching to get more ROM, whereas there's a fixed number of cycles per frame.
-
The 2600's sound is generated by the TIA chip, which has two identical and independent audio channels. Each channel has three registers that determine the sound that will be produced.
Audio channel 0:
- AUDC0 (AUDio Control 0) is the control register, which determines the waveform or tonal quality that will be produced. Valid values are 0 through 15.
- AUDF0 (AUDio Frequency 0) is the frequency register, which determines the frequency or note that will be produced. Valid values are 0 through 31.
- AUDV0 (AUDio Volume 0) is the volume register, which determines the volume or amplitude of the sound that will be produced. Valid values are 0 through 15.
Audio channel 1:
- AUDC1
- AUDF1
- AUDV1
(These are identical to AUDC0, AUDF0, and AUDV0.)
To play a note, you set AUDC0 or AUDC1 to pick the waveform you want to use. With one exception, each waveform is just a stream of 0s and 1s that are repeated endlessly in a specific pattern, causing the speaker to vibrate in that pattern and create a sound. The length of the pattern determines the primary frequency of the sound, and the complexity of the pattern determines how "pure" or "noisy" the sound is. One waveform is just a stream of 1s (or "always on"), so it sounds "silent" (because the speaker doesn't vibrate back and forth the way it does with the other waveforms)-- but you can use the volume register with this "always on" waveform to create your own waveforms. I'll come back to the control register and the TIA's "native" waveforms in a later post.
You also need to set AUDV0 or AUDV1 to pick the volume or amplitude of the sound you want to play-- 0 is "off" and 15 is the loudest.
Finally, you must set AUDF0 or AUDF1 to pick the frequency or note you want to play. But the TIA doesn't use the standard set of musical notes (C, D, F#, G, etc.)-- instead, it uses harmonics (or really "subharmonics") of the primary frequency that's been selected with the AUDC0 or AUDC1 register. To determine what the resulting frequency will be, add 1 to the AUDF0 or AUDF1 setting and divide the primary frequency by that number-- for example, AUDF0 = 3 divides the primary frequency by 4 (3 plus 1), whereas AUDF0 = 7 divides it by 8.
Unless you're using the "always on" waveform, making music with the TIA is a "set it and forget it" thing, meaning you can set AUDC0, AUDV0, and AUDF0 (or AUDC1, AUDV1, and AUDF1) and they'll keep their values, playing the same sound continuously until you change their settings to pick a different sound. In practical terms, this means you don't need to keep setting them over and over again within a loop to keep playing the same sound; you just set them once and then you don't have to worry about them again until you're ready to play a different sound. To give a simple example of what I mean, you can do this:
loop if triggering_event then gosub play_a_sound drawscreen goto loop play_a_sound AUDC0 = 4 : AUDV0 = 15 : AUDF0 = 11 : return
instead of this:
loop AUDC0 = 4 : AUDV0 = 15 : AUDF0 = 11 drawscreen goto loop
Of course, if you want to play a sequence of different notes, or even just play one note for a specific length of time (and then turn the note off), you'll need to do something a little more complicated than that example-- you'll need a counter to keep track of how long the current note has been playing, and you'll need to fetch the data for the next note after you're finished playing the current note. And depending on how long you want each note to play, you might even need more than one counter. For example, if your shortest note is going to be 1 second long, and you want each note to play for some multiple of 1 second, you'll probably want to use one counter to count frames, and another counter to count the duration of each note. In general terms, you can think in terms of a "tick," where 1 tick is the shortest period of time you want to work with as far as changing the notes or (if you're being really sophisticated and are using ADSR envelopes) dynamically changing the amplitude of each note. For example, you might want to define 1 "tick" as being equal 10 frames, such that each note's duration is specified in terms of a particular number of "ticks"-- e.g., a duration of 6 would really mean 60 frames (10 frames per "tick"),
You'll also want to create one or more data tables for your notes. You can put all of the data into one data or sdata table, or you can split the data into separate tables-- say, one table for the frequency of each note and another table for the length of each note. Following is a simple example of the multi-table method:
rem * for counting the number of frames drawn dim frame_counter = a rem * for counting the number of "ticks" to play the current note dim note_counter = b rem * for keeping track of which note is currently being played dim note_index = c rem * set the number of frames per "tick" const playback_rate = 30 rem * set the number of notes in the tune const number_of_notes = 8 rem * initialize the variables frame_counter = 0 : note_counter = 0 : note_index = 255 rem * set the waveform and amplitude AUDC0 = 4 : AUDV0 = 15 loop rem * if the current note is finished, play the next note if note_counter = 0 then gosub play_next_note drawscreen rem * update the frame counter frame_counter = frame_counter + 1 rem * if it's been 1 "tick," update the note counter if frame_counter = playback_rate then frame_counter = 0 : note_counter = note_counter - 1 goto loop play_next_note rem * update the index to point to the next note's data note_index = note_index + 1 rem * if the tune is finished, start over from the beginning if note_index = number_of_notes then note_index = 0 rem * fetch the data for the new current note AUDF0 = note_frequency[note_index] : note_counter = note_length[note_index] return data note_frequency 31,28,24,23,20,18,16,15 end data note_length 2,2,1,1,1,3,2,1 end
That's an example of a simple music driver to play a single tune over and over again (in this case, an out-of-tune scale). You might want to tinker with that example by increasing or decreasing the value of the playback_rate constant to see how it affects the speed at which each note changes, or try changing the value of AUDC0, changing the numbers in the data tables, etc.
To play different sounds for different events, you'd want to start (gosub to a routine for the desired sound) when the triggering event occurs, then stop the sound when its timer runs out. Depending on which event occurs, gosub to the desired routine. If you want two sounds at the same time, call one routine for one audio channel and a different routine for the other audio channel, and use a separate counter for each channel. But I'm not going to try to give an example of that right now.
-
1
-
-
I have another question about pixels. I've read that pixels can be used pretty much like objects. How do I set up pixels? And can they be used in collisions or are they just for show?
Yes, you can detect collisions between the playfield and the sprites (players, missiles, and ball). The only things you *can't* detect collisions with (using the collision registers) are the background and the blanking (should you ever try using the blanking to "draw" in black on the screen display).
Playfield pixels can sort of be used like sprites, but they're immobile, so the only way to "move" an object drawn with playfield pixels is by erasing certain playfield pixels and turning on other playfield pixels-- or, if applicable, by scrolling the playfield.
Given the horizontal resolution of playfield pixels, that doesn't usually work so great for horizontal "motion." But if you're drawing the playfield with a reasonably high vertical resolution then you can move a playfield pixel object vertically without it looking too horrible. For example, if you're writing a platformer game, you could use playfield pixels to draw elevators that go up and down, similar to Infiltrate.
-
It seems to be working now in IE10.
Yeah, it's been working for me for a couple of months now-- not sure when it stopped not working. If it wasn't a forum upgrade on Albert's end, it may have been a Microsoft update to IE10.
So if it still isn't working for anyone, try running Microsoft Update to see if any updates for IE10 show up as available. -
I tried pasting the code in my project, but I get a syntax error at this line:
if rand > 127 then pfpixel 1 temp2 on:next
You might try putting the next on a separate line. Looking back at the original code in the first post, I'm not sure if the next statements should have been inside the ifs the way they were.
Other than that suggestion, the pfpixel statement might not be available in all bB kernels-- for example, I don't think it works with the multisprite kernel.
-
Wouldn't compile for me.
Doesn't like the if statement on line 96
I seem to have all kinds of trouble getting if statements to compile sometimes-- and I swear a lot of the time the logic is the same as what used to work in earlier versions of bB. Usually when I have a problem it seems like the compiler is trying to interpret a logical combination as a complex math statement. That's why several of the ifs in my example program use nested ifs rather than &s. And IIRC the compiler has trouble handling elses the way you'd expect, like "if a then b else c : d : e"-- my expectation is that "c : d : e" would all be part of the else, but instead only c is the else and "d : e" execute regardless, as though there were an endif after c. I guess that's fair (as in "turnabout is fair play") if you can't do something like "if a then b : c : d else e." Yet the compiler usually has no trouble handling "if a then b : c : d" without an else. It would be awesome to eventually have true "if-then-else-endif" statements that let us use multiline thens and elses-- it would help simplify a lot of cases where you end up having to invert the if and use a goto to jump over what would have been a lengthy then.
As far as why that particular line wouldn't compile for you-- I don't know. Sometimes a statement won't compile in one updated version, but then I try a slightly different updated version and it works. I get a headache trying to juggle around all the minor updates. It's gotten to be a mess.

-
Hm, I understand the workings, but not how to write it out. I can't get it to work.
Here's a simple example I threw together. It's messy-- I didn't try to consolidate RAM space by dimming bit variables, for example, and I'm sure someone can find ways to improve the logic-- but it works.
Edit: Minor correction to the player1_1st_copy_hit routine. I'm attaching the updated files.
-
I don't think you have to get them in order.
You don't.
-
Is there a batari Basic thread earlier than the one below from July 7, 2005?
I couldn't remember if version 0.1 was released in 2005 or 2004, or maybe even before 2004-- and I was too tired at the time to go look it up!
I do remember that the first four versions (0.1, 0.2, 0.3, and 0.35) were released pretty close to each other, then there was a "pause" before 0.99 was released.Anyway, I was thinking that "on-goto" might not have been added to batari Basic yet when I wrote that "move_around_rooms.bas" example.
-
The sprite starts as a random color (which I got down and it will do everytime I start up Stella). But now I'm trying to test the fact, how can I go one step further and every time I press up on the joystick, then I can recall the randomness and change the color of the sprite? I tested setting it as white in the main, but it stays white no matter what. So if I set it to a random color in the main then it will show. If I don't even set it in the main obviously it doesn't appear UNTIL I press up...but it's always that one random color.
How to make it start off as a random color...then press up and it will change...press up again and it changes again? Is this where I need to set it to temp1 instead of f then? (As far as rand). Sorry if I'm babbling or confusing...I'm just getting aggrevated!
Well, unless you're using a multi-sprite kernel and are using the player that gets multiplexed, you'll need to set the player's color in the loop sometime before you call drawscreen (since COLUP0 and COLUP1 get wiped out at the end of drawscreen when the score is displayed). So "all" you need to do to test the random colors is to check the joystick just before you set the player's color and-- if the joystick is pressed up-- randomize the color again before you set it.
-
Also another quick question...let's say for instance your character will move normally. Then, by pressing the fire button, your character does something else instead of move (say for instance he fires in all 4 directions). How would you go about coding it to where you can switch out between moving and shooting? I can make my character move, then when I press the fire button he won't move, but instead fire in all 4 directions. However, when I press the fire button again, he won't start moving (thus cancelling out the shooting). I've tried numerous things, but the only thing I can come up with is having to hold the fire button down. I don't want to hold it down, just press the fire button to switch out between the two commands.
It sounds like you got the color issue figured out, and I'm not experienced with DPC+ yet, so I'll tackle the movement question.
From your description of what you want to achieve, I'd suggest defining a flag for indicating whether the player is moving or is stationary/shooting. It doesn't need to be an entire variable (byte)-- just a single bit. Random Terrain's bB web page should have lots of examples of dividing a byte into multiple bit variables or flags.
Now, supposing that you have plenty of variables free, the simplest way to do this would be to use an entire byte for the flag, then use the exclusive-or (the ^ operator) to flip the flag when the button is pressed, something like this:
dim flag = a flag = 0 : rem initialize the flag to "off" loop if joy0fire then flag = flag ^ 1 : rem this flips the flag on if it's off, or off if it's on if flag = 0 then gosub player_is_moving if flag = 1 then gosub player_is_firing goto loop
This is obviously an incomplete example, but hopefully you can get the idea of what I mean.
The tricky part, though, will be reading the fire button, because you'll need to "debounce" it-- which I didn't do in the above example. Debouncing a console switch (like game reset or game select) or a fire button or a game controller refers to processing its state in a way that prevents it from being "read" too many times in a row, or too quickly. For example, in the code above it's possible that pressing the fire button will rapidly flip the flag on and off and on and off many times as the program loops, because the computer/2600 operates so much faster than you do-- so even if you try to tap the button very quickly, it may seem to the 2600 as though you're holding the button down for a really long time. There are examples of debouncing the fire button in older posts, and Random Terrain also has examples on his bB web page.
-
here I've molested SeaGtGruff's code
Molest away!

-
SeaGtGruff's move_around_rooms is similar
except he goes to a subroutine for each
direction that does the table look up for
that direction then uses the room to
look up a room shape (and a room color)
then uses a bunch of if statements instead
of on goto (and why in the world.. ;P )
to select the correct room shape drawing
code for the room. (so different rooms
can have same shapes with different colors)
Well, it was written about 6.5 years ago, so I don't really remember why in the world I did it that way.
I'm not sure when on-goto was added to batari Basic, but I don't think the no_blank_lines option was available yet, otherwise I'm pretty sure I would have used it in that example. On Random Terrain's page it says "The original beta version [of batari Basic] was released in 2005. Version 1.0 was released in 2007." I thought the first versions of batari Basic were released before 2005, but if I remember correctly Fred considered the 0.99 release to be the first true "beta" release, so maybe that's what 2005 is referring to?Anyway, my example was just a quickie demo to suggest what *could* be done, not anything I spent a lot of time trying to optimize, and I hadn't meant it to be an example of how something *should* be done.
I only mentioned it because using a separate array for each direction allows up to 256 rooms. To break the 256-room barrier you could use sdata statements, or split the game into multiple "lands" and have separate sets of data statements for each land, allowing up to 256 rooms in each land, etc.But yeah-- if I were doing it today, I'd do it differently than how I did it back in 2006.

-
For the color you could define an array of the specific colors you want to use, and use the rand function to generate an index into the array, using any of various methods (discussed in other threads) to reduce the random number to within the desired range of index values.
To keep the color from changing all the time, you need to assign the random index value to a variable, and don't call the rand function again until you need to respawn the enemy in a new random location.
If you're using the multisprite or DPC+ kernel to draw multiple enemies, you'll need to have a separate variable for each enemy's color index.
-
Ah thank you both so much! I'll def have to try those out!
You can also look at a demo I posted a while back called "move_around_rooms.bas"-- you should be able to find it in this forum by searching for that program name. It's sort of like bogax's "lookup_room.bas" except each direction has its own data matrix so you can have up to 256 rooms if you want.
-
I bucked the herd and went with power-ups on the left, on the grounds that people in our culture read left-to-right, therefore it seems to me like it's more natural for the information to be presented left-to-right by priority. You might say that lives remaining have a greater priority than power-ups, but I think power-ups have a more *immediate* priority than lives remaining.
-
I kept the player colors inside the main...if I took them out, the player colors stayed the same except Player0...the sprites defaulted to black. Don't quite understand as to why, so I will just keep it in the main so they will stay their coded colors.
It's because the score is drawn using player0 and player1. If you aren't setting the colors for player0 and player1 in the loop, they get stuck on the score's color, which defaults to black.
-
1
-
-
Yes, it's possible for the yellow/white/black key to be placed in the yellow/white/black castle by the randomization, thereby making the game impossible to win. Of course, the game might still be possible to win if the white/black key is locked up in the white/black castle, depending on where everything else is-- mainly the chalice and the yellow key.

-
I'm trying to paint a rainbow effect on a PAL console. Since the colors are ordered very "strange" on a PAL console, I tried to write some code to "reorder" the color table for me. It didn't need to be a mapping NTSC -> PAL as close as possible, it should just a one nice rainbow, not two interlacing.
If you just want to do a rainbow effect in PAL without worrying about mapping the NTSC palette to the PAL palette, just skip every other hue in increasing order, then skip every other hue in decreasing order:
Increasing:
$2x
$4x
$6x
$8x
$Ax
$Cx
Decreasing:
$Dx
$Bx
$9x
$7x
$5x
$3x
This assumes you don't need/want to include the gray shades ($0x and $1x, as well as $Ex and $Fx).
So a PAL rainbow effect could be programmed as follows:
; Taste the PAL Rainbow! ; Version 1 - No Shades of Gray Allowed PROCESSOR 6502 VSYNC = $00 VBLANK = $01 WSYNC = $02 COLUBK = $09 PF0 = $0D PF1 = $0E PF2 = $0F AUDV0 = $19 AUDV1 = $1A GRP0 = $1B GRP1 = $1C ENAM0 = $1D ENAM1 = $1E ENABL = $1F TIM64T = $0296 TIMINT = $0285 first_color = $80 line_color = $81 hue_increment = $82 ORG $F800 Boot_Routine CLD LDA #0 STA PF0 STA PF1 STA PF2 STA AUDV0 STA AUDV1 STA GRP0 STA GRP1 STA ENAM0 STA ENAM1 STA ENABL LDA #$0E STA first_color Vertical_Blank LDA #2 STA VBLANK LDA #32*76/64 STA TIM64T Front_Porch BIT TIMINT BPL Front_Porch STA WSYNC LDA #2 STA VSYNC STA WSYNC STA WSYNC STA WSYNC LDA #0 STA VSYNC LDA #46*76/64 STA TIM64T LDA #$10 STA hue_increment LDA first_color AND #$10 BEQ Load_Color LDA #$D0 STA hue_increment Load_Color LDA first_color JSR Next_Color STY first_color STY line_color Back_Porch BIT TIMINT BPL Back_Porch STA WSYNC LDA #0 STA VBLANK LDX #230 Active_Video LDA line_color STA COLUBK JSR Next_Color STY line_color STY WSYNC DEX BNE Active_Video JMP Vertical_Blank Next_Color CLC ADC #$02 TAY AND #$0F BEQ Next_Hue RTS Next_Hue TYA CLC ADC hue_increment TAY BIT hue_increment BMI Decreasing_Hues CPY #$E0 BEQ Start_Decreasing RTS Start_Decreasing LDY #$D0 STY hue_increment RTS Decreasing_Hues CPY #$10 BEQ Start_Increasing RTS Start_Increasing LDA #$10 STA hue_increment LDY #$20 RTS ORG $FFFC WORD Boot_Routine WORD Boot_Routine END
It isn't very elegant code, and there's probably a better way to do it, but it works!
-
Hello ^^
Anybody here know how to check whether the playfield is completely empty? 0:
Thankies.
If you're using a bB playfield that's stored in RAM, you could use a routine to check each playfield byte to see if it's 0-- maybe something like this:
(1) Initialize a flag to 1 (i.e., pre-assume that the playfield isn't completely empty).
(2) Use a loop to start checking each playfield byte.
(3) As soon as a non-zero byte is detected, exit the loop with the flag still set to 1.
(4) Otherwise, keep looping to check the next playfield byte.
(5) If you reach the end of the loop (the last byte to be checked) and it's 0, exit the loop and clear the flag.
Or the other way around:
(1) Initialize a flag to 0 (i.e., pre-assume that the playfield is completely empty).
(2) Use a loop to start checking each playfield byte.
(3) If a byte isn't 0, set the flag to 1 and exit the loop.
(4) Otherwise, keep looping until you've checked all the bytes.
(5) When you eventually exit the loop-- either because of (3) or because you've checked all the bytes-- the flag will indicate whether or not the playfield is completely empty.
Another idea:
(1) Store the total number of playfield pixels that are "on," using as many bytes as necessary (probably 2).
(2) While the game is being played, decrement the number of playfield bytes each time a playfield pixel is turned "off."
(3) When the number reaches 0, you know the playfield is cleared.
-
A constant is a value that's defined and used as an "immediate" value (i.e., #value in assembly) rather than stored in a RAM variable. The value must be a valid decimal, hex, octal, or bit number that fits within one byte. So as far as I know, you can't use "const" to define one of batari Basic's fixed-point values. But I think you should be able to use "def" to do this:
def _20x=1.410
def _20y=0.513
-
1
-

Random position on playfield?
in batari Basic
Posted
I hate to sound any more ignorant than my recent posts have already made me sound
but is there a bB installation package, or is everything still just compressed into zip files? IIRC, a while back Fred/batari had asked if anyone could help work on getting together a proper installation package (especially for Windows since he doesn't use Windows? or does he?). Did anyone ever step up and offer to help with that?