Значок ресурса

Smooth Moves

Нет прав на скачивание
Автор: Simon N. Goodwin
Год: 1984
Издатели: Your Spectrum
Языки: 🇬🇧 Английский
Формат: 📼 TAP лента
Требования: 🖥️ ZX Spectrum 48K

Ссылки:
Страница на ZXArt
Страница на World Of Spectrum
Страница на Spectrum Computing

Скриншоты:
SmoothMoves.gif


!0.......^.........^.........^..


!B


\H11\H07\H10\H02 SMOOTH MOVES


\H11\H01


!2.......^.........^.........^.........^.........^.........^....


Does your Speccy output sometimes look like it's suffering from


a bad case of the shakes? Relax ... let things slide with Simon


Goodwin's cure for jerky graphics!


!1.......^.........^.........^.........^........





Presented here is a short machine code routine


that lets you move graphics smoothly around the


screen, without suffering the restrictions of


the Spectrum character grid. Graphics and ASCII


characters can be positioned at any high res-


olution coordinate with a simple Basic command.


You're not restricted to the 704 'PRINT pos-


itions' - rows zero to 21 and columns zero to 31


- you can place characters at any point on the


256 by 176 Hi-res grid.


The program uses only 120 bytes of memory and


is completely relocatable, which means that you


can load it anywhere in memory. It works without


problems on a 16K computer. Another advantage


over the usual PRINT AT command is that this one


allows you to use an extra ninety-odd user-


defined graphics. In addition to the usual 21


user-defined graphics (character codes 144-164),


you can define and position characters 165 to


255 with the YS Smooth Move routine.





!0.......^.........^.........^..


!B


INTO LOAD MODE


!1.......^.........^.........^.........^........


The Basic listing loads the machine code into


any area of memory. Type in the listing, taking


care over the DATA statements, and then decide


where you wish to store the code. On a 48K Spec-


trum you might want to put the code at address


64500. Type CLEAR 64499 to tell Basic that it


must not use addresses above 64499, and then RUN


the program. You'll be asked for a "Load


address" - enter 64500. The program reads the


DATA and stores it from memory address 64500


onwards.


If you've made a typing error in the DATA, an


appropriate message will appear. Correct the


error and RUN again. Don't test the routine


until the "Position character ..." message


appears; the code is then ready for use. It's a


good idea to SAVE everything, just in case an


error has slipped past the 'check' in the


loader.


On a 16K Spectrum (assuming you have no other


machine code in memory) you might put the code


at address 31670. Type CLEAR 31669 and then


specify a "Load address" of 31670. Of course,


you can load the code anywhere you like,


although it's best to protect it with the CLEAR


command, or it could be overwritten by Basic.


The routine provides a Hi-res version of the


command:


!0.......^.........^.........^..


PRINT INK 8; PAPER 8; OVER 1;


AT y,x;CHR$ c


!1.......^.........^.........^.........^........


The syntax is rather different:


!0.......^.........^.........^..


RANDOMIZE x AND y=c+USR a


!1.......^.........^.........^.........^........


Where 'x' and 'y' are the horizontal and vert-


ical coordinates of the top left corner of the


character, 'c' is the ASCII code of the char-


acter and 'a' is the address where you stored


the routine. So:


!0.......^.........^.........^..


RANDOMIZE 0 AND 175=65+USR


64500


!1.......^.........^.........^.........^........


will position a letter 'A' (character 65) at the


top left corner of the screen, assuming you


stored the machine code at address 645000. The


RANDOMIZE is a 'dummy' to hold the result of the


USR call. If your program uses random numbers


you should replace RANDOMIZE with a dummy


variable assignment, such as:


!0.......^.........^.........^..


LET dummy=0 AND 175=65+USR


64500


!1.......^.........^.........^.........^........


You're allowed to specify coordinates or char-


acter codes with expressions as well as vari-


ables or numbers. For instance:


!0.......^.........^.........^..


RANDOMIZE xpos+xdir AND ypos-


ydir=CODE "*"+USR move


!1.......^.........^.........^.........^........


is allowed. Our routine uses a neat technique to


fetch the three previous expressions on the


line, before the USR call. If there are more or


less than three values, a 'Parameter' error will


be reported. Make sure that you've used the


correct separators - AND, equals and plus -


between the coordinates, the character code and


the USR call. If you're using calculations more


complicated than addition, subtraction, multi-


plication and division, you may need to put each


coordinate or character code in brackets - so


that the routine can distinguish them.


The machine code contains extensive error


trapping. It won't let you use y coordinates


less than seven, since each character is eight


lines high. A character at coordinates 0,6 would


