Skip to content

Burn, then let go

Separate heading, velocity and position to build inertial flight.

  • Sinclair ZX Spectrum
  • BASIC

Give the ship a short burn, then let go. It keeps moving. Turn its nose and it still follows the same path until another burn changes that motion.

We need three separate pieces of state:

State Variables Question it answers
Position x,y Where is the centre?
Heading h Where does the nose point?
Velocity vx,vy How does position change each update?

Replace lines 100, 340, 1010, 1020, 1060, 1070.

Add lines 280, 290, 300, 310, 320, 330, 4000, 4010, 4020, 4030, 4040, 4050, 4060.

changes.bas
 100 LET x=48: LET y=56: LET vx=0: LET vy=0: LET h=2: LET steps=0
 280 IF k$<>" " THEN GO TO 320
 290 LET vx=vx+.2 *a(h): LET vy=vy+.2 *b(h)
 300 LET speed=SQR (vx*vx+vy*vy)
 310 IF speed>3 THEN LET vx=3 *vx/speed: LET vy=3 *vy/speed
 320 LET nx=x+vx: LET ny=y+vy
 330 IF nx<22 OR nx>233 OR ny<30 OR ny>145 THEN GO SUB 3000: LET e$="Hull lost. Try a gentler burn.": GO TO 4000
 340 LET x=nx: LET y=ny: LET steps=steps+1
1010 PRINT AT 0,2; INK 5;"DRIFT";AT 0,19; INK 7;"FREE FLIGHT"
1020 PRINT AT 1,2;"Turn. Burn. Coast. Brake."
1060 PRINT AT 19,2; INK 5;"O/P turn   SPACE thrust"
1070 PRINT AT 20,2; INK 7;"Turn back to slow down."
4000 PRINT AT 1,0;"                                ";AT 1,2; INK 6;e$
4010 PRINT AT 20,2;"R plays again. Q quits.      "
4020 IF INKEY$<>"" THEN GO TO 4020
4030 LET k$=INKEY$
4040 IF k$="q" OR k$="Q" THEN GO TO 9000
4050 IF k$="r" OR k$="R" THEN GO TO 100
4060 GO TO 4030

RUN the changed program.

Complete source at this checkpoint
drift.bas
  10 GO SUB 7000
 100 LET x=48: LET y=56: LET vx=0: LET vy=0: LET h=2: LET steps=0
 110 GO SUB 1000: GO SUB 3000
 200 LET k$=INKEY$
 210 IF k$="q" OR k$="Q" THEN GO TO 9000
 220 IF k$="r" OR k$="R" THEN GO TO 100
 230 GO SUB 3000
 240 IF k$="o" OR k$="O" THEN LET h=h+1
 250 IF k$="p" OR k$="P" THEN LET h=h-1
 260 IF h=9 THEN LET h=1
 270 IF h=0 THEN LET h=8
 280 IF k$<>" " THEN GO TO 320
 290 LET vx=vx+.2 *a(h): LET vy=vy+.2 *b(h)
 300 LET speed=SQR (vx*vx+vy*vy)
 310 IF speed>3 THEN LET vx=3 *vx/speed: LET vy=3 *vy/speed
 320 LET nx=x+vx: LET ny=y+vy
 330 IF nx<22 OR nx>233 OR ny<30 OR ny>145 THEN GO SUB 3000: LET e$="Hull lost. Try a gentler burn.": GO TO 4000
 340 LET x=nx: LET y=ny: LET steps=steps+1
 350 GO SUB 3000
 370 GO TO 200
