              Spectrum Animation 16K and 48K



      Blast off into a new fast-action, flicker-free

      universe with Robert Newman's smooth-animation

                  machine-code routines.



[ This text should come with, or be found near, a TZX

  file with the same name, containing the machine code

  system, and demonstration, described below.

  The main part of this text was published in the April

  1983 issue of Your Computer. The next month, a short

  erratum was published. The text of this is found at the

  end of this file.

  It may be interesting to discover that this system was

  used at least twice: in August 1983, M. Furby used it

  in a Histograms program also published in Your Computer,

  and in May 1984, the magazine featured the game Ack-ack,

  written by A.M. Tucker, which used it as well.

  Note that everything between square brackets is a remark

  of my own, not the original article text.

                                Richard Bos, January 2012 ]



The provision of colour, sound and user-definable high-

resolution graphics on the Sinclair Spectrum encourages

many people to try writing arcade-style games for their

computer. Such programs require fast-action, flicker-free

graphics if they are to be successfull and exitingly

implemented on Spectrums.

  The usual method of producing the illusion of movement

involves first printing an object at one position, and then

erasing it and printing one character position further

along the screen. This method is certainly fast enough when

used in Basic programs on the Spectrum if only one or two

graphics characters require animation, but the movement has

a jerky appearance, because the smallest distance that a

character can be moved is one print position. There are

only 32 positions across the screen, or 22 from top to

bottom.

  Another disadvantage of Basic is that the action slows

down noticeably when several characters are required to

move, or if the graphics are large, involving printing on

a number of lines or across several columns. Most commer-

cially-written software uses machine code in order to

achieve the required speed and smoothness of movement, but

writing an entire game in machine code is not a task that

most home programmers would relish. It is therefore neces-

sary to consider other methods for speeding up the action

in Basic programs.



 Smooth routine



  On the ZX-81 it is possible to short-cut the Print state-

ment by Poking characters directly into the display file,

thereby getting slightly faster graphics. Unfortunately the

Spectrum's display file is laid out in a very complicated

fashion - see page 164 of the manual - and it is not really

feasible to do the same thing on this computer.

  For this reason I have written a machine-code routine

especially for the purpose of enabling games programmers to

obtain faster, smoother animation from Basic. It is inten-

ded to be used with user-defined graphics characters, which

can be made as large as desired and printed by a single

call to the routine. In addition, the graphics can be

located at any position on the 256 x 176 high-resolution

screen, and can therefore be made to move by as little as

one point at a time. This is a considerable improvement

over the coarse 32 x 22 resolution normally obtainable.

The colour of the grpahics can be controlled from Basic

with the normal Ink, Paper, Bright and Flash statements.

  The machine code occupies 197 bytes, and the safest way

to store it is to move RAMTOP downwards in memory, using

the Clear command, and place the code between the Basic

area and the user-defined graphics.

  The address of the routine will therefore different for

48K and 16K Spectrums. The routine itself, however, is the

same for both computers, and a dump of the machine code is

given in listing 1. Owners of 48K machines can use the

loader program in listing 2. Enter this program and Run it,

inputting the numbers from listing 1 as prompted: read the

numbers from left to right. I would advise you to check the

machine code before Saving it or attempting to use it. This

can be done with the same loader program by deleting lines

20, 30, 70 and 90, and changing line 80 to:

        80 PRINT TAB 10; PEEK i

If all is correct, you should Save the routine with the

command:

        SAVE "animate" CODE 65160,197

Owners of 16K computers need to make the following changes.

In listing 2, change line 20 to

        CLEAR 32389

and line 50 to

        FOR i=32390 TO 32586

Save the routine with the command

        SAVE "animate" CODE 32390,197

You can now test the routine by clearing the screen and

issuing the command:-

        RANDOMIZE USR 65171        48K

        RANDOMIZE USR 32401        16K

  Whereupon the character in user-defined graphic "a" -

usually a capital letter A - should appear at the top left-

hand corner of the screen. If this does not happen you have

made a mistake while entering the machine code.

  If the computer has crashed you must remember to reset

RAMTOP by giving the appropriate Clear command before

reloading your copy of the routine and checking it.

[The code is on the TZX under the name "animate", as sug-

gested above. It's at the 48K address, but as noted, it

is relocatable and can be loaded at any address desired,

including on the 16K.]

  If all went as expected, here is how to use the routine

from a Basic program. If you examine the disassembled

routine in listing 3 [not included], you will see that the

first 6 bytes are used as variables, XPOS, YPOS and so on.

These names will not be recognised if you try to use them

in a Basic program, but by Poking different values into

these six bytes you can control the operation of the

routine as follows.



 Routine control



  XPOS - address 32390 for 16K, 65160 for 48K - is the

X co-ordinate of the top left-hand corner when the graphic

character is printed on the screen. Possible values are the

same as are allowed for the PLOT command, that is 0 to 255.

  YPOS - address 32391 or 65161 - is the Y co-ordinate of

the graphic character when printed on the screen. It may