have its bottom line at y coordinate minus one!


The "Integer out of range" error message appears


if you use vertical coordinates less than seven


or greater than 175. X coordinates beyond 248


simply "wrap around" to the opposite side of the


screen; decimal values are rounded to the


nearest whole number.





!0.......^.........^.........^..


!B


A SMOOTH OPERATOR


!1.......^.........^.........^.........^........


The second Basic program shows the features of


the routine quite clearly. A ball bounces around


the screen at a variety of speeds. It's pos-


itioned using "LET d=" rather than "RANDOMIZE"


so that the random number sequence is not


constantly re-started whenever the ball moves.


The listing is fairly straightforward, but make


sure you type commas (not semi-colons) in line


330.


The machine code always uses the OVER 1


setting, so that any character can be erased


without destroying the background, simple by re-


drawing it in the same place. The characters


take on the colour of the INK where they are


plotted. This avoids the need for complicated


code to save and restore colours, and prevents


weird effects as objects pass one another.


The Spectrum normally uses character codes 165


to 255 to represent keywords - words like THEN,


PRINT and so on. There's never any need to zoom


those around the screen, so our machine code


program lets you define an extra 91 user-


defined graphics in their place. Together with


the 21 standard user-defined graphics, this


gives you 122 characters to play with.





!0.......^.........^.........^..


!B


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


LABELS |ADDRESS |COMMENT


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


| |SYSTEM POINTERS


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


UDGS | 5C7B |User graphics


| |pointer


CHARS | 5C36 |Character set


| |pointer


BLKCH | 5C92 |Block graphic


| |buffer


STACK | 5C65 |Maths stack end


| |pointer


STBOT | 5C63 |Maths stack


| |start pointer


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


| |ROM ROUTINES


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


MAKEB | 0B38 |Make graphic


| |in B


PIXEL | 22AA |Find address of


| |pixel


POP_A | 2DA2 |Pop A from


| |maths stack


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





!2.......^.........^.........^.........^.........^.........^....


The table above shows the system pointers and ROM routines used


in Smooth Move, giving their labels and addresses. This is for


the assembler's use only, and need not be typed in.


!1.......^.........^.........^.........^........





!B


In principle the new characters are defined in


exactly the same way as the old ones. They


follow the others in memory, which means that


you will have to expand the user-defined


graphics area before you can define more than


the standard 21 characters. On a 48K computer


you'd use the following commands to expand the


graphics area to cope with 122 characters:


!0.......^.........^.........^..


CLEAR 64559: POKE 23675,48:


POKE 23676,252


!1.......^.........^.........^.........^........


The POKEs adjust the system variable UDG so that


it points an extra 728 (91*8) bytes further down


memory. They don't reserve memory for any


machine code, so you'd probably use CLEAR 64499


and load the Smooth Move code at 64500 (or


thereabouts).


On a 16K computer load the machine code at


31670 and reserve space with:


!0.......^.........^.........^..


CLEAR 31669: POKE 23675,48:


POKE 23676,124


!1.......^.........^.........^.........^........


When you come to program the user-defined


graphics, you POKE the patterns into memory as


usual. The only difference is that you can't use


the USR "letter" function to locate characters


after USR "u". The extra characters still follow


at eight-byte intervals. User-defined graphic


"a" has character code 144, so you can find the


definition of the character with code 'n' by


typing:


!0.......^.........^.........^..


PRINT USR "a"+8*(n-144)





!B


TRICKS OF THE TRADE


!1.......^.........^.........^.........^........


Smooth Move uses some interesting machine code


tricks, so I've listed the assembler code of the


program as well as the Basic loader. This is the


longest listing, assembled using version 2.1 of


Picturesque's excellent EDITAS assembler.





!0.......^.........^.........^..


100 REM SMOOTH MOVE DEMO


110 REM By Simon N Goodwin


120 REM


130 REM Load code


140 CLEAR 30999


150 LOAD "Mover"CODE 31000


160 REM Set area


170 LET xmax=247


180 LET ymax=168


190 REM Set up positions


200 LET xpos=INT (RND*200)


210 LET ypos=17


220 LET xdir=INT (RND*6+1)


230 LET ydir=-INT (RND*5+1)


240 REM Define ball


250 RESTORE


260 FOR i=USR "a" TO USR "e"


270 READ d


280 POKE i,d


290 NEXT i


300 LET shape=144


310 INK 6: PAPER 2: BORDER 5


320 FOR i=0 TO 21


330 PRINT AT i,0, INVERSE 1,


350 NEXT i


360 GO TO 480


390 REM Move ball