1000 BORDER 0: PAPER 0: INK 7: CLS
1010 PRINT AT 0,2; INK 5;"DRIFT";AT 0,19; INK 7;"FREE FLIGHT"
1020 PRINT AT 1,2;"Turn. Burn. Coast. Brake."
1030 PLOT INK 1;15,24: DRAW INK 1;0,128: DRAW INK 1;225,0: DRAW INK 1;0,-128: DRAW INK 1;-225,0
1060 PRINT AT 19,2; INK 5;"O/P turn   SPACE thrust"
1070 PRINT AT 20,2; INK 7;"Turn back to slow down."
1080 PRINT AT 21,2; INK 5;"R retry              Q quit";
1090 RETURN
3000 LET px=INT (x+.5): LET py=INT (y+.5)
3010 PLOT INK 7; OVER 1;px+c(h),py+d(h)
3020 DRAW INK 7; OVER 1;e(h)-c(h),f(h)-d(h)
3030 DRAW INK 7; OVER 1;g(h)-e(h),j(h)-f(h)
3040 DRAW INK 7; OVER 1;c(h)-g(h),d(h)-j(h): RETURN
4000 PRINT AT 1,0;"                                ";AT 1,2; INK 6;e$
4010 PRINT AT 20,2;"R plays again. Q quits.      "
4020 IF INKEY$<>"" THEN GO TO 4020
4030 LET k$=INKEY$
4040 IF k$="q" OR k$="Q" THEN GO TO 9000
4050 IF k$="r" OR k$="R" THEN GO TO 100
4060 GO TO 4030
7000 DIM a(8): DIM b(8): DIM c(8): DIM d(8): DIM e(8): DIM f(8): DIM g(8): DIM j(8)
7010 FOR i=1 TO 8: LET angle=(i-1)*PI/4
7020 LET a(i)=COS angle: LET b(i)=SIN angle
7030 LET c(i)=INT (5 *a(i)+.5): LET d(i)=INT (5 *b(i)+.5)
7040 LET e(i)=INT (-3 *a(i)-3 *b(i)+.5): LET f(i)=INT (-3 *b(i)+3 *a(i)+.5)
7050 LET g(i)=INT (-3 *a(i)+3 *b(i)+.5): LET j(i)=INT (-3 *b(i)-3 *a(i)+.5)
7060 NEXT i: RETURN
9000 PAPER 0: INK 7: PRINT AT 21,0;"Finished. RUN to try again.     ";: STOP

RUN, hold SPACE briefly, then release it. The ship begins moving northeast and continues after release. R starts a fresh attempt; reaching a wall ends the current one. Leave yourself space for the turn rather than holding thrust until the wall arrives.

A burn adds velocity

The new reset gives vx and vy zero. SPACE reaches line 290, which adds .2a(h) horizontally and .2b(h) vertically. That change in velocity is acceleration. Without SPACE, line 280 skips the burn and leaves both velocity components alone.

At the initial northeast heading, a and b are about .7071. One burn adds about .1414 to each velocity component. Two burns from rest give about .2828,.2828. A later update without thrust keeps those values.

The pair’s length matters. Adding .2 to both components would make diagonal thrust stronger than an eastward burn. Using our unit direction vector gives a total velocity change of .2 whichever heading we choose.

Every update, including those spent turning, calculates nx=x+vx and ny=y+vy. Those are candidate coordinates: where the ship would go next. An eastward vx of 1.2 adds 1.2 pixels each update, even if rounding means the picture sometimes moves one pixel and sometimes two.

Limit speed without bending the path

SQR calculates a square root. SQR (vx*vx+vy*vy) gives the vector’s length: the ship’s speed in pixels per update. Squaring removes the signs; travelling west is not a negative speed.

Above speed 3, line 310 multiplies both components by the same fraction, 3/speed. For a hypothetical velocity (3,4), speed is 5 and that fraction is .6. The result (1.8,2.4) has length 3 and the same direction. Limiting each component separately would distort that direction.

Test before committing

The centre must stay within x=22–233 and y=30–145. These limits leave space for the triangle inside the arena. The test is numerical; it never asks what colour a pixel is.

At this point in the loop the old ship has been erased. If nx or ny is outside the limits, line 330 draws it back at its last valid position and selects the failure message. The result routine waits for key release, then accepts R or Q.

Otherwise line 340 accepts nx/ny and increases steps. Line 350 draws the ship at its new centre. steps counts updates, not seconds: BASIC takes different amounts of time through different paths. This is also why short taps may be missed.

After a northeast burn, you turn the nose south without pressing SPACE. What changes in the motion?

Show the explanation

Only the heading changes. vx and vy retain their northeast components, and every update continues adding them to x/y. A southward burn would begin reducing vy, but turning alone cannot do that.

If releasing SPACE stops the ship, check that vx/vy are reset only at line 100. If turning redirects it immediately, check that position is updated from vx/vy, not directly from a(h)/b(h).

Sources

Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 9, chapter 18. Chapter 9 covers mathematical functions including SQR; chapter 18 describes keyboard input. The acceleration, speed cap and rectangular limits are rules of this game.

Run it here

This unit's program, built for you.

Program
drift.tap
Machine
ZX Spectrum 48K (PAL)

Download drift.tap