--- title: "3D Driver" id: 53794 type: "computer_media" slug: "driver" url: "http://localhost/computer_media/driver/" markdown_url: "http://localhost/computer_media/driver.md" published_at: "2024-05-13T18:56:52+00:00" modified_at: "2026-03-30T21:40:51+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/05/3d-driver.png" excerpt: "Steer a UDG-rendered car down a perspective road while random drift fights your inputs — stay on track as long as you can to maximize your score." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 53877 title: "SINCUS Exchange Tape 101 – Entertainment" type: "computer_media" url: "http://localhost/computer_media/sincus-exchange-tape-101-entertainment/" - id: 55430 title: "Timex Sinclair Public Domain Library Tape 2004" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-2004/" - id: 55711 title: "ISTUG Public Domain Library 8" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-8/" media_type: "Program" images: - url: "http://localhost/wp-content/uploads/2024/05/3d-driver.png" related_content: - id: 21051 title: "Games for your Timex-Sinclair 2000" type: "book" url: "http://localhost/book/games-for-your-timex-sinclair-2000/" media_type_tags: "Game" --- This program is a single-player driving game in which the player steers a car (rendered using four custom UDG characters) along a road that converges toward a vanishing point, simulating a 3D perspective view. The car’s horizontal position is tracked by variable `p`, and the road edges are drawn each frame using PLOT/DRAW commands that project lines from the bottom of the screen to a horizon point. Random lateral drift is added each tick via `INT (RND*20)-10`, making steering progressively challenging. A score counter increments each frame the player stays on the road, and a crash triggers a descending BEEP tone sequence before prompting for replay. The UDGs (chars `\a` through `\d`) are defined by POKEing 32 bytes of bitmap data read from DATA statements at lines 9030–9060, forming the front view of a vehicle sprite. *** ## Program Analysis ### Program Structure The program is organized into several distinct sections: 1. **Initialization (lines 20–30):** Two subroutines set up UDG data and the screen, then the main loop begins. 2. **Main game loop (lines 40–120):** Draws the car sprite, checks boundary conditions, renders road perspective lines with XOR overdraw for erasure, reads player input, applies random drift, and increments the score. 3. **Crash handler (lines 1000–1050):** Redraws the car in FLASH/INK 2, plays a sound effect, displays the score, and prompts for replay. 4. **Screen setup subroutine (lines 8000–8990):** Sets colors, clears the screen, resets `p` and `sc`, and draws a top status bar. 5. **UDG loader subroutine (lines 9000–9060):** Reads 32 bytes from DATA and POKEs them into UDG addresses `USR "a"` through `USR "d"+7`. 6. **Remarks and save (lines 9500–9999):** Visual reference comments showing the UDG layout, followed by SAVE/VERIFY. ### Road Perspective Drawing The 3D road illusion is achieved with two PLOT/DRAW pairs. The left road edge is drawn from `(p-10, 159)` — the bottom of the screen near the car — to a vanishing point, using `DRAW -170+(p-10), -159`. The right edge similarly uses `DRAW -70+(p-10), -159`. These expressions mean the horizontal endpoint of each line shifts with the car’s position `p`, so the road always appears to lead toward where the car is heading, reinforcing the perspective effect. Lines 80–90 repeat the same PLOT/DRAW calls with `OVER 1`, which XOR-erases the previously drawn road lines before the next frame is rendered. This is a standard flicker-free animation technique on this platform, avoiding a full CLS each frame. ### Car Sprite via UDGs The car is a 2×2 grid of UDG characters (`\a\b` on the top row, `\c\d` on the bottom), displayed with `PRINT AT 15,15`. The 32 bytes of bitmap data across DATA lines 9030–9060 define the pixel patterns. Line 9500–9510 serve as a developer reference comment showing the intended layout of the four UDG characters. ### Input and Drift Mechanics Player steering is handled at line 100 using a compact Boolean arithmetic idiom: - `p = p + 4*(INKEY$="5") - 4*(INKEY$="8")` — pressing “5” moves left, “8” moves right, each by 4 pixel units per frame. Line 110 immediately applies random drift: `INT (RND*20)-10` produces a value in the range −10 to +9 each tick, making the car wander and increasing difficulty over time regardless of player input. ### Boundary Detection and Crash Line 50 tests whether `p` has gone out of the safe range 108–150. If so, control jumps to line 1000 (crash handler) rather than looping back. On a crash, lines 1000–1010 draw the final road position (without erasing), and line 1020 redraws the car sprite with `FLASH 1; INK 2` to signal a collision. ### Sound Effect The crash sound at line 1030 uses a `FOR` loop from 0 to 50, playing two BEEP calls per iteration (`BEEP .05,a` and `BEEP .0008,a`), producing a rising two-tone sweep that mimics a crash/alarm effect. ### Notable Techniques and Idioms - **Boolean arithmetic for input:**`4*(INKEY$="5")` evaluates the comparison as 1 (true) or 0 (false) and scales it, avoiding an IF/THEN branch. - **OVER 1 for erasure:** XOR plotting the same lines removes them without clearing the whole screen, preserving the status bar and sprite. - **LINE input for replay prompt:**`INPUT ... LINE a$` captures any ENTER keypress without requiring the user to type a specific value. - **Delay loop:**`FOR z=1 TO 120: NEXT z` on line 1050 introduces a brief pause after the score display before restarting. - **Unused line 1320:**`GO TO 50` at line 1320 is never reached by normal program flow and appears to be a dead code remnant. ### Potential Bugs and Anomalies | Line | Issue | | --- | --- | | `50` | Boundary check uses `p<108 OR p>150` but no road erase occurs before the crash jump, so the last road frame stays on screen — this is by design (lines 1000–1010 redraw it). | | `100` | Both INKEY$ calls are evaluated independently in the same statement; if both “5” and “8” are somehow pressed simultaneously (not possible on a real keyboard), the movements cancel. Not a real-world bug. | | `1320` | Unreachable dead code — `GO TO 50` with no path leading to line 1320. | | `8040` | The status bar uses 32 underscores printed at `AT 0,0` but the screen is 32 columns wide, which is correct; however, `PAPER 1` is only set for this PRINT, so the bar background relies on the INK/PAPER state rather than a persistent attribute — consistent with the `PAPER 0` set at line 8000. | ## Source Code ``` 10 REM 3D DRIVER from Games for Your Timex-Sinclair 2000, p.74 20 GO SUB 9000 30 GO SUB 8000 40 PRINT AT 15,15; INK 4;"\a\b";AT 16,15;"\c\d" 50 IF p<108 OR p>150 THEN GO TO 1000 60 PLOT p-10,159: DRAW -170+(p-10),-159 70 PLOT p+10,159: DRAW -70+(p-10),-159 80 PLOT OVER 1;p-10,159: DRAW OVER 1;-170+(p-10),-159 90 PLOT OVER 1;p+10,159: DRAW OVER 1;-70+(p-10),-159 100 LET p=p+4*(INKEY$="5")-4*(INKEY$="8") 110 LET p=p+(INT (RND*20)-10) 115 LET sc=sc+1 120 GO TO 50 990 STOP 1000 PLOT p-10,159: DRAW -170+(p-10),-159 1010 PLOT p+10,159: DRAW -70+(p-10),-159 1020 PRINT AT 15,15; FLASH 1; INK 2;"\a\b";AT 16,15;"\c\d" 1030 FOR a=0 TO 50: BEEP .05,a: BEEP .0008,a: NEXT a 1040 PRINT AT 1,10; PAPER 1;"You scored ";sc 1050 INPUT "Press "; INK 6;"ENTER"; INK 7;" to play again "; LINE a$: FOR z=1 TO 120: NEXT z: GO TO 30 1320 GO TO 50 7000 REM 8000 BORDER 0: PAPER 0: INK 7: CLS 8010 LET p=127 8020 LET sc=0 8040 PRINT AT 0,0; PAPER 1;"________________________________" 8990 RETURN 9000 FOR a=USR "a" TO USR "d"+7 9010 READ user: POKE a,user 9020 NEXT a: RETURN 9030 DATA 0,0,0,0,13,11,13,3 9040 DATA 0,0,0,0,176,208,175,192 9050 DATA 6,117,207,223,208,240,12,3 9060 DATA 102,174,243,251,19,15,48,192 9500 REM ab cd 9510 REM \a\b \c\d 9998 SAVE "Driver" LINE 0 9999 VERIFY "" ```