400 LET oldx=xpos


410 LET oldy=ypos


420 LET xpos=xpos+xdir


425 IF xpos>1 THEN IF xpos<xma


x THEN GO TO 440


430 LET xpos=oldx: LET xdir=INT


(RND*7+1)*-SGN xdir


435 BEEP .03,15


440 LET ypos=ypos+ydir


445 IF ypos>7 THEN IF ypos<yma


x THEN GO TO 460


450 LET ypos=oldy: LET ydir=INT


(RND*5+1)*-SGN ydir


455 BEEP .03,30


460 LET d=oldx AND oldy=shape+U


SR 31000


470 LET shape=shape+1-4*(shape=


147)


480 LET d=xpos AND ypos=shape+U


SR 31000


490 GO TO 400


590 REM Ball definition


600 DATA 60,66,135,143,143,159,


126,60


610 DATA 60,66,193,225,249,253,


126,60


620 DATA 60,126,249,241,241,225


,66,60


630 DATA 60,126,191,159,135,131


,66,60


640 DATA 0





!2.......^.........^.........^.........^.........^.........^....


A demonstration program featuring a ball bouncing around the


screen at a variety of speeds. (Make sure you type commas and


not semi-colons in line 330.)


!1.......^.........^.........^.........^........





!B


The assembler listing starts with the defin-


ition of a few constants used later in the


program. These are defined at the head of the


listing so that they can be checked and altered


easily. They also make the program easier to


read, especially if it doesn't immediately


spring to mind that, say, 5C65H is the address


of the Maths stack pointer! Three ROM routines


have been used, to minimise the program size and


keep things simple.


The machine code is in three main sections.


First, the parameters (the coordinates and char-


acter number) are checked, then the character


definition is located, and finally the character


is positioned on the screen. The parameter


checking relies on the way the Spectrum eval-


uates expressions. In a simple sum like:


!0.......^.........^.........^..


PRINT 2+3*4


!1.......^.........^.........^.........^........


the computer must work out the multiplication


before it does the addition. This is because the


correct answer is 14 (or 2+12), not 20 (5*4).


The Smooth Move code takes advantage of the


way Basic works out the result of a calculation,


by ensuring that the coordinates and character


number have been worked out, but not combined


together, as the USR call is performed. The


three numbers are languishing on a "maths stack"


of temporary results during the USR call. The


machine code can read the numbers which have


been so helpfully made ready by Basic, and then


put things tidy afterwards so that Basic can


carry on once the USR call is over.





!0.......^.........^.........^..


100 REM SMOOTH MOVE LOADER


110 REM By Simon N Goodwin


120 REM


200 INPUT "Load address";l


210 LET c=0


220 FOR i=l TO l+119


230 READ d


240 LET c=c+d


250 POKE i,d


260 NEXT i


270 IF c<>13017 THEN PRINT "Er


ror in DATA": STOP


280 PRINT "Position character c


AT x,y with"


290 PRINT "RANDOMIZE x AND y =


c +USR ";l


300 PRINT '"Save everything, ju


st in case..."


310 SAVE "SMOOTH/BAS"


320 SAVE "SMOOTH/COD"CODE l,120


330 STOP


400 DATA 42,101,92,229,235,42


410 DATA 99,92,1,15,0,9


420 DATA 237,82,40,2,207,25


430 DATA 205,162,45,254,128,56


440 DATA 11,71,214,144,56,19


450 DATA 237,91,123,92,24,4


460 DATA 237,91,54,92,38,0


470 DATA 111,41,41,41,25,24


480 DATA 6,205,56,11,33,146


490 DATA 92,229,221,225,205,162


500 DATA 45,103,229,205,162,45


510 DATA 225,111,229,14,8,225


520 DATA 37,229,36,197,68,77


530 DATA 205,170,34,193,71,175


540 DATA 176,221,126,0,40,17


550 DATA 235,38,0,111,62,8


560 DATA 144,71,41,16,253,235


570 DATA 126,170,119,35,123,174


580 DATA 119,221,35,13,32,213


590 DATA 225,225,34,101,92,201





!2.......^.........^.........^.........^.........^.........^....


If you've not yet got hold of an assembler, here's a Basic


loader program allowing you to load the Smooth Move.


!1.......^.........^.........^.........^........





!B


This gives us a convenient way of passing


numbers from Basic to machine code, without the


hassle of PEEKing and POKEing. We can ensure


that temporary results are ready by our choice


of separators between the coordinates. In the


command:


!0.......^.........^.........^..


RANDOMIZE x AND y=c+USR a


!1.......^.........^.........^.........^........


Basic must do the addition first, to get the