take values from 0 - bottom of screen - to 175 - top of

screen.

  WIDTH - address 32392 or 65162 - this is the number of

points left-right in the character to be printed.

  HT - address 32393 or 65163 - is the number of points

top-bottom in the character to be printed.

  MODE - address 32394 or 65164 - has the value 1 if you

wish to print a character at the current position, or 0 if

you wish to erase a block of WIDTH x HT points at the

current position.

  UDGCH - address 32395 or 65165 - this must have a value

from 1 to 21, and it tells the routine where to find the

data for the character that you want to print. A value of

1 means that the first byte of data is held at address USR

"a", that is, the first byte of the user graphic "a", while

a value of 21 means that it is held in address USR "u".

  Values Poked into these six bytes before calling the

routine will be unchanged on exit, so, if printing more

than one character, you may not need to update every byte.

You will get strange results, or possibly cause a crash if

you attempt to set XPOS and YPOS to values which do not

permit the character you wish to print to fit onto the

screen, and so your Basic program may need to include a

check to prevent this.



 Different colours



  The routine prints the graphic character in the colour

defined by the current contents of the system variable

ATTR T - location 23695. If you want to print characters in

different colours, you can set ATTR T from Basic without

changing the current print position by using a dummy print

statement such as

        PRINT PAPER 6; INK 1;

before calling the routine. The Flash and Bright statements

can also be used. [Note final semi-colon! Without it, you

would change ATTR P instead.]

  If you use the routine to print user-graphics consisting

of eight-by-eight points, then the method of storing the

pattern is exactly the same as described in chapter 14 of

the user manual. However, the routine can handle graphics

of any size, and the method for larger characters is

slightly different.

  Firstly, design your character on a piece of squared

paper. I am going to use the routine to move the character

across the screen by two points at a time, and so it is

best to leave a margin at left and right edges of two blank

columns. The operation of moving left or right by two

points and printing at the new position will then automati-

cally print over the old space invader, saving the trouble

of erasing it first. The character we want to use therefore

consists of 14 by 11 points.

[These paragraphs, and the following, refer to Figures 1

and 2, an ASCII approximation of which is:]



  +---First data byte---+ +-----Second byte-----+

  |   for each line     | |                     |

  .. .. .. .. .. XX XX XX XX .. .. .. .. .. .. ..

  .. .. .. XX XX XX XX XX XX XX XX .. .. .. .. ..

  .. .. XX XX XX XX XX XX XX XX XX XX .. .. .. ..

  .. .. XX XX .. .. XX XX .. .. XX XX .. .. .. ..

  .. .. XX XX .. .. XX XX .. .. XX XX .. .. .. ..

  .. .. XX XX XX XX XX XX XX XX XX XX .. .. .. ..

  .. .. .. XX XX XX XX XX XX XX XX .. .. .. .. ..

  .. .. .. XX .. XX .. .. XX .. XX .. .. .. .. ..

  .. .. .. XX .. .. XX XX .. .. XX .. .. .. .. ..

  .. .. XX .. .. .. .. .. .. .. .. XX .. .. .. ..

  .. .. XX .. .. .. .. .. .. .. .. XX .. .. .. ..

  Figure 1



  Figure 2

  .. .. .. .. XX .. .. .. .. XX .. .. .. .. .. ..

  .. .. .. .. XX .. .. .. .. XX .. .. .. .. .. ..



  If the width is not an exact multiple of eight, you must

add the required number of blank columns to the right-hand

edge. The width of the character is then divided into

eight-bit sections, which can be described by a Bin number

as usual and stored in the user-defined graphics area. A

program like that in listing 4 can be used for this. The

first byte of data for the character is going to be stored

in address given by USR "a". When entering data for your

own characters, remember that the data for the top line is

stored first, then the second line and so on.

  Since the space invader occupies 22 bytes, that is, all

of graphics "a" and "b" plus most of "c", the next unused

section begins at USR "d". This is where the four bytes of

data needed for the character in figure 2 can be stored.

When these two lines are printed over the bottom two lines

of the space invader, its legs will appear to move while it

moves across the screen. Enter and Run listing 4. You can

save the user-graphics if you wish with

        SAVE "chars"CODE USR "a",32

Erase listing 4 - you can do this with New since the

routine and the user-graphics are safe above RAMTOP - and

enter the program in listing 5. This will make a row of

seven multicoloured space invaders walk across and down the

screen in the manner so familiar to all devotees of the ar-

cade game. Note that all seven invaders can be erased with

one call to the routine when moving down a line by setting

MODE to 0, WIDTH to 140 and HT to 11 - lines 130-160.

  Other sections of the program are as follows: lines 300-

340 print the row of seven characters in the seven diffe-

rent Ink colours. Lines 200-260 call the subroutine at line

300 to print first the row of space invaders at a certain

position and then overprint their legs with the character

in figure 2.

  Lines 100-170 make the invaders move first left to right

across the screen, and then walk back in the reverse direc-

tion. Lines 20-60 make the invaders move down the screen

after walking across it.

