Jump to content
IGNORED

bB and timers help needed


jubileebop

Recommended Posts

Does your game use the score? You could use that as a counter and count down.. decrease the score every so many frames.

 

For the interval between key presses you could set a flag when you press the button..

 

like

 

set the flag like this:

 


if a = 0 then goto fire else nofire

fire:
if joy0fire then a = 1

nofire:

 

Something like that..

Link to comment
Share on other sites

Does your game use the score? You could use that as a counter and count down.. decrease the score every so many frames.

 

Yes, I will use the score but I will format it to look like a timer. If I understand correctly.. I count 60 frames and that is one second on my timer, right? How do I count frames? (forgive my newbie question)

Link to comment
Share on other sites

Yes, I will use the score but I will format it to look like a timer. If I understand correctly.. I count 60 frames and that is one second on my timer, right? How do I count frames? (forgive my newbie question)

Are you talking about a simple counter like this:

 

   dim Time_Counter = a

  COLUBK = $C4
  scorecolor = $1C


Main_Loop


  Time_Counter = Time_Counter + 1

  if Time_Counter < 60 then Skip_Timer

  Time_Counter = 0

  score = score + 1

Skip_Timer


  drawscreen


  goto Main_Loop

 

Or something more advanced?

Edited by Random Terrain
Link to comment
Share on other sites

I replaced with Time_Counter with Frame_Counter. This is what I had in mind:

 

  
  dim Frame_Counter = f

  COLUBK = $C4
  scorecolor = $1C

Main_Loop

  Frame_Counter = Frame_Counter + 1
  
  if Frame_Counter < 60 then Skip_Timer

  score = score + 1
  Frame_Counter = 0
 
Skip_Timer

  drawscreen

  goto Main_Loop

 

1. Is the concept OK? Is there a better way to tell time?

2. How do I know when frame advanced (when does Frame_Counter = Frame_Counter + 1)?

 

Thanks

Link to comment
Share on other sites

In most cases you can consider the time between "drawscreen" commands to be 1/60th of a second in NTSC.

 

Its actually slightly less than 1/60 and I'm assuming you didn't overun the allotted cycles in bB, but assuming that each tick of your timer is 1/60th of a second will work unless you're implementing a "clock program" that needs to accurately display the time for months.

 

You should be aware that your frame counter will reach 255 and start over at zero again. If you need more time you'll need another variable for minutes. (or 256*seconds)

 

Yes, this is the best method. The 2600 has a hardware timer, but its only useful for shorter intervals, and its already used by bB.

Link to comment
Share on other sites

If your program has a loop that contains one and only one 'drawscreen' statement in it, the loop will execute at a frequency of either 60 times a second or 50 times a second, depending on whether your program contains a 'set tv ntsc' or 'set tv pal' statement. Note that 'set tv ntsc' is the default, so if you omit the 'set tv' statement, the frame rate will be 60 times a second.

 

Actually, 60 times a second and 50 times a second are the approximate frame rates, so if you use a timer that's driven by the frame rate, it won't keep accurate time, but it should be more than accurate enough for most games.

 

Here's a simple program that displays hours, minutes, and seconds in the score. You can reset the timer by pressing the joystick button. If you have an accurate clock that displays seconds, and reset the timer to coincide with 0 seconds on the clock, then let the program run unattended for a while, you should be able to see that the seconds do not stay in sync between the clock and the program.

 

  dim frames=a
  dim seconds=b
  dim minutes=c
  dim hours=d

  scorecolor=$0E

loop

  if joy0fire then gosub reset_timer

  drawscreen

  frames=frames+1
  if frames=60 then frames=0:seconds=seconds+1:score=score+1
  if seconds=60 then seconds=0:minutes=minutes+1:score=score+40
  if minutes=60 then minutes=0:hours=hours+1:score=score+4000

  goto loop

reset_timer

  frames=0:seconds=0:minutes=0:hours=0:score=0

  return

To make it PAL/50 compatible, add 'set tv pal' to it, and change the line after 'frames=frames+1' to 'if frames=50' instead of 'if frames=60'.

 

For a racing game, you probably want to display the fractions of a second, so you could take out the hours and change the lines between 'drawscreen' and 'goto loop' to be as follows:

 

  frames=frames+1:score=score+1
  if frames=60 then frames=0:seconds=seconds+1:score=score+40
  if seconds=60 then seconds=0:minutes=minutes+1:score=score+4000

Again, you would change it to 'if frames=50' for a PAL/50 game.

 

If you 'dim' the three bytes of the score, you could use them directly instead of having to use three variables for 'frames', 'seconds', and 'minutes', as follows:

 

  dim minutes=score
  dim seconds=score+1
  dim frames=score+2

  scorecolor=$0E