correct answer - adding is always done before


comparison (=) and comparisons are done before


AND. This idea is explained on page 12 of the


thin "Introduction" manual which came with your


Speccy.


On the way through the expression, Basic works


out any calculations needed to find x, y and c,


since those calculations should have a higher


priority than the 'plus' at the end of the line.


If you want to use equals, AND, or other so-


called "logical operations" in your calculation


of x, y and c, you must put the relevant


calculations in brackets, so that Basic will


work out the whole value before it reaches the


USR call. A list of priorities is on page 201 of


the Spectrum manual. Logical operations have


priority '2', '3', '4' or '5'.


Basic puts temporary results in an area called


the "maths stack". Two system variables are used


to mark the top and bottom of this area; each


value stored within it takes up five bytes.


Lines 1340-1450 of the assembler are used to


check that the maths stack is 15 bytes long when


the USR call is reached; this means three values


are ready. If the stack does not contain three


values, the routine stops with a 'Parameter'


error - this is generated by lines 1440 & 1450.





!0.......^.........^.........^..


!B


A CHARACTER STUDY


!1.......^.........^.........^.........^........


The ROM subroutine POP_A is used to read a


number from the maths stack and into the A


register. Lines 1470-1560 fetch the character


code, which is the last thing calculated and


hence at the 'top' of the stack. They test the


code to decide whether the character is a block


graphic, a user-defined graphic or an ASCII


character. There's no definition of the block


graphics in the ROM - those are generated as


required by a routine called MAKEB, which puts


the pattern specified by a code in the B regis-


ter at address BLKCH.


In the case of ASCII or user-defined charac-


ters, the routine finds the appropriate start


address from the system variables (UDGS points


to the user-defined graphics and CHARS points to


the ASCII symbols). The character code is multi-


plied by eight (since each definition takes


eight bytes) and the location of the character


is found by adding the start address to the


resultant value. GFONT copies the address of the


character definition into register IX, for safe-


keeping.


POP_A is used twice more to fetch the y and x


coordinates where the character is to be


displayed. The loop from PLINE onwards puts the


character into video memory, one line at a time.


Register C is used to count the lines.


The program takes the coordinates of each line


and uses a ROM call to find the address where


that line should appear. The ROM subroutine


named PIXEL takes x and y coordinates in regis-


ters C and B, returning with the address of the


byte required in HL and the position within the


byte in A. The character definition is fetched


and shifted sideways if need be.


Each line of the Spectrum display corresponds


to 32 bytes of video memory. The contents of


that memory determines what's displayed on the


line. The normal Spectrum PRINT routine uses one


byte per character on each line, which means


that characters cannot be printed partly in one


byte and partly in the next. Smooth Move allows


you to split characters between one byte and the


next (hence the finer control over positioning).


The character code is put into one end of the HL


register pair, which is shifted sideways until


it's at the required place on the boundary


between H and L. The ADD Hl,HL instruction is


used to shift the value - every time you add a


binary value to itself it moves one place to the


left, because each column has twice the value of


the one to its right.


At STORE the graphic line is mixed into the


display with the XOR instruction - the machine


code equivalent of PRINT OVER. The program loops


back to PLINE until all eight lines of the


character have been positioned.





!0.......^.........^.........^..


!B


TIDYING UP


!1.......^.........^.........^.........^........


The routine can't return to Basic until both


stacks - the processor stack and the maths stack


- have been put back the way they were found.


Line 2330 throws away the coordinate information


which was on the processor stack. Finally, the


value of the maths stack pointer is retrieved,


so that Basic doesn't get confused by the sudden


loss of three data items. The USR function


returns the value zero, since B and C have both


counted down to nothing.


This program is only an introduction to Hi-res


animation on the Spectrum. The best graphic


routines handle large shapes, with automatic


animation and motion, collision detection, and


so forth. One day I might divulge the secrets of


the YS Sprite System, which puts most of the


power of a dedicated arcade machine at your


fingertips - that's if I ever finish writing it


...!





!2.......^.........^.........^.........^.........^.........^....


!B


The assembler code for Smooth Move - just so that you can see


the interesting machine code tricks that Simon's used.





FDE8 1320 ORG 65000


1330 ; "Fetch end of stack"


FDE8 2A655C 1340 MOVER LD HL,(STACK)


FDEB E5 1350 PUSH HL


1360 ; "3 numbers on stack?"


FDEC EB 1370 EX DE,HL


FDED 2A635C 1380 LD HL,(STBOT)


FDF0 010F00 1390 LD BC,15


FDF3 09 1400 ADD HL,BC


