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

!B

\H11\H07\H10\H00          S P R I T E           

\H11\H07\H10\H00        D E S I G N E R         



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

 User-defined sprites on the Spectrum? It's not that difficult!

 Get things moving on-screen with more machine code magic from

                      Toni Baker.

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

This  month's  block of crafty code makes  weird

shapes fly around all over the screen. In  fact,

you shouldn't find it too hard to add a few bits

and pieces to the idea yourself. It's all basic-

ally   very   simple.  You  design  up  to  five

different sprites - of any figure, shape, design

and  so  on  - which in this case are 16  pixels

wide  by  16  pixels  high;  imagine four  user-

defined graphics characters glued together in  a

square and you have the idea. But - and this  is

where the story really begins - there's more  to

this program than meets the eye, for it  incorp-

orates a rather mind-blowing idea ...



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

!B

MOTION PICTURES

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

You  see, once you've defined a sprite, you  can

then  specify its coordinates on the screen  and

its velocity across the screen. In other  words,

they  move!  Curiouser  and  curiouser.  Once  a

sprite  is set in motion, you can continue  exe-

cuting  more Basic or machine code. The  sprites

will keep moving on-screen, simultaneously  with

any other program.

  One line of Basic can set a sprite in  motion.

The next Basic line will, of course, be executed

in  sequence - but it'll be executed whilst  the

sprite is moving. Thus, the setting in motion in

the first place is all you have to worry  about.

How  it  all  works is quite intricate, so  I'll

explain  in  a  moment  or two; if you find  the

blurb  a  bit  too  heavy going, try quaffing  a

cuppa or two before attempting to follow it.  In

the meantime, I'll tell you how to integrate  my

machine code with your Basic.



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

!B

DOWN TO DESIGN

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

The first statement of your Basic program must

be  a  "DIM  s$(x,8)";  where  x is the  maximum

number  of  things  you  want flying around  on-

screen  at  any  one time. Then, you'll want  to

include  the statements "LET on=33013" and  "LET

off=33020". From here on in it's up to you.  The

statement  "RANDOMIZE  USR  on"  will bring  the

moving sprite facility into action, whereas  the

statement  "RANDOMIZE USR off"will bring  things

back to normal.

  The  sprites themselves are defined using  the

ordinary user-defined graphics. You can have  up

to five different designs on-screen at once,

which are:

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

Sprite 1=UDGs A,B,C,D

Sprite 2=UDGs E,F,G,H

Sprite 3=UDGs I,J,K,L

Sprite 4=UDGs M,N,O,P

Sprite 5=UDGs Q,R,S,T

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

You can define them yourself in the usual ways.

  The  array,  s$, is the one that contains  all

the information, however, and each element  must

be  precisely defined. Now ... it's "pay  atten-

tion"  time.  Take a look at the box giving  the

explanation of the sprite parameters. (Note that

in the explanations given, I've used the  letter

'N'  to represent one of the strings in s$;  the

number is completely arbitrary.)

  The  element s$(N,8) is actually very  import-

ant. If it contains any character whose code  is

less  than  or  equal to 64 (decimal), then  the

sprite  is said to be inactive - that is,  it'll

not  appear on the screen. You can make as  many

alterations as you like to the other elements of

s$. Once all the alterations have been made, you

can  then  alter s$(N,8) and the sprite will  be

active and will start moving across the screen.

  If such a moving sprite collides with anything

on-screen,  or  if  it  hits  the  edges of  the

screen, then it'll instantly stop

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

!B

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

\H11\H07\H10\H00     THE SPRITE PARAMETERS      

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

STRING  | EXPLANATION

ELEMENT |

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

s$(N,1) |CHR$ (the sprite number

        | - between one & five)

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

s$(N,2) |This must always be

        |initialised to CHR$(1)

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

s$(N,3) |CHR$ (the number of

        |frames between 

        |successive movements)

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

s$(N,4) |CHR$ (the figure's Y

        |coordinate)

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