loop

  if joy0fire then gosub reset_timer

  drawscreen

  score=score+1
  if frames=$60 then score=score+40
  if seconds=$60 then score=score+4000

  goto loop

reset_timer

  score=0

  return

I'm not certain what you mean by your other question, so I'll answer it two ways.

 

If you want to know the time between two presses of the fire button but want the timer to keep running, you'll need to have separate variables to keep track of the timing between presses of the fire button.

 

But if you want the fire button to stop the timer, you can just use the score, as follows:

 

  dim minutes=score
  dim seconds=score+1
  dim frames=score+2
  dim timer_running=a

  scorecolor=$0E

loop

  if joy0fire then timer_running=timer_running^1

  drawscreen

  if timer_running then score=score+1
  if frames=$60 then score=score+40
  if seconds=$60 then score=score+4000

  goto loop

This isn't perfect, because you really need to debounce the fire button, otherwise it's almost impossible to press it just once.

 

Michael

Edited by SeaGtGruff
Link to comment
Share on other sites

As long as the total race time would not exceed 100 minutes (which is plenty), you could divide the existing score to include framecounting as the low 2 digits (so they would be the means to display 50th or 60th fractions of a second). Saves a variable...and the total race time can go up to 99:59.59 or 99:59.49 before rolling over. Otherwise, you could use floating-point multiplication to approximate 100th's of a second.

Link to comment
Share on other sites

As long as the total race time would not exceed 100 minutes (which is plenty), you could divide the existing score to include framecounting as the low 2 digits (so they would be the means to display 50th or 60th fractions of a second). Saves a variable...and the total race time can go up to 99:59.59 or 99:59.49 before rolling over. Otherwise, you could use floating-point multiplication to approximate 100th's of a second.

Crikey, I didn't think about how PAL/50 would display 00 to 49 instead of 00 to 59 in the 'jiffies' digits (which I called 'frames'). But I don't know about floating-point multiplication-- not that it wouldn't work, because obviously it will. I'm just thinking it might be simpler/faster to use fixed-point addition, or maybe use a table lookup (which would take either 50, 60, or 110 extra bytes of ROM for the table). Or if you let the frames go up to 59 for NTSC/60 or PAL/60, you'd need to change them only for NTSC/50 or PAL/50.

 

Michael

Link to comment
Share on other sites

Might be better to just use 10ths of a second instead (updating every 5 or 6 frames, depending on refresh rate)...then use the leftover sprite position from the 6-digit display to use as a decimal point. In that case, 1 byte of temp ram would be needed to hold the actual vs. displayed value of score3.

Link to comment
Share on other sites

I figured out how to do hundredths of a second without any ROM tables, fixed-point or floating-point math, or extra variables.

 

For PAL, just add 2 to the score each frame. When you get to 50 frames, the seconds will automatically increment by themselves! Then all you need to do is check to see when you've reached 60 seconds so you can increment the minutes.

 

For NTSC, you need to add 5 for every 3 frames, or 1-and-2/3 every frame. With a digital display you'd drop any remainders instead of rounding up, so the addition will follow the pattern of +1, +2, +2, +1, +2, +2, +1, +2, +2, etc. Again, the seconds will automatically increment themselves when you get to 60 frames.

 

If you don't want to waste a variable for keeping track of whether you're using NTSC or PAL, just set a const named ntsc. Set it to 1 for NTSC, or to 0 for PAL.

 

  set tv ntsc
  const ntsc=1

  dim minutes=score
  dim seconds=score+1
  dim frames=score+2

  scorecolor=$0E

loop

  if joy0fire then score=0

  drawscreen

  score=score+2
  if !ntsc then skip_ntsc

  temp1=frames&$0F
  if temp1=2 || temp1=7 then score=score-1

skip_ntsc

  if seconds=$60 then score=score+4000

  goto loop

For PAL, just change the first two lines:

 

  set tv pal
  const ntsc=0

It goes ahead and adds 2 to score, since that will be the most likely addition. Then, if it's PAL (or not NTSC), it skips ahead to check the seconds. Otherwise (if it *is* NTSC) it checks the last digit of the already-incremented score. If the last digit is 2 or 7, it subtracts 1 from the score. So for NTSC the pattern for the hundredths of a second will be as follows:

 

00 (or .0000)

01 (or .0167)

03 (or .0333)

05 (or .0500)

06 (or .0667)

08 (or .0833)

10 (or .1000)

11 (etc.)

13

15

16

18

20

21

23

25

26

28

30

etc.

 