FDF4 ED52 1410 SBC HL,DE


FDF6 2802 1420 JR Z,FCODE


1430 ; "3 parameters needed!"


FDF8 CF 1440 RST #08


FDF9 19 1450 DEFB 25


1460 ; "Find the char. code"


FDFA CDA22D 1470 FCODE CALL POP_A


1480 ; "Divide into 3 groups:"


1490 ; " 0-127 ASCII chars"


1500 ; "128-143 block graphics"


1510 ; "144-255 user defined"


FDFD FE80 1520 CP 128


FDFF 380B 1530 JR C,ASCII


FE01 47 1540 LD B,A


FE02 D690 1550 SUB 144


FE04 3813 1560 JR C,BLOCK


1570 ; "Must be a UDG"


FE06 ED5B7B5C 1580 LD DE,(UDGS)


FE0A 1804 1590 JR INDEX


1600 ;


FE0C ED5B365C 1610 ASCII LD DE,(CHARS)


1620 ; "Find character form"


FE10 2600 1630 INDEX LD H,#00


FE12 6F 1640 LD L,A


FE13 29 1650 ADD HL,HL


FE14 29 1660 ADD HL,HL


FE15 29 1670 ADD HL,HL


FE16 19 1680 ADD HL,DE


FE17 1806 1690 JR GFONT


1700 ;


FE19 CD380B 1710 BLOCK CALL MAKEB


FE1C 21925C 1720 LD HL,BLKCH


FE1F E5 1730 GFONT PUSH HL


FE20 DDE1 1740 POP IX


1750 ; "Fetch Y coordinate"


FE22 CDA22D 1760 CALL POP_A


FE25 67 1770 LD H,A


1780 ; "Fetch X coordinate"


FE26 E5 1790 PUSH HL


FE27 CDA22D 1800 CALL POP_A


FE2A E1 1810 POP HL


FE2B 6F 1820 LD L,A


FE2C E5 1830 PUSH HL


1840 ; "Process 8 screen lines"


FE2D 0E08 1850 LD C,8


FE2F E1 1860 PLINE POP HL


1870 ; "Step up to next line"


FE30 25 1880 DEC H


FE31 E5 1890 PUSH HL


FE32 24 1900 INC H


1910 ; "Convert coord in H,L"


1920 ; "to address in HL & A"


FE33 C5 1930 PUSH BC


FE34 44 1940 LD B,H


FE35 4D 1950 LD C,L


FE36 CDAA22 1960 CALL PIXEL


FE39 C1 1970 POP BC


1980 ; "Copy bit offset to B"


FE3A 47 1990 LD B,A


2000 ; "See if char is on grid"


FE3B AF 2010 XOR A


FE3C B0 2020 OR B


2030 ; "Read font anyway"


FE3D DD7E00 2040 LD A,(IX+0)


2050 ; "Store NOW if on grid"


FE40 2811 2060 JR Z,STORE


2070 ; "Generate 16 bit mask"


FE42 EB 2080 EX DE,HL


FE43 2600 2090 LD H,0


FE45 6F 2100 LD L,A


2110 ; "Reverse shift count"


FE46 3E08 2120 LD A,8


FE48 90 2130 SUB B


FE49 47 2140 LD B,A


FE4A 29 2150 SHIFT ADD HL,HL


FE4B 10FD 2160 DJNZ SHIFT


2170 ; "Put mask in DE"


FE4D EB 2180 EX DE,HL


2190 ; "Mix into display"


FE4E 7E 2200 LD A,(HL)


FE4F AA 2210 XOR D


FE50 77 2220 LD (HL),A


FE51 23 2230 INC HL


FE52 7B 2240 LD A,E


FE53 AE 2250 STORE XOR (HL)


FE54 77 2260 LD (HL),A


2270 ; "Advance through font"


FE55 DD23 2280 INC IX


2290 ; "Count one line done"


FE57 0D 2300 DEC C


FE58 20D5 2310 JR NZ,PLINE


2320 ; "Tidy stacks; n.b. BC=0"


FE5A E1 2330 POP HL


FE5B E1 2340 POP HL


FE5C 22655C 2350 LD (STACK),HL


FE5F C9 2360 RET


2370 END


!1.......^.........^.........^.........^........





!B


--


from Your Spectrum #7 (Sep.1984)


--


!$
Автор
Verter_bot
Загрузки
0
Просмотры
1
Расширение
zip
Размер
12 КБ
Хэш
f742a7a6fbc63cbc81fdb2322df9a3cf
Первый выпуск
Последнее обновление

Оценки

0.00 звезд(ы) 0 оценок
Назад
Вверх