Chapter 18: Motion

BASin

Chapter 18: Motion

Summary

PAUSE, INKEY$, PEEK

Quite often you will want to make the program take a specified length of time, and for this you will find the PAUSE statement useful.

PAUSE n

stops computing and displays the picture for n frames of the television (at 50 frames per second in Europe or 60 in America). n can be up to 65535, which gives you just under 22 minutes; if n=0 then it means 'PAUSE for ever'.

A pause can always be cut short by pressing a key (note that Esc will cause a break as well). You have to press the key down after the pause has started.

This program works the second hand of a clock:

 10 REM First we draw the clock face
 20 FOR n=1 TO 12
 30 PRINT AT 10-10*COS (n/6*PI),16+10*SIN (n/6*PI);n
 40 NEXT n
 50 REM Now we start the clock
 60 FOR t=0 TO 200000: 
    REM t is the time in seconds
 70 LET a=t/30*PI: 
    REM a is the angle of the second hand in radians
 80 LET sx=80*SIN a: 
    LET sy=80*COS a
200 PLOT 128,88: 
    DRAW OVER 1;sx,sy: 
    REM draw second hand
210 PAUSE 42
220 PLOT 128,88: 
    DRAW OVER 1;sx,sy: 
    REM erase second hand
400 NEXT t

This clock will run down after about 55.5 hours because of line 60, but you can easily make it run longer. Note how the timing is controlled by line 210. You might expect PAUSE 50 to make it tick one a second, but the computing takes a bit of time as well and has to be allowed for. This is best done by trial and error, timing the computer clock against a real one, and adjusting line 210 until they agree. (You can't do this very accurately; an adjustment of one frame in one second is 2% or half an hour in a day.)

There is a much more accurate way of measuring time. This uses the contents of certain memory locations. The data stored is retrieved by using PEEK. Chapter 25 explains what we're looking at in detail. The expression used is

(65536*PEEK 23674+256*PEEK 23673+PEEK 23672)/50

This gives the number of seconds since the computer was turned on (up to about 3 days and 21 hours, when it goes back to 0).

Here is a revised clock program to make use of this:

 10 REM First we draw the clock face
 20 FOR n=1 TO 12
 30 PRINT AT 10-10*COS (n/6*PI),16+10*SIN (n/6*PI);n
 40 NEXT n
 50 DEF FN t()=INT (65536*PEEK 23674+256*PEEK 23673+PEEK 23672)/50): 
    REM number of seconds since start
100 REM Now we start the clock
110 LET t1=FN t()
120 LET a=t1/30*PI: 
    REM a is the angle of the second hand in radians
130 LET sx=72*SIN a: 
    LET sy=72*COS a
140 PLOT 131,91: 
    DRAW OVER 1;sx,sy: 
    REM draw hand
200 LET t=FN t()
210 IF t<=t1 THEN 
    GO TO 200: 
    REM wait until time for next hand
220 PLOT 131,91: 
    DRAW OVER 1;sx,sy: 
    REM rub out old hand
230 LET t1=t: 
    GO TO 120

The internal clock that this method uses should be accurate to about .01% as long as the computer is just running its program, or 10 seconds per day; but it stops temporarily whenever you do BEEP, or a LOAD or SAVE operation, or use the printer or any of the other extra pieces of equipment you can use with the computer. All these will make it lose time.

The numbers PEEK 23674, PEEK 23673 and PEEK 23672 are held inside the computer and used for counting in 50ths of a second. Each is between 0 and 255, and they gradually increase through all the numbers from 0 to 255; after 255 they drop straight back to 0.

The one that increases most often is PEEK 23672. Every 1/50 second it increases by 1. When it is at 255, the next increase takes it to 0, and at the same time it nudges PEEK 23673 up by 1. When (every 256/50 seconds) PEEK 23673 is nudged from 255 to 0, it in turn nudges PEEK 23674 up by 1. This should be enough to explain why the expression above works.

Now, consider carefully: suppose our three numbers are 0 (for PEEK 23674), 255 (for PEEK 23673) and 255 (for PEEK 23672). This means that it is about 21 minutes after switch-on - our expression ought to yield

(65536*0+256*255+255)/50 = 1310.7

But there is a hidden danger. The next time there is a 1/50 second count, the three numbers will change to 1, 0 and 0. Every so often, this will happen when you are half way through evaluating the expression: the computer would evaluate PEEK 23674 as 0, but then change the other two to 0 before it can peek them. The answer would then be

(65536*0+256*0+0)/50 = 0

which is hopelessly wrong.

A simple rule to avoid this problem is evaluate the expression twice in succession and take the larger answer. If you look carefully at the program above you can see that it does this implicitly.

Here is a trick to apply the rule. Define functions

10 DEF FN m(x,y)=(x+y+ABS (x-y))/2: 
   REM the larger of x and y
20 DEF FN u()=(65536*PEEK 23674+256*PEEK 23673+PEEK 23672)/50: 
   REM time, may be wrong
30 DEF FN t()=FN m(FN u(), FN u()): 
   REM time, right

You can change the three counter numbers so that they give the real time instead of the time since the computer was switched on. For instance, to set the time at 10.00am, you work out that this is 10*60*60*50=1800000 fiftieths of a second, and that

1800000=65536*27+256*119+64

To set the three numbers to 27, 119 and 64, you do

POKE 23674,27: POKE 23673,119: POKE 23672,64

In countries with mains frequencies of 60 Hertz these programs must replace '50' by '60' where appropriate.

The function INKEY$ (which has no argument) reads the keyboard. If you are pressing exactly one key (or a Shift key and just one other key) then the result is the character that that key normally gives; otherwise the result is the empty string.

Try this program, which works like a typewriter.

10 IF INKEY$ <>"" THEN 
   GO TO 10
20 IF INKEY$ ="" THEN 
   GO TO 20
30 PRINT INKEY$;
40 GO TO 10

Here line 10 waits for you to lift your finger off the keyboard and line 20 waits for you to press a new key.

Remember that unlike INPUT, INKEY$ doesn't wait for you. So you don't type Enter, but on the other hand if you don't type anything at all then you've missed your chance.

Exercises

  1. What happens if you miss out line 10 in the typewriter program?
     
  2. Another way of using INKEY$ is in conjunction with PAUSE, as in this alternative typewriter program.
    10 PAUSE 0
    20 PRINT INKEY$;
    30 GO TO 10
    

    To make this work, why is it essential that a pause should not finish if it finds you already pressing a key when it starts?

  3. Adapt the second hand program so that it also shows minute and hour hands, drawing them every minute. If you're feeling ambitious, arrange so that every quarter of an hour it puts on some kind of show - you could produce the Big Ben chimes with BEEP. (See next chapter.)
     
  4. (For sadists.) Try this:
    10 IF INKEY$ ="" THEN 
       GO TO 10
    20 PRINT AT 11,14;"OUCH!"
    30 IF INKEY$ <>"" THEN 
       GO TO 30
    40 PRINT AT 11,14;"     "
    50 GO TO 10
    

Chapter 19

Chapter 17