Here is the "designing formula nibble" part of the article. Very cool how this thing works. every byte on the screen (between horizon and front edge of car) gets updated each frame, line by line. The shapes that are used ("bitmaps") are very simple. The posts get drawn over the top of the screen by a seperate routine. You could remove the posts, and add your own animated character in the sky :-) scanned from nibble mag: DESIGNING FORMULA NIBBLE Drawing the track was the biggest challenge of designing For- mula Nibble. The tracks are divided into segments, each represent- ing about 20 feet of actual roadway. The angle of each segment with respect to the previous segment is stored in one byte. It's a kind of turtle graphics approach to defining a curve: turn a bit to the left, go ahead one segment, turn a bit to the right, go ahead one segment, and so on. Enough memory is set aside for each track to allow up to four 256-segment blocks. At present, the Monaco track uses two blocks (512 bytes) and both the Detroit and Mon- treal circuits use three blocks. As you drive on the track, a pointer into the track data is incremented. The view you see displayed con- FIGURE 4: Straight Track From Right sists of the 24 segments that lie ahead of your current position. To see how this information can be used to draw a view of the track, imagine looking at the scene on the screen. Figure 3 shows what you would see if you were directly astride the track's center line. The segment of the track that is immediately in front of your car is at the bottom of the screen, the next segment is just above that and so on until all segments that are visible are displayed. Each segment is drawn a bit smaller than the preceding one to give a sense of perspective. Figure 3 shows only five segments of the 24 that are actually displayed, but the principle is the same. When you are looking down a straightaway, the center line simply heads straight up towards the horizon. Imagine moving to the right of the center line. You would now see something like Figure 4. In programming terms, the X- coordinate of the start of the center line has become smaller. To maintain proper perspective, the center line must now angle to the right so that it still meets the vanishing point in the middle of the horizon. For any given X-coordinate, we can calculate what the angle should be. The program uses precalculated values stored in a table and the X-coordinate as an index to find the correct value. So far, we have been talking about straight sections of track. Sup- pose that the information for the segments up ahead indicates that the track curves to the left. In that case, we start out as before, but the angle of the second segment turns more to the left. The next segment is angled even more to the left, and so on until you have a view like Figure 5. To put it all together: the angle of the first segment is determined by the X-coordinate of the track center and each succeeding segment's angle equals the previous angle plus any change indicated by the segment's data. Since we know the location of the center line, it is easy to deter- mine where the track edges are. As Figure 6 shows, subtracting the width of the track lane determines the X-coordinate of the left edge, and adding this same width determines the X-coordinate of the right edge. Another table holds the widths to be used for each screen line, or Y-coordinate, in the track view. The widths decrease as you go up the screen to give a sense of perspective. The angles for the center line are expressed in terms of the change in the X-coordinate (delta X). For each increment of the Y- coordinate, the X-coordinate changes by delta X. If delta X is zero, then the line heads straight up the screen. If it equals one, then for each Y-coordinate, the X-coordinate increases by one. This would generate a 45-degree angle. Since we will want to show angles be- tween 0 and 45 degrees, delta X must be able to take on a frac- tional value. Machine language variables are not very good at expressing fractions, so one byte is used to hold the integer por- tion of the number, and a second byte contains the fractional part. Each segment of track is drawn one screen line at a time, start- ing at the bottom of the segment and working up. For each line, FIGURE 5: Curved Track the track center X-coordinate equals the previous X-coordinate plus delta X for the new segment. Once we know the X-coordinates for the track center and the left and right track edges, then the screen line can be drawn. The basic algorithm for drawing a horizontal screen line can be described like this: Start at the left edge of the screen and draw whole bytes of the grass pattern up to the left track edge. Draw the two bytes that form that edge, then draw bytes of the track surface pattern up to the X-coordinate of the center line. After drawing the center line, continue with more bytes of the track surface up to the right track edge. That edge's bytes come next, followed by bytes of the grass pattern stretching to the right edge of the screen. The procedure is fairly quick, since whole bytes of the image are drawn at once. This allows the entire view of the track to be redrawn in each frame. The actual bit patterns used for the track edges are standard pre- shifted shapes. That is, there are seven copies of each shape, one for each possible starting position within a screen byte. Four sizes of the left and right track edges are used, in white and purple. As the segments are drawn, a counter is incremented so that every third segment has purple track edges instead of white. As the player ad- vances along the track, the starting value for this counter is up- dated. This ensures that the colored edges will stay in sync with the segments as they move past. The methods used to store data for an entire track are discussed in the Designing a Track section. The procedures described above create the basic view of the track that appears just above the player's car. Since it draws each screen line all the way across, it overwrites the curved nose of the car and the top of the tires. These sections must be redrawn in every frame of animation. To avoid flickering as they are erased and then restored, both Hi-Res screens are used. As one frame of animation is displayed, the next is drawn on the hidden screen, and then it's displayed. The variable SCRNNUM keeps track of which screen is being displayed and, therefore, which screen should be drawn on next. The routines that draw the other graphic elements (e.g., the hands on the steering wheel, the tires, the starting lights and the dash- board instruments) work much alike. In each case, the routine first determines which version of the shape to display. For example, the hands are normally shown steering straight ahead. If the player is turning sharply enough to the left or right, then the appropriate version of the hand shapes are used instead. Each version of the shape is stored in memory as a block of bytes. A table stores the addresses of the start of each version. The routine picks the proper address out of the table and modifies the actual drawing code so it will use the correct shape. Then the shape is drawn on the screen, one row at a time. FIGURE 6: Calculations for Track Edge Curve Rating Left Right 0 0 0 1 240 16 2 224 32 3 208 48 4 192 64 5 176 80 6 160 96 7 144 112 TABLE 1: Conversion Table for Curve Data TABLE 1: Conversion Table for Curve Data In most of the drawing routines, the Y-Register indicates which byte on the screen line is being modified, and the X-Register acts as an index to the bytes of the shape. These bytes are simply placed in the Hi-Res screen's memory. However, some of the routines in the Hi-Res screen's memory. However, some of the routines display them in different ways. The routine to draw a starting light XOR's the bytes with the existing screen bytes. This allows it to XOR's the bytes with the existing screen bytes. This allows it to be used both to draw a starting light and, when used a second time, to erase it. Vehicle dynamics were the next problem. Most important was the simulated skidding. The calculations that determine when the car should skid were relatively simple. The problem was deciding what the car should do when skidding occurred and how to show it effectively. At the risk of oversimplifying, there are two basic types of skids, understeer and oversteer. Understeer occurs when the car's front tires lose grip, and the car just plows straight off the road. Oversteer usually occurs when the rear tires refuse to slow down at the same rate as the rest of the car, and the back end swings around. I would have preferred to show the oversteer type of skid. the road. Oversteer usually occurs when the rear tires refuse to slow down at the same rate as the rest of the car, and the back end swings around. I would have preferred to show the oversteer type of skid. down at the same rate as the rest of the car, and the back end swings around. I would have preferred to show the oversteer type of skid. around. I would have preferred to show the oversteer type of skid. It's more dramatic, leaving no doubt that you have gone beyond the limits of your tires, but the driver's view during a spin made for jerky, confusing graphics. Therefore, Formula Nibble uses the understeer type of skid. When your car goes into a skid, you lose steering control and hear a special sound effect. MODIFICATIONS If you would like to try some modifications, experiment with the values for car capabilities. ACCEL and DECEL determine how fast the car speeds up and slows down. Try values in the range of 1 to 8 (line 186 in Listing 4). TOPSPD (lines 830-840 in Listing 5) must not be higher than 255 minus the ACCEL value. STRFACT (lines 830-840), the steering factor, is used in calculating how sharply one can turn before skidding. The lower the value, the more likely that the car will skid. Try a range of 1 to 10 for this. The RESPOND variable (line 184 in Listing 4) controls how quickly your inputs affect the car. Anything less than 64 will make the ac- tion seem too abrupt. You might also want to change the keys that are used when play- ing under keyboard control. In lines 270 and 280 of the BASIC program (Listing 5), the letters in quotation marks are the keys. Do not use the Space bar, Control-S, Control-R, or Control-Q, since they already perform functions in the game. DESIGNING A TRACK Designing your own track can be fun, too. As an example, I'll explain the method I used to create the Monaco track (Figure 7). First, sketch out the path of the track on paper. I searched through back issues of car magazines, found a drawing of Monaco, and used back issues of car magazines, found a drawing of Monaco, and used this as the basis for my sketch. Decide where the start/finish line will be, then divide the track into two to four equal-sized blocks. Each block will represent about one mile of track, so the number of blocks you use should be determined by how long you want the track to appear. The Monaco circuit is shorter than average at only two blocks, while Detroit and Montreal are both three blocks long. 1R 32 16 4R 16 64 0 56 0 3L 16 208 5L 12 176 6R 20 96 0 16 0 6R 16 96 0 16 0 7L 16 144 7R 16 112 5R 16 80 3R 8 48 BLOCK 1 3R 8 48 BLOCK 2 2R 48 32 0 56 0 5L 16 176 6L 8 160 6R 8 96 0 8 0 6R 8 96 6L 8 160 0 8 0 2L 12 224 7R 16 112 3R 28 48 1R 24 16 TABLE 2: Coding for Monaco Track Divide the blocks into 32 equal sections. Doing this will often reveal where you made one block longer than another, as the sec- tions turn out to be of different lengths. Fiddle around with the sec- tions until they are reasonably equal, but you don't need micrometer accuracy here. Now mark where each curve starts and ends. A curve often has portions with different radii. It may start out as a fairly broad curve and then turn more sharply. Mark the division between these portions. The second corner in the Monaco track is a good example. It begins with the portion labeled 3L and becomes tighter in the section marked 5L. Rate each curve or portion of a curve in terms of how sharp it is. Assign a 1 to the gentlest curves and use a 7 for the tightest curves. I also added a suffix to remind me if it curved left or right as seen from a car on the road. Straightaways are assigned a value of zero. Besides severity, you must also determine how long each curve is. As was mentioned previously, there are 256 segments in each block. If you have divided each block into 32 sections, then there will be eight segments per section. Use this as a guide to deter- mine how many segments are included in each curve. List the curves and straights in the order that you would drive through them. Next to the rating for each curve, mark down how many segments long it is. Double-check to make sure that the total length of all curves and straights in each block equals 256. Add another column to your list to translate the rating for each curve into a value the program can use. For left turns, use values of 240 (the broadest), 224, 208, 192, 176, 160 and 144 (the sharp- est). Right turns range from 16 (the gentlest) to 32, 48, 64, 80, 96 and 112 (the most difficult). Table 1 is a conversion table and Table 2 lists all of the data for the Monaco track. Use the curve rating column for comparison with Figure 7. FIGURE 7: Monaco Track Layout and Coding This information can be used in a BASIC program to POKE the track data into memory. Look at MAKE. TRK. DATA (Listing 3). The central routine is the simple loop in line 140. The number of times through the loop equals the length of the curve or straight- away, and the value POKEd into memory is the number from the third column of your list. Start the track data at memory address 32768, and with each pair of numbers, add the curve's length to the address so the next curve's data will be POKEd into the correct location. If your track does not use all four blocks reserved for it, make sure to fill up the extra space with zeros. For example, at the end of the Monaco data (line 290), you will see the pair of num- bers 512,0. This tells the loop to POKE 512 zeros into the two unused blocks, filling them up. This ensures that the next track's data will start at the right place in memory. After the last track's data, supply a pair of negative numbers in a DATA statement (line 400) to tell the loop that there is no more data. The easiest way to do all of this is to substitute your track's data for one of the tracks in the MAKE. TRK. DATA program. Once the BASIC program has POKEd the data into memory, it saves it to disk so FORMULA. NIBBLE (Listing 5) can load it back in later. Modify line 200 so that it contains the name of your modi- fied track data file. In line 170 of FORMULA.NIBBLE, substi- tute your filename in place of TRK.CURVE.DATA so that your custom track will be loaded instead of the standard one. Finally, you will probably want to change the track name displayed by the program. In line 180, substitute your name for " . . . MONACO" and the other track names. The name should be eight characters long. If it's shorter than eight characters, put periods in front of it to pad it up to eight characters. If you add other modifications to FORMULA.NIBBLE, be care- ful to keep it the same length it is now. It just fits (with only a few bytes to spare) between the top of the second text page and the bot- tom of the first Hi-Res screen. I would have liked to add an op- tions screen that would allow the user to modify the keyboard controls and car capabilities, but I just plain ran out of room. I've got to put on my racing gloves and take Formula Nibble out for a spin. With a bit more practice, I should be able to break 2:00.0 on the Detroit track.