s$(N,5) |CHR$ (the figure's X

        |coordinate)

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

s$(N,6) |CHR$ (the figure's

        |vertical displacement

        |each time it moves)

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

s$(N,7) |CHR$( the figure's

        |horizontal displacement

        |each time it moves)

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

s$(N,8) |This must be set last

        |of all, and must be any

        |character whose code is

        |greater than 64

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



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

In the table above, it must be noted that 'N' is used to repre-

sent one of the strings in s$ - the number is arbitrary.

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

!B

moving  and  deactivate.  Element  s$(N,8)  will

automatically reset to CHR$(0). You can test for

this occurrence in a Basic program.



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

A TIMELY INTERRUPTION

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

OK,  it's  tea-break  time! Arm yourself with  a

cuppa and I'll explain how it all works.

  The machine code is an interrupt routine. This

means that the program runs itself automatically

50  times a second. Each time it runs it  checks

out the array s$ and shuffles sprites around the

screen   accordingly.   The   basic  instruction

"RANDOMIZE   USR   on"   simply  activates  this

interrupt procedure, whereas "RANDOMIZE USR off"

deactivates  it. Interrupt procedures are  quite

clever;  however, it's very easy to muck  things

up  and just a tiny little bug will spell  total

disaster   and   blast   the  poor  Speccy  into

oblivion.   This  is  true  simple  because  the

program runs itself once for every new TV frame,

whether you want it to or not.

  Take a peek at the basic program that's  lying

around in this article. It manages to do in just

a few statements what would otherwise have  been

quite  a  complicated  program;  it  produces  a

figure  which  bounces  around  the screen.  The

first seven lines just initialise the array, s$,

and line 80 starts things moving. Line 90 is the

one  to think about - it looks like an  infinite

loop,  but  in fact it's not; it's just  waiting

until the figure hits an edge. If you break  out

of  the  program at any time you'll notice  that

the figure will keep moving even while you  type

a  command,  until it hits a wall (when it  will

stop). At this point, you should type "RANDOMIZE

USR off" before you do anything else.

  Well, that's it for this issue. I'm just going

off to stick my head in a bucket of  inspiration

-  hopefully in time for me to produce yet  more

gems next month. See you then.



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

!B

--------------------------------.-------------------------------

  10 DIM s$(1,8)                Dimensions the array, s$

--------------------------------.-------------------------------

  20 LET on=33013               Initialise the variables

  30 LET off=33020

--------------------------------.-------------------------------

  40 FOR j=1 TO 8               Read the data in line 160

  50 READ a

  60 LET s$(1,j)=CHR$ a

  70 NEXT j

--------------------------------.-------------------------------

  80 RANDOMIZE USR on            Switches on the sprite facility

--------------------------------.-------------------------------

  90 IF s$(1,8)="A" THEN  GO TO  Waits until a sprite hits the

90                               edge of the screen

--------------------------------.-------------------------------

 100 LET y=CODE s$(1,4)          'y' is the Y coordinate of the

                                 sprite

--------------------------------.-------------------------------

 110 LET x=CODE s$(1,5)          'x' is the X coordinate of the

                                 sprite

--------------------------------.-------------------------------

 120 IF y=0 OR y=22 THEN  LET s$ Reverses the Y movement of

(1,6)=CHR$ (256-CODE s$(1,6)): B the sprite if necessary

EEP .03,24

--------------------------------.-------------------------------

 130 IF x=0 OR x=30 THEN  LET s$ Reverses the X movement of

(1,7)=CHR$ (256-CODE s$(1,7)): B the sprite if necessary

EEP .03,12

--------------------------------.-------------------------------

 140 LET s$(1,8)="A"             Reactivates the sprite

--------------------------------.-------------------------------

 150 GO TO 90                    A loop to send the action back

                                 to line 90.

--------------------------------.-------------------------------

 160 DATA 1,1,2,10,5,255,1,65    Contains the data for s$

--------------------------------.-------------------------------



The Basic program to get things moving on-screen - type it in

