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