1989 · MicroStyle

Stunt Car Racer

This minisite was contributed by air. It’s agent-generated and needs a human editor. Clone https://github.com/gamesexplained/gamesexplained and follow kit/START.md to curate games/c64/stunt-car-racer with me to Gold.

The track is drawn in lines about seven times a second, into whichever of two pictures is hidden. The race's clocks count those pictures rather than time, and the races the player does not drive are settled by a roll of the dice.

01 · The view

The view is redrawn about seven times a second

The dashboard, the wheels and the flame change every frame, fifty times a second. The view of the track changes once every seven frames or so, when a new picture of it is finished.

Sixteen frames in a row of a practice race on Little Ramp, from the Play tab's game. A blue square marks a frame whose view is new: the interrupt has swapped the bitmap on show, from the one at $4000 to the one at $6000 or back.

Each pass of the race (RACE_LOOP, $3D05) reads the controls, moves the car and the opponent one step, and draws the view into the bitmap that is not on show. Then it asks the raster interrupt to swap the two (REQUEST_FLIP), and the interrupt does so at the top of the next frame, so the picture never tears. A pass on Little Ramp takes about seven frames.

The view is drawn piece by piece from the car forwards, four pieces of track a pass (DRAW_VIEW, $167A). Each piece's corners are turned into the eye's frame, projected onto the screen, joined by lines and filled.

As the C64-Wiki notes, a poke raises the draw distance: more of the track is drawn, and the game runs slower. The number of pieces drawn after the first two is the 2 in LDA #$02 at $173D, so 6 poked into $173E draws eight pieces in all. A pass then takes 8.8 frames in place of 7.1, which is about 5.7 pictures a second in place of 7, and the race clock, which adds 0.14 seconds a pass, falls further behind real time. The Play tab's Far view switch makes the same change, and with Fast CPU on it costs no speed.

02 · The clocks

The race clock counts passes, not seconds

The clock on the dashboard adds 0.14 seconds every pass of the race, the time seven frames take. When a pass takes longer than seven frames, the clock falls behind the real time.

60.0 sof racing
passes of the race
on the race clock
slow

The clock is a minute of real racing at fifty frames a second. TICK_CLOCK ($109C) adds $14, 14 hundredths in decimal, to the clock once a pass. A pass on Little Ramp took 7.25 frames on average over 500 frames (69 passes), so the clock showed 9.66 seconds for ten seconds of play.

Lap times and the best lap are read off these clocks too. A track whose view takes longer to draw has a slower clock, so a lap there reads faster than it took.

03 · Damage

Hard landings crack the car, and big bumps put holes in it

The car rests on three springs. A landing that presses a spring past the track's damage line adds to the damage, and the crack across the top of the windscreen grows to match.

The springs keep a count of presses in a row ($E1), and a press adds damage only while that count is below a number the track sets: 3 on Roller Coaster, 10 on Big Ramp (WHEELS_ON_ROAD, $0A97). The Tracks tab lists the number for every track.

The crack is cut into the bitmap a pixel pair at a time (CRACK, $1B88). When it reaches the far side, or the damage reaches 128, the car is wrecked. A bump of 20 or more also takes one of the car's ten whole parts ($C719), drawn as a hole in the damage bar. A crack that grows into a hole adds damage rather than length.

The holes stay from race to race through a season and into the next. The car gets all ten parts back only after a season that ends with the player in the bottom division or as the winner of the top one (CHANGES, $375D). A practice race puts the parts back as they were before it.

04 · Tracks

Each track is a loop of pieces on a grid

The eight tracks are stored as descriptions, and the game builds a track from its description before every race.

Little Ramp seen from above, as the game shows it before a practice race

Little Ramp from above, in VICE, before a practice race. The Tracks tab shows every track this way, from all four sides.

BUILD_TRACK ($EA34) reads a track's description (the pointers at $B220) into the tables at $0400-$0773: each piece's kind, the square of the map it sits on, its heights, its ends and its distance round the track. Little Ramp has 44 pieces, and Roller Coaster and Draw Bridge have 78 each. The same description sets the track's boost and how forgiving its springs are.