Of course, this is just using the score "as is"-- no extra characters for fancy formatting. To put a colon in the 2nd position would require changing the if-then for the seconds check, and would limit you to a maximum of 9 minutes and 59+ seconds. To put a decimal in the 5th position would require using a variable for the frame counter, as Nukey Shay said, but the logic would be a bit simpler than the example above, since you'd just increment the 6th digit every 5 or 6 frames depending on the TV type. It would still be a little tricky, because you'd have to make sure the addition doesn't destroy the decimal point, and manually update the seconds as needed.

 

Michael

Link to comment
Share on other sites

Alternate .asm methods for colon/decimals:

 

Different digit GFX (those with and without such characters)...no extra cycles needed in the display loop. When the kernel is setting the LSB's or MSB's for a digit, just bump it to the alternate set for the digits you want affected.

 

Using the ball sprite as divider(s)...7 cycles needed in the display loop, none if the divider is just a vertical line as tall as the digits.

 

When printing the score, is this a seperate bB module? I noticed that a custom logo display has been added which can be displayed above scores. Since that is the case, you could potentially use that routine and leave the score alone for other uses.

Link to comment
Share on other sites

Here's an example that displays an edited timer-- minutes in the 1st position, a colon in the 2nd position, seconds in the 3rd and 4th positions, a decimal point in the 5th position, and tenths of a second in the 6th position. That means the timer can go up to only 9:59.9 before wrapping around to 0:00.0, which should probably be okay for a racing game. The program will work for either NTSC/60 or PAL/50. You'll need a modified includes file and score graphics file (attached below).

 

  includesfile timer.inc

  set tv ntsc
  const one_tenth=6

  dim minutes=score
  dim seconds=score+1
  dim tenths=score+2
  dim frames=a

  scorecolor=$0E

loop

  if joy0fire then score=0:frames=0

  tenths=tenths|$A0
  minutes=minutes|$0B

  drawscreen

  frames=frames+1:if frames<>one_tenth then skip_tenths

  frames=0
  tenths=tenths&$0F
  minutes=minutes&$F0
  score=score+1
  if tenths=$10 then score=score+90
  if seconds=$60 then score=score+94000

skip_tenths

  goto loop

Since the score is a BCD number, and we want to use all the decimal digits (0 through 9), I defined "digit 10" ($A) to be a decimal point and "digit 11" ($B) to be a colon. If you want to set any of the score's digits to a non-BCD value (like $A or $B), you must directly set the appropriate byte of the score (e.g., tenths=$A0 or seconds=$0B). However, if you try to perform any math on the score while any of its digits contain a non-BCD value, the result will probably be garbled, or the new value probably won't be what you expected. So this example clears the colon and decimal from the score before doing any math on the score. Then the colon and decimal are restored to the score just before calling drawscreen.

 

To change it so it will work for PAL/50, change "set tv ntsc" to "set tv pal", and change "const one_tenth=6" to "const one_tenth=5".

 

Rather than alter the original score_graphics.asm file, I copied it to score_graphics_timer.asm and added the two extra characters. That means you need to use a modified includes file instead of the default.inc file, so batari Basic will compile the program with the score_graphics_timer.asm file. I copied default.inc to timer.inc and changed the score graphics filename. That means you must put an "includesfile timer.inc" statement at the beginning of the program so batari Basic will know it's supposed to compile the program using the timer.inc includes file.

 

If I remember correctly, the forum doesn't like you to attach .asm files, so I've zipped the includes file, score graphics file, and program file together. An NTSC/60 .bin and a PAL/50 .bin are also provided so you can run the program without having to compile it first.

 

Michael

racing_timer_ntsc60.bas.bin

racing_timer_pal50.bas.bin

timer.zip

post-7456-128488215641_thumb.png

  • Like 3
Link to comment
Share on other sites

When printing the score, is this a seperate bB module? I noticed that a custom logo display has been added which can be displayed above scores. Since that is the case, you could potentially use that routine and leave the score alone for other uses.

The score is part of the kernel, but there's an assembler directive between the game area and the score area that will call a minikernel routine if one's included, so it would be possible to put the timer display in a minikernel and leave the score alone.

 

Michael

Link to comment
Share on other sites

SeaGtGruff and the others already gave the proper answer but..

 

Another technique is to update a single counter variable ("counter = counter + 1") every iteration of the main loop and just use single bits out of it to activate events.

 

I find that counter{0} is great for flip-flopping things every frame and counter{4} is good for walking animations.

Link to comment
Share on other sites

The score is part of the kernel, but there's an assembler directive between the game area and the score area that will call a minikernel routine if one's included, so it would be possible to put the timer display in a minikernel and leave the score alone.

 

What I mean by "seperate" is can that routine built into the main kernel be called more than once in the display? No need to reinvent the wheel...if it can be avoided. It would just be a matter of swapping ram used for the score with ram that is used for the timer, JSR to the display loop, then swap them back.

