jubileebop Posted September 18, 2010 Share Posted September 18, 2010 Hi, I need help with a racing game: 1. I'd like to have a timer from start of race running on screen. I looked for a bB implementation of timers and found nothing. Does anyone know how to? 2. I'd also like to time the interval between key presses (fire button). Thanks Quote Link to comment Share on other sites More sharing options...
yuppicide Posted September 18, 2010 Share Posted September 18, 2010 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.. Quote Link to comment Share on other sites More sharing options...
jubileebop Posted September 18, 2010 Author Share Posted September 18, 2010 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) Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 18, 2010 Share Posted September 18, 2010 (edited) 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 September 18, 2010 by Random Terrain Quote Link to comment Share on other sites More sharing options...
jubileebop Posted September 18, 2010 Author Share Posted September 18, 2010 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 Quote Link to comment Share on other sites More sharing options...
RevEng Posted September 18, 2010 Share Posted September 18, 2010 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. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 18, 2010 Share Posted September 18, 2010 (edited) 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 September 18, 2010 by SeaGtGruff Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 18, 2010 Share Posted September 18, 2010 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. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 18, 2010 Share Posted September 18, 2010 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 Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 18, 2010 Share Posted September 18, 2010 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. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 19, 2010 Share Posted September 19, 2010 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 Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 19, 2010 Share Posted September 19, 2010 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. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 19, 2010 Share Posted September 19, 2010 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 3 Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 19, 2010 Share Posted September 19, 2010 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 Quote Link to comment Share on other sites More sharing options...
jubileebop Posted September 20, 2010 Author Share Posted September 20, 2010 This was very helpful THNX! Special thanks to River Patroller... Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted September 20, 2010 Share Posted September 20, 2010 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. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 20, 2010 Share Posted September 20, 2010 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. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 20, 2010 Share Posted September 20, 2010 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 Quote Link to comment Share on other sites More sharing options...
jubileebop Posted September 25, 2010 Author Share Posted September 25, 2010 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 Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 25, 2010 Share Posted September 25, 2010 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 Quote Link to comment Share on other sites More sharing options...
graywest Posted June 2, 2015 Share Posted June 2, 2015 (edited) 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 June 2, 2015 by graywest Quote Link to comment Share on other sites More sharing options...
+Muddyfunster Posted August 15, 2018 Share Posted August 15, 2018 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.