CHAPTER 16 PLAYER AND MISSILE GRAPHICS (PMG) Players and missiles (called sprites on some computers) are movable objects which are independent of the normal graphics. Player and missile graphics are fairly straight forward. Once the computer is set-up for PM graphics, five 8-pixel-wide columns can be displayed on the screen. The horizontal resolution (width of each pixel) and the vertical resolution (number of scan lines per pixel) are variable. The horizontal position of each column is determined by it's horizontal position register. Each column is simply a representation of a bit map in a certain block of memory. If you want to draw an object on the screen, you simply put a bit map representing it in the proper memory block. The vertical position of an object is determined by the location of it's bit map in memory. For example, if you want to draw a happy face in the middle of the screen, you put a happy face bit map in the middle of one of the memory blocks controlling one of the columns. One column (player) displayed on the screen ---------- first byte of a block | | | | ------------------------------ | | | | | | | | | | | | | | | | | | | | | | | | | | ++++ | visible | | | + + | | | |+ + + +| | | |+ +| area | | |++ ++| | | |+ ++++ +|--object | | | + + | bit map | | | ++++ | | | | | | | | | | | | | | ------------------------------ | | | | ---------- last byte of a block Horizontal positions $00 $30 $CE $FF (0) (48) (206) (255) | | | | | Left edge right edge | | | Far left far right To move the happy face vertically you would move the entire bit map in memory. To move the happy face horizontally you change the number in the horizontal position register for the proper player. One of the players can be (and often is) split into four columns of two pixels wide each. These columns are then called missiles. In this case, each missile has it's own horizontal position register. SETTING UP PM GRAPHICS PM graphics are enabled by the direct memory access control register, DMACTL [$D400 (54272)]. The program using PM graphics will usually use the shadow register, SDMCTL [$022F (559)]. DMACTL (SDMCTL) 7 6 5 4 3 2 1 0 ----------------- |0|0| control | ----------------- bits 5 1 = enable display list reading 4 0 = one line player resolution 1 = two line player resolution 3 1 = enable four players 2 1 = enable fifth player or missiles 1 & 0 00 = no background 01 = narrow background (128 color clocks, 1 color clock equals 2 GRAPHICS 8 pixels) 10 = normal background (160 color clocks) 11 = wide background (192 color clocks) Normally, bits 5 and 1 are set to 1. Bits 4, 3 and 2 are used to enable players and/or missiles accordingly. Once DMACTL is set up for the type of PM graphics to enable, the graphics control register, GRACTL [$D01D (53277)], is used to actually enable the PM graphics. GRACTL 7 6 5 4 3 2 1 0 ----------------- |not used | | | | ----------------- Bits 2 1 = latch paddle triggers 1 1 = enable four players 0 1 = enable fifth player or missiles If only DMACTL is set up, the ANTIC chip will access memory for PM graphics but will not display them. Next, the memory area used for the PM bit maps must be set. This block must start on a 2K (8 page) boundary if single line resolution is used and a 1K (4 page) boundary for two line resolution. The page number where the bit map starts is stored in the PM base register, PMBASE [$D407 (54279)]. For one line resolution this number will be a multiple of 8. For two line resolution it will be a multiple of 4. PMBASE holds the MSB of the address of the PM bit map. The LSB will always be 0 so it need not be specified. The PM bit maps 2 line resolution 128 bytes (1/2 page) per player ----------------- start + 0 | |\ +---------------+ 1-1/2 page | | (384 bytes) +===============+ unused | |/ +---------------+ +$180 (384) |M3 |M2 |M1 |M0 | fifth player or missiles +===============+ +$200 (512) | player 0 map | +---------------+ +$280 (640) | player 1 map | +===============+ +$300 (768) | player 2 map | +---------------+ +$380 (896) | player 3 map | +===============+ +$400 (1024) 1 line resolution 256 bytes (1 page) per player ----------------- start + 0 | |\ + + | | +===============+ | | 768 bytes + + | | (3 pages) +===============| | | unused + + | |/ +===============+ +$300 (768) | | | | | fifth player +M3 |M2 |M1 |M0 | or missiles | | | | | +===============+ +$400 (1024) | | + player 0 map + | | +===============+ +$500 (1280) | | + player 1 map + | | +===============+ +$600 (1536) | | + player 2 map + | | +===============+ +$700 (1792) | | + player 3 map + | | +===============+ +$800 (2048) Example of using P/M graphics in BASIC 0 REM ---LABEL REGISTERS ETC 10 LINES=2 20 VERT=120 22 IF LINES=2 THEN VERT=VERT/2 30 PM0=1024 32 IF LINES=2 THEN PM0=PM0/2 40 HORIZ=120 50 PCOLR0=704 60 SDMCTL=559 70 SIZEP0=53256 80 HPOSP0=53248 90 SDMCTL=559 100 PMRAM=PEEK(106)-16 110 PMBASE=54279 120 GRACTL=53277 130 PMSTART=PMRAM*256+PM0 200 REM ---SET REGISTERS 210 POKE SDMCTL,62 212 IF LINES=2 THEN POKE SDMCTL,46 220 POKE SIZEP0,1 230 POKE HPOSP0,HORIZ 240 POKE PCOLR0,88 250 POKE PMBASE,PMRAM 260 POKE GRACTL,3 300 REM ---DRAW PLAYER 310 POKE PMSTART+VERT,60 320 POKE PMSTART+VERT+1,66 330 POKE PMSTART+VERT+2,165 340 POKE PMSTART+VERT+3,129 350 POKE PMSTART+VERT+4,195 360 POKE PMSTART+VERT+5,189 370 POKE PMSTART+VERT+6,66 380 POKE PMSTART+VERT+7,60 The above program will draw a happy face in about the middle of the screen using player 0. To move the player horizontally, poke a different number into HPOSP0. To draw the player in a different vertical position, change VERT. To use a different player or missile, use the memory maps above to find the starting address of the player you want to use. For example, to use player 1 change line 40 to PM1=1280. Then change line 130 to PMSTART=PMRAM*256+PM1. The variable "LINES" determines the vertical resolution. The number poked into SIZEP0 determines the width. P/M PRIORITY The priorities of players, missiles and non-P/M graphics can be controlled by the PRIOR register [$D10B (53275)] and its shadow register, GPRIOR [$26F (623)]. Objects with higher priority will appear to move in front of lower priority objects. The format of PRIOR is as follows: PRIOR bit assignment 7 6 5 4 3 2 1 0 ----------------- | | | | | | | | | ----------------- 1 6 3 1 8 4 2 1 2 4 2 6 8 Bits 7-6 Control the GTIA graphics modes. 00 = normal 01 = mode 9 10 = mode 10 11 = mode 11 5 1 = multiple color player enable. Permits overlapping of players 0 and 1 or 2 and 3 with a third color in the overlapped region. 4 1 = fifth player enable. All missiles will assume the color controlled by COLOR3 [$2C7 (711)]. missiles are positioned together to make the fifth player. 3-0 Controls the priorities of players, missiles and other graphics. Objects with higher priority will appear to move in front of those with lower priority. The following chart may need some clarification. In the chart: PM0 = player 0 and missile 0 C0 = COLOR0, plotted graphics controlled by color register 0 in the SETCOLOR command. P5 = all four missiles when combined into one player. BAK = the background, known as COLOR4 or color register 4 in the SETCOLOR command. Etc. Bits 0-3 of PRIOR and P/M priorities Bit 3=1 2=1 1=1 0=1 C0 C0 PM0 PM0 highest C1 C1 PM1 PM1 priority PM0 C2 C0 PM2 PM1 C3+P5 C1 PM3 PM2 PM0 C2 C0 PM3 PM1 C3+P5 C1 C2 PM2 PM2 C2 C3+P5 PM3 PM3 C3+P5 lowest BAK BAK BAK BAK priority Only one priority bit can be set at a time. If more than one priority bit is 1, overlapping areas of conflicting priorities will turn black. COLLISIONS Each player or missile has a register showing overlap (collisions) with other objects. Each player has two registers assigned to it; one to detect collisions with other players and one to detect collisions with plotted objects. Likewise each missile has two registers; one to detect collisions with players and one to detect collisions with plotted objects. Careful use of these 16 registers can detect any type of collision. Each register uses only the lower 4 bits. The bits which equal 1 tell what the associated object has collided with. For example, to detect collisions of player 1 to other players examine P1PL [$D00D (53261)]. P1PL, player 1 to player collisions 7 6 5 4 3 2 1 0 ----------------- P1PL |unused | | | | | ----------------- 8 4 2 1 3 = 1 collision with player 3 2 = 1 collision with player 2 1 = 1 invalid 0 = 1 collision with player 0 Etc. When looking for collisions with plotted objects, the bit number tells what color register is assigned to the object the collision was with. For example, to detect collisions between player 1 and plotted objects (officially called the play field), P1PF [$D005 (53253)] is used. P1PF, player 1 to ploted object collisions 7 6 5 4 3 2 1 0 ----------------- P1PF |unused | | | | | ----------------- 8 4 2 1 3 = 1 collision with COLOR3 2 = 1 " COLOR2 1 = 1 " COLOR1 0 = 1 " COLOR0 Etc. Once a collision occurs it remains indicated in its collision register. To clear out all collision registers, write anything to HITCLR [$D01E (53278)]. STA HITCLR or POKE 53278,0 will do. Useful database variables and OS equates HPOSP0 $D000 (53248): write: horizontal position of player 0 M0PF " " : read: missile 0 to plotted graphics collisions HPOSP1 $D001 (53249): write: horizontal position of player 1 M1PF " " : read: missile 1 to plotted graphics collisions HPOSP2 $D002 (53250): write: horizontal position of player 2 M2PF " " : read: missile 2 to plotted graphics collisions HPOSP3 $D003 (53251): write: horizontal position of player 3 M3PF " " : read: missile 3 to plotted graphics collisions HPOSM0 $D004 (53252): write: horizontal position of missile 0 P0PF " " : read: Player 0 to plotted graphics collisions HPOSM1 $D005 (53253): write: horizontal position of missile 1 P1PF " " : read: Player 1 to plotted graphics collisions HPOSM2 $D006 (53254): write: horizontal position of missile 2 P2PF " " : read: Player 2 to plotted graphics collisions HPOSM3 $D007 (53255): write: horizontal position of missile 3 P3PF " " : read: Player 3 to plotted graphics collisions SIZEP0 $D008 (53256): write: size of player 0 M0PL " " : read: missile 0 to player collisions SIZEP1 $D009 (53257): write: size of player 1 M1PL " " : read: missile 1 to player collisions SIZEP2 $D00A (53258): write: size of player 2 M2PL " " : read: missile 2 to player collisions SIZEP3 $D00B (53259): write: size of player 3 M3PL " " : read: missile 3 to player collisions SIZEM $D00C (53260): write: widths for all missiles P0PL " " : read: player 0 to other player collisions GRAFP0 $D00D (53261): write: player 0 graphics (used by OS) P1PL " " : read: player 1 to other player collisions GRAPF1 $D00E (53262): write: player 1 graphics P2PL " " : read: player 2 to other player collisions GRAFP2 $D00F (53263): write: player 2 graphics P3PL " " : read: player 3 to other player collisions GRAPF3 $D010 (53264): write: player 3 graphics GRAFM $D011 (53265): write: missile graphics (used by OS) COLPM0 $D012 (53266): color for player/missile 0 COLPM1 $D013 (53267): color for player/missile 1 COLPM2 $D014 (53268): color for player/missile 2 COLPM3 $D015 (53269): color for player/missile 3 COLPF0 $D016 (53270): color register 0 COLPF1 $D017 (53271): color register 1 COLPF2 $D018 (53272): color register 2 COLPF3 $D019 (53273): color register 3 COLBK $D01A (53274): background color (register 4) PRIOR $D01B (53275): priority select, GTIA modes GRACTL $D01D (53277): graphics control HITCLR $D01E (53278): writing anything clears all collision bits DMACTL $D400 (54272): direct memory access (DMA) control PMBASE $D407 (54279): start of P/M memory Shadow registers SDMCTL $022F (559): DMACTL GPRIOR $026F (623): PRIOR PCOLR0 $02C0 (704): COLPM0 PCOLR1 $02C1 (705): COLPM1 PCOLR2 $02C2 (706): COLPM2 PCOLR3 $02C3 (707): COLPM3 COLOR0 $02C4 (708): COLPF0 COLOR1 $02C5 (709): COLPF1 COLOR2 $02C6 (710): COLPF2 COLOR3 $02C7 (711): COLPF3 COLOR4 $02C8 (712): COLBK