and see ...



!B

Machine code       Assembler          Comments

---------.---------.------------------.-------------------------

                   ORG  80F5

---------.---------.------------------.-------------------------

3E80     ON        LD   A,#80

ED47               LD   I,A           I:=80

ED5E               IM   2             Activate interrupt routine

C9                 RET

---------.---------.------------------.-------------------------

ED46     OFF       IM   0             Deactivate routine

C9                 RET

---------.---------.------------------.-------------------------

0181     IADDR     DEFW 8101          Direct interrupt control

                                      to address 8101

---------.---------.------------------.-------------------------

F5       SPRITES   PUSH AF

C5                 PUSH BC

D5                 PUSH DE

E5                 PUSH HL

DDE5               PUSH IX            Stack all registers used

                                      by the routine

DD2A4B5C           LD   IX,(VARS)     Point IX to array s$

DD7E00             LD   A,(IX+#00)

FED3               CP   #D3

200F               JR   NZ,EXIT       Jump if first variable is

                                      not array s$

DD4604             LD   B,(IX+#04)    B:=1st dimension of array

                                      (number of sprites)

---------.---------.------------------.-------------------------

C5       SP_LOOP   PUSH BC            Stack this number

010800             LD   BC,#0008

DD09               ADD  IX,BC         Point IX to start of next

                                      sprite(next array element)

CD7181             CALL NXT_SPRT      Treat next sprite

C1                 POP  BC            B:=remaining number of

                                      sprites to treat

10F4               DJNZ SP_LOOP

---------.---------.------------------.-------------------------

DDE1     EXIT      POP  IX

E1                 POP  HL

D1                 POP  DE

C1                 POP  BC

F1                 POP  AF            Restore all registers

FF                 RST  #38           Carry out normal 

                                      interrupt procedures

C9                 RET

---------.---------.------------------.-------------------------

CB0C     LINE      RRC  H

CB0C               RRC  H

CB0C               RRC  H             HL:=coded print position

011F00             LD   BC,#001F

09                 ADD  HL,BC         Move print position one

                                      square down and one left

CB04               RLC  H

CB04               RLC  H

CB04               RLC  H             HL:=correct print position

C9                 RET

---------.---------.------------------.-------------------------

CD4081   WIPE      CALL H_WIPE        Erase top half of sprite

CD2981             CALL LINE          Point HL to bottom half of

                                      sprite

---------.---------.------------------.-------------------------

CD4481   H_WIPE    CALL Q_WIPE        Erase one square of sprite

23                 INC  HL            Point HL to remaining square

---------.---------.------------------.-------------------------

E5       Q_WIPE    PUSH HL

0608               LD   B,#08         B:=Number of rows per 

                                      square

---------.---------.------------------.-------------------------

3600     WP_LOOP   LD   (HL),#00      Erase next row

24                 INC  H             Point HL to next row

10FB               DJNZ WP_LOOP

E1                 POP  HL

C9                 RET

---------.---------.------------------.-------------------------

AF       TEST      XOR  A             A:=00

CD5581             CALL H_TEST        Test upper half of sprite

                                      position

CD2981             CALL LINE          Point HL to lower half

---------.---------.------------------.-------------------------

CD5981   H_TEST    CALL Q_TEST        Test one square of sprite

                                      position

23                 INC  HL            Point HL to remaining square

---------.---------.------------------.-------------------------

E5       Q_TEST    PUSH HL

0608               LD   B,#08

---------.---------.------------------.-------------------------

B6       TS_LOOP   OR   (HL)          If any pixel is set then A

                                      becomes non-zero

24                 INC  H             HL points to next row

10FC               DJNZ TS_LOOP

E1                 POP  HL

C9                 RET

---------.---------.------------------.-------------------------

78       FIND_ADDR LD   A,B           This subroutine computes

E618               AND  #18           in HL the print pos of the

F640               OR   #40           square (on-screen) which

67                 LD   H,A           has PRINT-AT coords given

78                 LD   A,B           by registers B,C

0F                 RRCA

0F                 RRCA

0F                 RRCA

E6E0               AND  #E0

B1                 OR   C

6F                 LD   L,A

C9                 RET

---------.---------.------------------.-------------------------

DD7E07   NXT_SPRT  LD   A,(IX+#07)    A:=activation flag

FE40               CP   #40

D8                 RET  C             Return if sprite inactive

DD3501             DEC  (IX+#01)      Count frames between

                                      movements

C0                 RET  NZ            Return if the sprite does

                                      not require moving

DD7E02             LD   A,(IX+#02)    A:=frame interval between

                                      movements

DD7701             LD   (IX+#01),A    Re-initialise frame count

DD4603             LD   B,(IX+#03)    B:=y coordinate

DD4E04             LD   C,(IX+#04)    C:=x coordinate

CD6281             CALL FIND_ADDR     HL:=print pos of sprite

CD3A81             CALL WIPE          Erase sprite

DD7E03             LD   A,(IX+#03)    A:=y coordinate

DD8605             ADD  A,(IX+#05)    A:=intended y coordinate

FE17               CP   #17

301F               JR   NC,NS_EXIT    Jump if intended y coord

                                      out of range

47                 LD   B,A           B:=intended y coordinate

DD7E04             LD   A,(IX+#04)    A:=x coordinate

DD8606             ADD  A,(IX+#06)    A:=intended x coordinate

FE1F               CP   #1F

3014               JR   NC,NS_EXIT    Jump if intended x coord

                                      out of range

4F                 LD   C,A           C:=intended x coordinate

---------.---------.------------------.-------------------------

C5                 PUSH BC

CD6281             CALL FIND_ADDR     HL:=intended print pos

CD4E81             CALL TEST          Test for collision

C1                 POP  BC            BC:=intended coordinates

A7                 AND  A

2008               JR   NZ,NS_EXIT    Jump if sprite has hit

                                      something

DD7003             LD   (IX+#03),B    Store new y coordinate

DD7104             LD   (IX+#04),C    Store new x coordinate

180A               JR   NS_DRAW

---------.---------.------------------.-------------------------

DD360700 NS_EXIT   LD   (IX+#07),#00  Deactivate sprite

DD4603             LD   B,(IX+#03)    B:=old y coordinate

DD4E04             LD   C,(IX+#04)    C:=old x coordinate

---------.---------.------------------.-------------------------

DD6E00   NS_DRAW   LD   L,(IX+#00)    L:=sprite type number

2D                 DEC  L             L now in range 0 to 4

2600               LD   H,#00         HL now in range 0 to 4

29                 ADD  HL,HL

29                 ADD  HL,HL

29                 ADD  HL,HL

29                 ADD  HL,HL

29                 ADD  HL,HL         Multiply by 32d

ED5B7B5C           LD   DE,(UDG)      Point DE to graphic A

19                 ADD  HL,DE         Point HL to required

                                      sprite graphics

E5                 PUSH HL

CD6281             CALL FIND_ADDR     HL:=print pos of sprite

D1                 POP  DE            DE:=address of pixel

                                      information

---------.---------.------------------.-------------------------

CDDB81   DRAW      CALL H_DRAW        Draw upper half of sprite

CD2981             CALL LINE          Point HL to lower half

---------.---------.------------------.-------------------------

CDDF81   H_DRAW    CALL Q_DRAW        Draw next square of sprite

23                 INC  HL            Point HL to next square

---------.---------.------------------.-------------------------

E5       Q_DRAW    PUSH HL

0608               LD   B,#08

---------.---------.------------------.-------------------------

1A       DR_LOOP   LD   A,(DE)

77                 LD   (HL),A        Print next row

13                 INC  DE

24                 INC  H             Point HL to next row

10FA               DJNZ DR_LOOP

E1                 POP  HL

C9                 RET

---------.---------.------------------.-------------------------

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



!B

--

from Your Spectrum #10 (Dec/Jan.1984/85)

--

!$