05 · The league

The races you do not drive are settled by dice

Each division has three drivers and one race a round. Every race the player is not in, in every division, is worked out from two numbers.

against
the winner takes the fastest lap

 

The odds count every pair of the two drivers' rolls as equally likely. Before each round of races RACE_OTHERS ($E87F) gives each driver a rating: its base from the table at $E8B6, 120 for Hot Rod down to 20 for Road Hog, plus 0 to 63 at random. RACE_RESULT ($E92C) then gives the race to the higher rating, a tie to a coin, and the fastest lap to the winner unless a draw of 96 in 256 gives it to the loser.

A win is worth two points and the fastest lap one. Points tie-break on wins, then on a coin (SORT_DIVISION, $E9A3). A season is six races, four of them the player's, and at its end the winner of each division goes up and the last comes down. Out of Division 1 only the player goes up, into the Super League.

How each of these drivers races you, from the line it picks to how often it swerves, is on the Opponents tab.

06 · Sound

Sound: the engine is two voices an octave apart

There is no music in this game. The engine is two of the SID's voices an octave apart, and the sound effects come and go over it on the third.

Each button runs the game's own sound code, its bytes from the listing, on a 6502 in the page. A practice race on Little Ramp is twenty seconds of a race played on the Play tab: the crane sets the car down, it pulls away and speeds up, runs off the edge of the track, lands hard and is wrecked. Every call the race made to the sound's routines is played back in the frame it came in, with the bytes they read: the car's speed, whether its wheels are on the road, the stick and the random number. The other buttons start one effect each, as the game's own callers start it, with the engine's voices silent. test_sound.js holds every frame of the race to the Play tab's, register by register.

EffectWhenWhat voice 2 playsWhere
0a key is taken on the keys screena square wave at $5000, its gate held 4 framesREDEFINE_KEYS $97AF
1every pass while a wheel is over the road's edge, and while a wrecked car's pieces flynoise at the pitch the caller puts at $AF8C: the speed plus 2, from $0A to $34, and now and then $05 or $0F; $0A on a wreck; held 30 framesDUST $2C6F, DUST_WRECKED $2C51
1a bump of 20 or more takes one of the car's parts: on that pass and the nextthe same noise at $2000DAMAGE $10D9
2the cars push each othernoise at $1400, held 30 framesOPP_PUSH $2176
3a wheel lands hardnoise at $0300, at full volume from the start, held 3 framesWHEELS_ON_ROAD $0A97
4a bump adds damage and takes no parta square wave at $6400, held 1 frameDAMAGE $10D9
5, 6the race startsnothing: they set voices 3 and 1 up for the engine, with no waveform and the gate offSTART_SOUNDS $3F27

The engine's note follows the car's speed along the road, forwards or backwards (ENGINE_SOUND, $E104, once a pass). The note it aims for is the speed plus 5, times 32, and it sets the step the raster interrupt adds to the note every frame ($CF0F) to an eighth of the way there, so a pass of seven frames covers most of the gap. Voice 1 plays the note and voice 3 half of it, an octave down, both a pulse wave a little narrower than square, whose width each pass sets at random. At rest the note is 160, a low buzz of about 9 Hz; at the speed the race above reaches it is about 1,850, 109 Hz.

With no wheel on the road the speed counts as 0, the engine idling, unless the stick is pushed forward or back: then it counts as 200, the engine racing with nothing to push against. The note climbs at most 256 a frame, and falls at most 256 a frame on the road and 32 in the air, so the revs die away slowly while the car flies. Both voices go through the filter, with all three of its modes on, its resonance at 15 and its cut-off rising with the speed, from $6E to $E6. The volume is 5 of 15.

A sound effect is seven bytes at $AF80, eight apart: the voice, the waveform, the envelope, the pitch, the pulse width and how many frames its gate is held (START_EFFECT, $8655). Every effect in a race is on voice 2, and the interrupt counts its frames down (EFFECT_TICK, $86EF): it lets the gate go, waits as long as the release takes, and then silences the voice. An effect that starts while another plays cuts it off, so the stones are one long hiss, started again every pass, and their pitch follows the speed.