Link to comment
Share on other sites

The score is part of the kernel, but there's an assembler directive between the game area and the score area that will call a minikernel routine if one's included, so it would be possible to put the timer display in a minikernel and leave the score alone.

 

What I mean by "seperate" is can that routine built into the main kernel be called more than once in the display? No need to reinvent the wheel...if it can be avoided. It would just be a matter of swapping ram used for the score with ram that is used for the timer, JSR to the display loop, then swap them back.

No, it isn't separate in that sense. But the kernel could be customized to make the score routine a separate subroutine so it could be called (reused) for other situations.

 

On the other hand, if you're talking about swapping between the score and something else on different frames, I did it a while back to display an inventory strip without destroying the score. I customized the kernel to recognize two optional keywords named "userscore_flag" and "userscore_page," and I think batari might be planning to include those customizations in the next release of the standard kernel (they were easy to do, and don't mess up the timing). So that could be used to swap back and forth between the normal score and a timer that uses custom characters.

 

Michael

Link to comment
Share on other sites

Hi,

I embedded your code for the timer in my game (and copied timer.inc and score graphics .asm to my game folder). My problem is that the dots (one and two) are displayed as boxes!

 

Another problem I'm having is that the counter is blinking becuase of pfscroll down. I thought that counter was seperate from playfield (shouldn't be effected by vertical scrolling).

 

Thanks

post-27368-128541991249_thumb.jpg

Link to comment
Share on other sites

I embedded your code for the timer in my game (and copied timer.inc and score graphics .asm to my game folder). My problem is that the dots (one and two) are displayed as boxes!

Make sure you put "includesfile timer.inc" at the very beginning of your program-- it must be the first line, before anything else.

 

You also need to set the nibbles (or BCD digits) to display the colon and the decimal point right before calling "drawscreen." Then you have to clear them before doing any math on the score:

 

  tenths=tenths|$A0 : rem * set the decimal point
  minutes=minutes|$0B : rem * set the colon

  drawscreen

  tenths=tenths&$0F : rem * clear the decimal point
  minutes=minutes&$F0 : rem * clear the colon

In the code snippet above, I removed some lines between "drawscreen" and where you clear the decimal point and colon, to help emphasize the placement of the statements relative to "drawscreen"-- but you need those other lines in there, so don't take them out.

 

Another problem I'm having is that the counter is blinking becuase of pfscroll down. I thought that counter was seperate from playfield (shouldn't be effected by vertical scrolling).

It is separate, and it shouldn't be affected by scrolling the playfield. I just added a playfield to my example and scrolled it, and it didn't affect the timer-- no flickering or blinking. The only thing I can think of is that your loop may be too long, causing the screen to roll. If you're using the Stella emulator, press Alt-L while the program is running, to display the number of lines in the upper left corner-- they should remain steady at either 262 (for NTSC) or 312 (for PAL). If they don't, you'll need to figure out what you can do to save time. Note that you don't need to put playfield and player statements inside your loop, because once you set them, they'll keep their graphics until you need to set them again (i.e., if their graphics need to change). So if you've added a playfield statement inside your loop, move it to just above where the loop begins.

 

Also note that there's an exception to what I just said about the graphics. You *do* need to put any COLUP0 and COLUP1 statements inside your loop, so the player colors will get set properly each time you draw the screen-- otherwise the player colors will get changed to the scorecolor (since the score is drawn with the players).

 

Michael

Link to comment
Share on other sites

  • 4 years later...

Just in case anyone needs it - I'm posting a very minor modification to SeaGtGruff's racing timer code that I changed for my own game. This will cause the timer to count down rather than up. (See updated code below.) I set the clock to start at 2 minutes.

 includesfile timer.inc

   set tv ntsc
   const one_tenth=6

   dim minutes=score
   dim seconds=score+1
   dim tenths=score+2
   dim frames=a

   scorecolor=$0E
   score = 200000

loop

   if joy0fire then score=200000:frames=0

   tenths=tenths|$A0
   minutes=minutes|$0B

   drawscreen

   frames=frames+1:if frames<>one_tenth then skip_tenths

   frames=0
   tenths=tenths&$0F
   minutes=minutes&$F0
   score=score-1
   if tenths=$99 then score=score-90
   if seconds=$99 then score=score-4000

skip_tenths

   goto loop
Edited by graywest
Link to comment
Share on other sites

  • 3 years later...

Late to the party on this,

 

I've been using the timing code on a DPC+ project. Timer works fine but the separators appear as parts of my player sprites.

 

I've been trying to debug it but have come to the conclusion it may not work with DPC+.

 

Used a modified includesfile to ensure the score_graphics_timer.asm would be included. Compiles ok, but with corrupted separators.

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