Risky Woods
Risky Woods has one of the biggest copperlists you will ever see in an Amiga game! To begin, let's see what the game looks like:
If you disable sprites, you will be amazed to see that the entire background layer has been created using sprites!
If bitplanes are disabled, you are left with the sprite playfield. The first thing that you notice is that the background pattern repeats every 64 pixels. This is a dead giveaway that it is created using 4 sixteen colour sprites and redrawing them horizontally across each line.
Because the sprites are repeated, there is no need to change the data and the copper spends all it's time repositioning the sprites.
The limitation with this technique is that by the time we reach the right hand side of the screen, all the sprites will be drawn there for the next line, so the game has to reset all 8 sprites back to the far left of the screen. This takes up almost all the available DMA time, so there is no time left to change the colour palette or do any other copper tricks. This gives the game quite a muted appearance compared with many games that have a multi-coloured background (Shadow of the Beast, Turrican etc).
For the parallax effect, whenever the player scrolls several pixels sideways, the game has to shift the sprite data in the background horizontally by 1 pixel. Rather than updating the graphics every pixel (which may well slow the game down), the game pre-buffers the sprite data. At address $1c1e4, the following graphics are found:
As you can see, there are 8 sets of the 4 attached background sprites, all offset by 2 pixels each time. At first glance, this would suggest that the game alters the sprite pointers to simulate scrolling the background graphics by 2 pixels each time. But if you play the game, you can see that the background graphics smoothly scroll along 1 pixel at a time! How is that possible?
When I first noticed this, I assumed the game was rotating the graphics as required, but the sprite graphics never change. If you scroll by 1 pixel and check the copperlist, the sprite pointers remain pointing to the same graphics.
And this is where another stunningly simple trick comes into play. If you examine the copperlist, you can see the game sets up the sprite pointers once at the top of the screen:
000798b4: 0120 0002 ;SPR0PTH := 0x0002 Setup sprites 000798b8: 0122 5da4 ;SPR0PTL := 0x5da4 000798bc: 0124 0002 ;SPR1PTH := 0x0002 000798c0: 0126 606c ;SPR1PTL := 0x606c 000798c4: 0128 0002 ;SPR2PTH := 0x0002 000798c8: 012a 6334 ;SPR2PTL := 0x6334 000798cc: 012c 0002 ;SPR3PTH := 0x0002 000798d0: 012e 65fc ;SPR3PTL := 0x65fc 000798d4: 0130 0002 ;SPR4PTH := 0x0002 000798d8: 0132 68c4 ;SPR4PTL := 0x68c4 000798dc: 0134 0002 ;SPR5PTH := 0x0002 000798e0: 0136 6b8c ;SPR5PTL := 0x6b8c 000798e4: 0138 0002 ;SPR6PTH := 0x0002 000798e8: 013a 6e54 ;SPR6PTL := 0x6e54 000798ec: 013c 0002 ;SPR7PTH := 0x0002 000798f0: 013e 711c ;SPR7PTL := 0x711c
If you examine the first sprite data at address $25da4, you will see the following:
00025da4: 3800 e800 0002606c: 3800 e880
The first 2 words in the sprite data correspond to SPRxPOS and SPRxCTL respectively. When the game scrolls by a single pixel, the game updates the SPRxCTL values from $e800 to $e801 (sprite 0), and $e880 to $e881 (sprite 1), and that shifts the sprites across by a single pixel.
SPRxCTL
To see how this works, have a look at the bits for the SPRxCTL registers:
- Bits 15-8 specify vertical stop position for a sprite image, bits V7 - V0.
- Bit 7 is the attach bit, used to bolt 2 sprites together.
- Bits 6-3 are reserved for future use (make zero).
- Bit 2 is bit V8 of vertical start.
- Bit 1 is bit V8 of vertical stop.
- Bit 0 is bit H0 of horizontal start.
The Amiga can display more than 256 pixels horizontally, which requires 9 bits to store the horizontal location. The upper 8 bits are stored in the SPRxPOS registers, but the lowest bit is stored in bit 0 of the SPRxCTL register. The game can therefore display the background graphics at any even location by storing 8 versions (indented by 2 pixels extra each time) and then by toggling that one bit, it can shift the graphics across to an odd value, accessing the remaining positions.
So you don't notice the sprites shifting by a single pixel, the game area is made smaller than the expected width of 288 pixels, and instead only displays 287 pixels across. That way you never notice one vertical strip of blank pixels appearing.
The reason the game can't alter the SPRxPOS registers is that the enormous copperlist has precalculated all the positions for the sprites positions, and altering thousands of values every frame would be too slow.
By storing 8 copies of the sprite graphics, the game only has to update 8 words in memory to shift the graphics by a pixel, and when the game scrolls the background by 2 pixels it only has to alter the sprite pointer addresses in the copperlist, 8 sprites x 2 words = 32 bytes of data!
Copperlist
And now for the amazing copperlist! The poor copper in your Amiga is having to work overtime and process 27k of screen changes every frame!
00079800: 0100 4200 ;BPLCON0 := 0x4200 Setup screen 00079804: 00e0 0000 ;BPL1PTH := 0x0000 00079808: 00e2 0402 ;BPL1PTL := 0x0402 0007980c: 00e4 0000 ;BPL2PTH := 0x0000 00079810: 00e6 2382 ;BPL2PTL := 0x2382 00079814: 00e8 0000 ;BPL3PTH := 0x0000 00079818: 00ea 4302 ;BPL3PTL := 0x4302 0007981c: 00ec 0000 ;BPL4PTH := 0x0000 00079820: 00ee 6282 ;BPL4PTL := 0x6282 00079824: 0108 0004 ;BPL1MOD := 0x0004 00079828: 010a 0004 ;BPL2MOD := 0x0004 0007982c: 0092 0038 ;DDFSTRT := 0x0038 00079830: 0094 00c8 ;DDFSTOP := 0x00c8 00079834: 0180 0000 ;COLOR00 := 0x0000 Set colour palette 00079838: 0182 0b62 ;COLOR01 := 0x0b62 0007983c: 0184 0b96 ;COLOR02 := 0x0b96 00079840: 0186 0963 ;COLOR03 := 0x0963 00079844: 0188 0741 ;COLOR04 := 0x0741 00079848: 018a 0520 ;COLOR05 := 0x0520 0007984c: 018c 0720 ;COLOR06 := 0x0720 00079850: 018e 0a20 ;COLOR07 := 0x0a20 00079854: 0190 0ca3 ;COLOR08 := 0x0ca3 00079858: 0192 0bab ;COLOR09 := 0x0bab 0007985c: 0194 0788 ;COLOR10 := 0x0788 00079860: 0196 0565 ;COLOR11 := 0x0565 00079864: 0198 0310 ;COLOR12 := 0x0310 00079868: 019a 0433 ;COLOR13 := 0x0433 0007986c: 019c 0ddd ;COLOR14 := 0x0ddd 00079870: 019e 0000 ;COLOR15 := 0x0000 00079874: 01a0 0000 ;COLOR16 := 0x0000 00079878: 01a2 0112 ;COLOR17 := 0x0112 0007987c: 01a4 0aab ;COLOR18 := 0x0aab 00079880: 01a6 0889 ;COLOR19 := 0x0889 00079884: 01a8 0667 ;COLOR20 := 0x0667 00079888: 01aa 0445 ;COLOR21 := 0x0445 0007988c: 01ac 0223 ;COLOR22 := 0x0223 00079890: 01ae 02cd ;COLOR23 := 0x02cd 00079894: 01b0 0000 ;COLOR24 := 0x0000 00079898: 01b2 0003 ;COLOR25 := 0x0003 0007989c: 01b4 0004 ;COLOR26 := 0x0004 000798a0: 01b6 0005 ;COLOR27 := 0x0005 000798a4: 01b8 0007 ;COLOR28 := 0x0007 000798a8: 01ba 0009 ;COLOR29 := 0x0009 000798ac: 01bc 000b ;COLOR30 := 0x000b 000798b0: 01be 0334 ;COLOR31 := 0x0334
Now the game sets up the 8 sprites:
000798b4: 0120 0002 ;SPR0PTH := 0x0002 Setup sprites 000798b8: 0122 5da4 ;SPR0PTL := 0x5da4 000798bc: 0124 0002 ;SPR1PTH := 0x0002 000798c0: 0126 606c ;SPR1PTL := 0x606c 000798c4: 0128 0002 ;SPR2PTH := 0x0002 000798c8: 012a 6334 ;SPR2PTL := 0x6334 000798cc: 012c 0002 ;SPR3PTH := 0x0002 000798d0: 012e 65fc ;SPR3PTL := 0x65fc 000798d4: 0130 0002 ;SPR4PTH := 0x0002 000798d8: 0132 68c4 ;SPR4PTL := 0x68c4 000798dc: 0134 0002 ;SPR5PTH := 0x0002 000798e0: 0136 6b8c ;SPR5PTL := 0x6b8c 000798e4: 0138 0002 ;SPR6PTH := 0x0002 000798e8: 013a 6e54 ;SPR6PTL := 0x6e54 000798ec: 013c 0002 ;SPR7PTH := 0x0002 000798f0: 013e 711c ;SPR7PTL := 0x711c
And here the madness begins! For every scanline in the top part of the screen, the game positions all 8 sprites and while screen DMA occurs, it quickly moves the sprites 64 pixels to the right so they are re-displayed. Sprites are all attached to each other meaning they are 16 colour sprites. This is required as the game leaves no DMA time left to change the colour palette as it's having to reposition sprites so often!
What is effectively happening is that in the horizontal sweep of the video beam, the copper is racing ahead shifting the sprites into their next repeated position. There is only just enough DMA time to beat the video beam before it has to repeat it again for the next line. The copper gets an $18 (24) pixel headstart for shifting the sprites, as it waits for horizontal position $30, setting the first 2 sprites to appear at position $48 and then the next 2 at position $50 etc.
The closest analogy I can think of for this is in the Wallace and Gromit episode where Gromit is laying down the train track just ahead of the train that he is riding on!
000798f4: 3831 fffe ;Wait for vpos >= 0x38 and hpos >= 0x30. 000798f8: 0140 3848 ;SPR0POS := 0x3848 000798fc: 0148 3848 ;SPR1POS := 0x3848 00079900: 0150 3850 ;SPR2POS := 0x3850 00079904: 0158 3850 ;SPR3POS := 0x3850 00079908: 0160 3858 ;SPR4POS := 0x3858 0007990c: 0168 3858 ;SPR5POS := 0x3858 00079910: 0170 3860 ;SPR6POS := 0x3860 00079914: 0178 3860 ;SPR7POS := 0x3860 00079918: 0140 3868 ;SPR0POS := 0x3868 0007991c: 0148 3868 ;SPR1POS := 0x3868 00079920: 0150 3870 ;SPR2POS := 0x3870 00079924: 0158 3870 ;SPR3POS := 0x3870 00079928: 0160 3878 ;SPR4POS := 0x3878 0007992c: 0168 3878 ;SPR5POS := 0x3878 00079930: 0170 3880 ;SPR6POS := 0x3880 00079934: 0178 3880 ;SPR7POS := 0x3880 00079938: 0140 3888 ;SPR0POS := 0x3888 0007993c: 0148 3888 ;SPR1POS := 0x3888 00079940: 0150 3890 ;SPR2POS := 0x3890 00079944: 0158 3890 ;SPR3POS := 0x3890 00079948: 0160 3898 ;SPR4POS := 0x3898 0007994c: 0168 3898 ;SPR5POS := 0x3898 00079950: 0170 38a0 ;SPR6POS := 0x38a0 00079954: 0178 38a0 ;SPR7POS := 0x38a0 00079958: 0140 38a8 ;SPR0POS := 0x38a8 0007995c: 0148 38a8 ;SPR1POS := 0x38a8 00079960: 0150 38b0 ;SPR2POS := 0x38b0 00079964: 0158 38b0 ;SPR3POS := 0x38b0 00079968: 0160 38b8 ;SPR4POS := 0x38b8 0007996c: 0168 38b8 ;SPR5POS := 0x38b8 00079970: 0170 38c0 ;SPR6POS := 0x38c0 00079974: 0178 38c0 ;SPR7POS := 0x38c0 00079978: 0140 38c8 ;SPR0POS := 0x38c8 0007997c: 0148 38c8 ;SPR1POS := 0x38c8 00079980: 0150 38d0 ;SPR2POS := 0x38d0 00079984: 0158 38d0 ;SPR3POS := 0x38d0
And the next line is much the same, waiting for the next vertical scanline:
00079988: 3931 fffe ;Wait for vpos >= 0x39 and hpos >= 0x30. 0007998c: 0140 3948 ;SPR0POS := 0x3948 00079990: 0148 3948 ;SPR1POS := 0x3948 00079994: 0150 3950 ;SPR2POS := 0x3950 00079998: 0158 3950 ;SPR3POS := 0x3950 0007999c: 0160 3958 ;SPR4POS := 0x3958 000799a0: 0168 3958 ;SPR5POS := 0x3958 000799a4: 0170 3960 ;SPR6POS := 0x3960 000799a8: 0178 3960 ;SPR7POS := 0x3960 000799ac: 0140 3968 ;SPR0POS := 0x3968 000799b0: 0148 3968 ;SPR1POS := 0x3968 000799b4: 0150 3970 ;SPR2POS := 0x3970 000799b8: 0158 3970 ;SPR3POS := 0x3970 000799bc: 0160 3978 ;SPR4POS := 0x3978 000799c0: 0168 3978 ;SPR5POS := 0x3978 000799c4: 0170 3980 ;SPR6POS := 0x3980 000799c8: 0178 3980 ;SPR7POS := 0x3980 000799cc: 0140 3988 ;SPR0POS := 0x3988 000799d0: 0148 3988 ;SPR1POS := 0x3988 000799d4: 0150 3990 ;SPR2POS := 0x3990 000799d8: 0158 3990 ;SPR3POS := 0x3990 000799dc: 0160 3998 ;SPR4POS := 0x3998 000799e0: 0168 3998 ;SPR5POS := 0x3998 000799e4: 0170 39a0 ;SPR6POS := 0x39a0 000799e8: 0178 39a0 ;SPR7POS := 0x39a0 000799ec: 0140 39a8 ;SPR0POS := 0x39a8 000799f0: 0148 39a8 ;SPR1POS := 0x39a8 000799f4: 0150 39b0 ;SPR2POS := 0x39b0 000799f8: 0158 39b0 ;SPR3POS := 0x39b0 000799fc: 0160 39b8 ;SPR4POS := 0x39b8 00079a00: 0168 39b8 ;SPR5POS := 0x39b8 00079a04: 0170 39c0 ;SPR6POS := 0x39c0 00079a08: 0178 39c0 ;SPR7POS := 0x39c0 00079a0c: 0140 39c8 ;SPR0POS := 0x39c8 00079a10: 0148 39c8 ;SPR1POS := 0x39c8 00079a14: 0150 39d0 ;SPR2POS := 0x39d0 00079a18: 0158 39d0 ;SPR3POS := 0x39d0
This repeats on every scanline until the final line of the play area:
0007fe20: e731 fffe ;Wait for vpos >= 0xe7 and hpos >= 0x30. 0007fe24: 0140 e748 ;SPR0POS := 0xe748 0007fe28: 0148 e748 ;SPR1POS := 0xe748 0007fe2c: 0150 e750 ;SPR2POS := 0xe750 0007fe30: 0158 e750 ;SPR3POS := 0xe750 0007fe34: 0160 e758 ;SPR4POS := 0xe758 0007fe38: 0168 e758 ;SPR5POS := 0xe758 0007fe3c: 0170 e760 ;SPR6POS := 0xe760 0007fe40: 0178 e760 ;SPR7POS := 0xe760 0007fe44: 0140 e768 ;SPR0POS := 0xe768 0007fe48: 0148 e768 ;SPR1POS := 0xe768 0007fe4c: 0150 e770 ;SPR2POS := 0xe770 0007fe50: 0158 e770 ;SPR3POS := 0xe770 0007fe54: 0160 e778 ;SPR4POS := 0xe778 0007fe58: 0168 e778 ;SPR5POS := 0xe778 0007fe5c: 0170 e780 ;SPR6POS := 0xe780 0007fe60: 0178 e780 ;SPR7POS := 0xe780 0007fe64: 0140 e788 ;SPR0POS := 0xe788 0007fe68: 0148 e788 ;SPR1POS := 0xe788 0007fe6c: 0150 e790 ;SPR2POS := 0xe790 0007fe70: 0158 e790 ;SPR3POS := 0xe790 0007fe74: 0160 e798 ;SPR4POS := 0xe798 0007fe78: 0168 e798 ;SPR5POS := 0xe798 0007fe7c: 0170 e7a0 ;SPR6POS := 0xe7a0 0007fe80: 0178 e7a0 ;SPR7POS := 0xe7a0 0007fe84: 0140 e7a8 ;SPR0POS := 0xe7a8 0007fe88: 0148 e7a8 ;SPR1POS := 0xe7a8 0007fe8c: 0150 e7b0 ;SPR2POS := 0xe7b0 0007fe90: 0158 e7b0 ;SPR3POS := 0xe7b0 0007fe94: 0160 e7b8 ;SPR4POS := 0xe7b8 0007fe98: 0168 e7b8 ;SPR5POS := 0xe7b8 0007fe9c: 0170 e7c0 ;SPR6POS := 0xe7c0 0007fea0: 0178 e7c0 ;SPR7POS := 0xe7c0 0007fea4: 0140 e7c8 ;SPR0POS := 0xe7c8 0007fea8: 0148 e7c8 ;SPR1POS := 0xe7c8 0007feac: 0150 e7d0 ;SPR2POS := 0xe7d0 0007feb0: 0158 e7d0 ;SPR3POS := 0xe7d0 0007feb4: 0080 0002 ;COP1LCH := 0x0002 Setup score panel copperlist 0007feb8: 0082 aac2 ;COP1LCL := 0xaac2 0007febc: 0088 0000 ;COPJMP1 := 0x0000
Now the game has set the copperlist to $2aac2 and invoked it. This creates the score panel at the bottom of the screen:
0002aac2: 0080 0007 ;COP1LCH := 0x0007 0002aac6: 0082 9800 ;COP1LCL := 0x9800 0002aaca: e801 fffe ;Wait for vpos >= 0xe8 and hpos >= 0x00. 0002aace: 00e0 0001 ;BPL1PTH := 0x0001 0002aad2: 00e2 0000 ;BPL1PTL := 0x0000 0002aad6: 00e4 0001 ;BPL2PTH := 0x0001 0002aada: 00e6 06c0 ;BPL2PTL := 0x06c0 0002aade: 00e8 0001 ;BPL3PTH := 0x0001 0002aae2: 00ea 0d80 ;BPL3PTL := 0x0d80 0002aae6: 00ec 0001 ;BPL4PTH := 0x0001 0002aaea: 00ee 1440 ;BPL4PTL := 0x1440 0002aaee: 00f0 0001 ;BPL5PTH := 0x0001 0002aaf2: 00f2 1b00 ;BPL5PTL := 0x1b00 0002aaf6: 0092 0040 ;DDFSTRT := 0x0040 0002aafa: 0094 00c8 ;DDFSTOP := 0x00c8 0002aafe: 0108 0000 ;BPL1MOD := 0x0000 0002ab02: 010a 0000 ;BPL2MOD := 0x0000 0002ab06: 0100 5200 ;BPLCON0 := 0x5200 0002ab0a: 0102 0011 ;BPLCON1 := 0x0011 0002ab0e: 0180 0000 ;COLOR00 := 0x0000 0002ab12: 0182 0b62 ;COLOR01 := 0x0b62 0002ab16: 0184 0b96 ;COLOR02 := 0x0b96 0002ab1a: 0186 0963 ;COLOR03 := 0x0963 0002ab1e: 0188 0741 ;COLOR04 := 0x0741 0002ab22: 018a 0520 ;COLOR05 := 0x0520 0002ab26: 018c 0720 ;COLOR06 := 0x0720 0002ab2a: 018e 0a20 ;COLOR07 := 0x0a20 0002ab2e: 0190 0ca3 ;COLOR08 := 0x0ca3 0002ab32: 0192 0aaa ;COLOR09 := 0x0aaa 0002ab36: 0194 0777 ;COLOR10 := 0x0777 0002ab3a: 0196 0555 ;COLOR11 := 0x0555 0002ab3e: 0198 0310 ;COLOR12 := 0x0310 0002ab42: 019a 0333 ;COLOR13 := 0x0333 0002ab46: 019c 0ddd ;COLOR14 := 0x0ddd 0002ab4a: 019e 0000 ;COLOR15 := 0x0000 0002ab4e: 01a0 0f0f ;COLOR16 := 0x0f0f 0002ab52: 01a2 0a62 ;COLOR17 := 0x0a62 0002ab56: 01a4 0941 ;COLOR18 := 0x0941 0002ab5a: 01a6 0831 ;COLOR19 := 0x0831 0002ab5e: 01a8 0710 ;COLOR20 := 0x0710 0002ab62: 01aa 0b82 ;COLOR21 := 0x0b82 0002ab66: 01ac 000b ;COLOR22 := 0x000b 0002ab6a: 01ae 0008 ;COLOR23 := 0x0008 0002ab6e: 01b0 0999 ;COLOR24 := 0x0999 0002ab72: 01b2 0666 ;COLOR25 := 0x0666 0002ab76: 01b4 0888 ;COLOR26 := 0x0888 0002ab7a: 01b6 0444 ;COLOR27 := 0x0444 0002ab7e: 01b8 0222 ;COLOR28 := 0x0222 0002ab82: 01ba 0111 ;COLOR29 := 0x0111 0002ab86: 01bc 0004 ;COLOR30 := 0x0004 0002ab8a: 01be 0006 ;COLOR31 := 0x0006 0002ab8e: e901 fffe ;Wait for vpos >= 0xe9 and hpos >= 0x00. 0002ab92: 01a0 0444 ;COLOR16 := 0x0444 0002ab96: ea01 fffe ;Wait for vpos >= 0xea and hpos >= 0x00. 0002ab9a: 01a0 0666 ;COLOR16 := 0x0666 0002ab9e: eb01 fffe ;Wait for vpos >= 0xeb and hpos >= 0x00. 0002aba2: 01a0 0777 ;COLOR16 := 0x0777 0002aba6: ec01 fffe ;Wait for vpos >= 0xec and hpos >= 0x00. 0002abaa: 01a0 0999 ;COLOR16 := 0x0999 0002abae: ed01 fffe ;Wait for vpos >= 0xed and hpos >= 0x00. 0002abb2: 01a0 0aaa ;COLOR16 := 0x0aaa 0002abb6: ffdf fffe ;Wait for vpos >= 0xff and hpos >= 0xde. 0002abba: 0101 fffe ;Wait for vpos >= 0x01 and hpos >= 0x00. 0002abbe: 01a0 0444 ;COLOR16 := 0x0444 0002abc2: 01a9 fffe ;Wait for vpos >= 0x01 and hpos >= 0xa8. 0002abc6: 01a0 0444 ;COLOR16 := 0x0444 0002abca: 0201 fffe ;Wait for vpos >= 0x02 and hpos >= 0x00. 0002abce: 01a0 0666 ;COLOR16 := 0x0666 0002abd2: 02a9 fffe ;Wait for vpos >= 0x02 and hpos >= 0xa8. 0002abd6: 01a0 0666 ;COLOR16 := 0x0666 0002abda: 0301 fffe ;Wait for vpos >= 0x03 and hpos >= 0x00. 0002abde: 01a0 0777 ;COLOR16 := 0x0777 0002abe2: 03a9 fffe ;Wait for vpos >= 0x03 and hpos >= 0xa8. 0002abe6: 01a0 0777 ;COLOR16 := 0x0777 0002abea: 0401 fffe ;Wait for vpos >= 0x04 and hpos >= 0x00. 0002abee: 01a0 0999 ;COLOR16 := 0x0999 0002abf2: 04a9 fffe ;Wait for vpos >= 0x04 and hpos >= 0xa8. 0002abf6: 01a0 0999 ;COLOR16 := 0x0999 0002abfa: 0501 fffe ;Wait for vpos >= 0x05 and hpos >= 0x00. 0002abfe: 01a0 0aaa ;COLOR16 := 0x0aaa 0002ac02: 05a9 fffe ;Wait for vpos >= 0x05 and hpos >= 0xa8. 0002ac06: 01a0 0aaa ;COLOR16 := 0x0aaa 0002ac0a: 0601 fffe ;Wait for vpos >= 0x06 and hpos >= 0x00. 0002ac0e: 01a0 0ddd ;COLOR16 := 0x0ddd 0002ac12: 06a9 fffe ;Wait for vpos >= 0x06 and hpos >= 0xa8. 0002ac16: 01a0 0ddd ;COLOR16 := 0x0ddd 0002ac1a: 0701 fffe ;Wait for vpos >= 0x07 and hpos >= 0x00. 0002ac1e: 01a0 0ddd ;COLOR16 := 0x0ddd 0002ac22: 07a9 fffe ;Wait for vpos >= 0x07 and hpos >= 0xa8. 0002ac26: 01a0 0ddd ;COLOR16 := 0x0ddd 0002ac2a: 1101 fffe ;Wait for vpos >= 0x11 and hpos >= 0x00. 0002ac2e: 01a0 0444 ;COLOR16 := 0x0444 0002ac32: 1201 fffe ;Wait for vpos >= 0x12 and hpos >= 0x00. 0002ac36: 01a0 0666 ;COLOR16 := 0x0666 0002ac3a: 1301 fffe ;Wait for vpos >= 0x13 and hpos >= 0x00. 0002ac3e: 01a0 0777 ;COLOR16 := 0x0777 0002ac42: 1401 fffe ;Wait for vpos >= 0x14 and hpos >= 0x00. 0002ac46: 01a0 0999 ;COLOR16 := 0x0999 0002ac4a: 1501 fffe ;Wait for vpos >= 0x15 and hpos >= 0x00. 0002ac4e: 01a0 0aaa ;COLOR16 := 0x0aaa 0002ac52: 1901 fffe ;Wait for vpos >= 0x19 and hpos >= 0x00. 0002ac56: 009c 8010 ;INTREQ := 0x8010 0002ac5a: 0180 0000 ;COLOR00 := 0x0000 0002ac5e: 0182 0000 ;COLOR01 := 0x0000 0002ac62: 0184 0000 ;COLOR02 := 0x0000 0002ac66: 0186 0000 ;COLOR03 := 0x0000 0002ac6a: 0188 0000 ;COLOR04 := 0x0000 0002ac6e: 018a 0000 ;COLOR05 := 0x0000 0002ac72: 018c 0000 ;COLOR06 := 0x0000 0002ac76: 018e 0000 ;COLOR07 := 0x0000 0002ac7a: 0190 0000 ;COLOR08 := 0x0000 0002ac7e: 0192 0000 ;COLOR09 := 0x0000 0002ac82: 0194 0000 ;COLOR10 := 0x0000 0002ac86: 0196 0000 ;COLOR11 := 0x0000 0002ac8a: 0198 0000 ;COLOR12 := 0x0000 0002ac8e: 019a 0000 ;COLOR13 := 0x0000 0002ac92: 019c 0000 ;COLOR14 := 0x0000 0002ac96: 019e 0000 ;COLOR15 := 0x0000 0002ac9a: 01a0 0000 ;COLOR16 := 0x0000 0002ac9e: 01a2 0000 ;COLOR17 := 0x0000 0002aca2: 01a4 0000 ;COLOR18 := 0x0000 0002aca6: 01a6 0000 ;COLOR19 := 0x0000 0002acaa: 01a8 0000 ;COLOR20 := 0x0000 0002acae: 01aa 0000 ;COLOR21 := 0x0000 0002acb2: 01ac 0000 ;COLOR22 := 0x0000 0002acb6: 01ae 0000 ;COLOR23 := 0x0000 0002acba: 01b0 0000 ;COLOR24 := 0x0000 0002acbe: 01b2 0000 ;COLOR25 := 0x0000 0002acc2: 01b4 0000 ;COLOR26 := 0x0000 0002acc6: 01b6 0000 ;COLOR27 := 0x0000 0002acca: 01b8 0000 ;COLOR28 := 0x0000 0002acce: 01ba 0000 ;COLOR29 := 0x0000 0002acd2: 01bc 0000 ;COLOR30 := 0x0000 0002acd6: 01be 0000 ;COLOR31 := 0x0000 0002acda: ffff fffe ;Wait for vpos >= 0xff and hpos >= 0xfe. ;End of Copperlist
Quite an interesting technique!
Popular Sprite Tricks
2 sprites are displayed then repositioned horizontally right across the screen to create the colourful static background. The remaining sprites are used for the main character, the status bar and player bullets.
One of the first jaw-droppingly beautiful Amiga games that still looks great today. Sprites were heavily re-used on the screen, along with priority changes to make them appear between the playfields.
The amazing tunnel sequence was created with a 6 frame animation sequence made with only 4 colours and mirrored vertically. The asteroid layer sits on top of this, with a status panel and player ship made of sprites sitting on top.
Post your comment
Comments
I'm pretty sure the racing-the-beam aspect of the Copper is by design since the Amiga's lineage goes back to the Atari 2600 and is essentially an extension of the Atari 800. Everything in the OCS Amigas was timed precisely. More info in the Byte Magazine articles on the Amiga and interviews with the design team: http://www.blitter.com/~nebulous/otherworld/Amiga/AmigaByte-Aug1985.pdf http://www.blitter.com/~nebulous/otherworld/Amiga/AmigaByte-Nov1985(JMiner).pdf https://www.youtube.com/watch?v=6YqDOKXQk1w https://archive.org/details/amiga-hardware-reference-manual-3rd-edition
J-Bot 30/05/2023 7:08am (18 months ago)
Thank you for this article! I always wondered how they achieved this.
Ragnarok 11/01/2016 1:56pm (9 years ago)
No one has commented on this page yet.
RSS feed for comments on this page | RSS feed for all comments