[These two programs, combined, are in "Invaders" on the

TZX. I've modified them so that it determines whether it is

running on a 16K or 48K machine, loads the code at the

appropriate address, and sets a few variables instead of

POKEing into absolute addresses. This would also be useful

for relocating the routine, as described below. The origi-

nal listings are below; note that there was no 16K version

of listing 5.]



 Fast Graphics



  From this example, you should be able to see how the

routine can be used to advantage in your own programs,

producing spectacular, fast-action graphics.

  Finally, should you find that the user-defined graphics

area is not large enough to store the number or size of

characters that you wish to print with this routine, you

can relocate the routine and use a larger area of RAM for

character storage.

  This can be done very easily since the machine-code can

be put anywhere, provided that its first byte, that is,

XPOS, comes immediately after RAMTOP. [In fact, the routine

itself can be anywhere, provided that the 11 bytes after

RAMTOP are available for its variables and temporary work-

space.] For example, if you wanted to use the routine to

generate 40 characters per line printing, you would need to

define your own six-by-eight character set, or copy the

Sinclair one, misssing out the left and right hand margins

which give spaces between the letters. This would require a

large area of memory - about 800 bytes - for storage, and

so 48K owners would need to relocate the routine at, say,

address 64000 by issuing a command

        CLEAR 63999

and then loading with

         LOAD "animate" CODE 64000

  The user-defined graphics area can now be moved to start

at address 64300 by Poking system variable UDG - location

23675/6 - accordingly. This gives ample space for an alter-

native character set or for any other user-graphics.



-----------------------------

[Listing 1 was a decimal dump of "animate", listing 2 was a

simple decimal code loader, and listing 3 was a disassembly

of the same code.]



 Listing 4.



 10 REM character in figure 1

 20 FOR i=USR "a" TO USR "a"+21

 30 READ n: POKE i,n

 40 NEXT i

 50 DATA BIN 00000111,BIN 10000000,

   BIN 00011111,BIN 11100000,BIN 00111111,

   BIN 11110000,BIN 00110011,BIN 00110000

 60 DATA BIN 00110011,BIN 00110000,

   BIN 00111111,BIN 11110000,BIN 00011111,

   BIN 11100000,BIN 00010100,BIN 10100000

 70 DATA BIN 00010011,BIN 00100000,

   BIN 00100000,BIN 00010000,BIN 00100000

   BIN 00010000

 80 REM character in figure 2

 90 FOR i=USR "d" TO USR "d"+3

 100 READ n: POKE i,n

 110 NEXT i

 120 DATA BIN 00001000,BIN 01000000,

    BIN 00001000,BIN 01000000



 Listing 5.



    1 REM multicoloured invaders

    2 REM (c) R Newman 1983

    3 REM 48K version

    4 REM -----------------------

    5 CLEAR 65159

   10 PAPER 7: BORDER 7: CLS

   20 FOR y=160 TO 100 STEP -20

   30 GO SUB 100

   40 NEXT y

   50 INK 0

   60 STOP

   70 REM ***********************

  100 POKE 65162,14: POKE 65164,1

  110 FOR x=0 TO 100 STEP 2: GO S

 UB 200: NEXT x

  120 FOR x=100 TO 0 STEP -2: GO

 SUB 200: NEXT x

  130 POKE 65160,0: POKE 65161,y

  140 POKE 65162,140: POKE 65163,

 11

  150 POKE 65164,0

  160 RANDOMIZE USR 65171

  170 RETURN

  180 REM ***********************

  200 POKE 65161,y: POKE 65163,11

  210 POKE 65165,1

  220 GO SUB 300

  230 POKE 65161,y-9: POKE 65163,

 2

  240 POKE 65165,4

  250 GO SUB 300

  260 RETURN

  270 REM ***********************

  300 FOR c=0 TO 6: PRINT INK c;

  310 POKE 65160,c*20+x

  320 RANDOMIZE USR 65171

  330 NEXT c

  340 RETURN

  350 REM ***********************



-----------------------------------------------------------



[ The following erratum was published in the letters sec-

tion of May 1983's Your Computer. The version of the code

on the TZX has this correction already applied to it. ]



I apologise to readers using the machine-code routine

described in my article on fast animated graphics for the

Spectrum who have found that it does not work correctly

when "Width" is greater than 16-bits. The culprit is a

missing instruction LD (IX+9),8 which should come between

the instructions EX HL,DE and L4 DEC (IX+8) in listing 3.

If you have your original version of the machine-code

routine "Animate" on tape, then you should obtain a correc-

ted version as follows: reset RAMTOP to 65159 - 48K - or

32389 - 16K - with the appropriate CLEAR command. Load your

old version of "Animate".

  Enter and run this Basic program:

10 LET a=65160 (32390 for 16K)

20 POKE a+158,24

30 POKE a+159,37

40 FOR b=a+197 TO a+204

50 READ c: POKE b,c

60 NEXT b

70 DATA 78,235,221,54,9,8,24,211

80 SAVE "Animate"CODE a,205

