Jim Power
Jim Power in Mutant Planet is an Amiga game with some amazing sprite tricks. Even the title screen heavily uses sprites. First, the title screen with sprites enabled on the left, and disabled on the right:
If sprites are disabled, the background colour almost disappears completely!
As you can probably tell from the full title screen, the background repeats regularly, every 32 pixels. This gives away the fact that the game is repeating 2 sprites across the screen. The same trick is used in the game, so let's see what it looks like:
Analysing the game shows that has been designed around the Amiga's hardware limitations and a game put around it. Sprites are used as follows:
- Sprites 0 and 1 (attached) are used for the main character and the status bar under the game
- Sprites 2 and 3 (attached) are the right side of the main character
- Sprites 4 and 5 are the player bullets (hence a limitation of 2 bullets on screen at once)
- Sprites 6 and 7 are 4 colour sprites repeated across the screen for the background and the top status bar
As you can probably imagine, the copperlist is a biggie! In the screenshot above, you can see where there are horizontal bands of solid colour. The game carefully fades the sprite patterns into these colours allowing the game to change the rest of the screen palette during these areas.
The main game area part of the copperlist starts by waiting for line $3e, then sets one of the sprite colours, loads the sprite data, and positions sprite 6 at horizontal position $40 (64 in decimal). 64 is the far left of the normal viewable screen. It then positions sprite 7 to $48 (80 in decimal), exactly 16 pixels to the right of sprite 6. During that time, sprite 6 is moved 16 pixels to the right, followed by sprite 7. This effect renders the sprites across the entire screen:
0000872c: 3e21 fffe ;Wait for vpos >= 0x3e and hpos >= 0x20. 00008730: 01ba 0035 ;COLOR29 := 0x0035 00008734: 0174 0155 ;SPR6DATA := 0x0155 00008738: 0176 0000 ;SPR6DATB := 0x0000 0000873c: 017c ffa8 ;SPR7DATA := 0xffa8 00008740: 017e 0000 ;SPR7DATB := 0x0000 00008744: 0170 0040 ;SPR6POS := 0x0040 00008748: 0178 0048 ;SPR7POS := 0x0048 0000874c: 0170 0050 ;SPR6POS := 0x0050 00008750: 0178 0058 ;SPR7POS := 0x0058 00008754: 0170 0060 ;SPR6POS := 0x0060 00008758: 0178 0068 ;SPR7POS := 0x0068 0000875c: 0170 0070 ;SPR6POS := 0x0070 00008760: 0178 0078 ;SPR7POS := 0x0078 00008764: 0170 0080 ;SPR6POS := 0x0080 00008768: 0178 0088 ;SPR7POS := 0x0088 0000876c: 0170 0090 ;SPR6POS := 0x0090 00008770: 0178 0098 ;SPR7POS := 0x0098 00008774: 0170 00a0 ;SPR6POS := 0x00a0 00008778: 0178 00a8 ;SPR7POS := 0x00a8 0000877c: 0170 00b0 ;SPR6POS := 0x00b0 00008780: 0178 00b8 ;SPR7POS := 0x00b8 00008784: 0170 00c0 ;SPR6POS := 0x00c0 00008788: 0178 00c8 ;SPR7POS := 0x00c8 0000878c: 0170 00d0 ;SPR6POS := 0x00d0 00008790: 0178 00d8 ;SPR7POS := 0x00d8
The next line doesn't use any sprites, and simply sets a colour register, before the next 2 lines do the repeated sprite trick again:
00008794: 3f21 fffe ;Wait for vpos >= 0x3f and hpos >= 0x20. 00008798: 019e 0035 ;COLOR15 := 0x0035 0000879c: 4021 fffe ;Wait for vpos >= 0x40 and hpos >= 0x20. 000087a0: 01bc 0267 ;COLOR30 := 0x0267 000087a4: 0174 ffe8 ;SPR6DATA := 0xffe8 000087a8: 0176 0017 ;SPR6DATB := 0x0017 000087ac: 017c 55ff ;SPR7DATA := 0x55ff 000087b0: 017e aa00 ;SPR7DATB := 0xaa00 000087b4: 0170 0040 ;SPR6POS := 0x0040 000087b8: 0178 0048 ;SPR7POS := 0x0048 000087bc: 0170 0050 ;SPR6POS := 0x0050 000087c0: 0178 0058 ;SPR7POS := 0x0058 000087c4: 0170 0060 ;SPR6POS := 0x0060 000087c8: 0178 0068 ;SPR7POS := 0x0068 000087cc: 0170 0070 ;SPR6POS := 0x0070 000087d0: 0178 0078 ;SPR7POS := 0x0078 000087d4: 0170 0080 ;SPR6POS := 0x0080 000087d8: 0178 0088 ;SPR7POS := 0x0088 000087dc: 0170 0090 ;SPR6POS := 0x0090 000087e0: 0178 0098 ;SPR7POS := 0x0098 000087e4: 0170 00a0 ;SPR6POS := 0x00a0 000087e8: 0178 00a8 ;SPR7POS := 0x00a8 000087ec: 0170 00b0 ;SPR6POS := 0x00b0 000087f0: 0178 00b8 ;SPR7POS := 0x00b8 000087f4: 0170 00c0 ;SPR6POS := 0x00c0 000087f8: 0178 00c8 ;SPR7POS := 0x00c8 000087fc: 0170 00d0 ;SPR6POS := 0x00d0 00008800: 0178 00d8 ;SPR7POS := 0x00d8 00008804: 411d fffe ;Wait for vpos >= 0x41 and hpos >= 0x1c. 00008808: 01ba 0267 ;COLOR29 := 0x0267 0000880c: 01bc 0035 ;COLOR30 := 0x0035 00008810: 0174 abff ;SPR6DATA := 0xabff 00008814: 0176 5400 ;SPR6DATB := 0x5400 00008818: 017c feaf ;SPR7DATA := 0xfeaf 0000881c: 017e 0150 ;SPR7DATB := 0x0150 00008820: 0170 0040 ;SPR6POS := 0x0040 00008824: 0178 0048 ;SPR7POS := 0x0048 00008828: 0170 0050 ;SPR6POS := 0x0050 0000882c: 0178 0058 ;SPR7POS := 0x0058 00008830: 0170 0060 ;SPR6POS := 0x0060 00008834: 0178 0068 ;SPR7POS := 0x0068 00008838: 0170 0070 ;SPR6POS := 0x0070 0000883c: 0178 0078 ;SPR7POS := 0x0078 00008840: 0170 0080 ;SPR6POS := 0x0080 00008844: 0178 0088 ;SPR7POS := 0x0088 00008848: 0170 0090 ;SPR6POS := 0x0090 0000884c: 0178 0098 ;SPR7POS := 0x0098 00008850: 0170 00a0 ;SPR6POS := 0x00a0 00008854: 0178 00a8 ;SPR7POS := 0x00a8 00008858: 0170 00b0 ;SPR6POS := 0x00b0 0000885c: 0178 00b8 ;SPR7POS := 0x00b8 00008860: 0170 00c0 ;SPR6POS := 0x00c0 00008864: 0178 00c8 ;SPR7POS := 0x00c8 00008868: 0170 00d0 ;SPR6POS := 0x00d0 0000886c: 0178 00d8 ;SPR7POS := 0x00d8 00008870: 4221 fffe ;Wait for vpos >= 0x42 and hpos >= 0x20. 00008874: 019e 0267 ;COLOR15 := 0x0267 00008878: 4321 fffe ;Wait for vpos >= 0x43 and hpos >= 0x20. 0000887c: 01bc 04aa ;COLOR30 := 0x04aa 00008880: 0174 f42b ;SPR6DATA := 0xf42b 00008884: 0176 0bd4 ;SPR6DATB := 0x0bd4 00008888: 017c aa8b ;SPR7DATA := 0xaa8b 0000888c: 017e 5574 ;SPR7DATB := 0x5574 00008890: 0170 0040 ;SPR6POS := 0x0040 00008894: 0178 0048 ;SPR7POS := 0x0048 00008898: 0170 0050 ;SPR6POS := 0x0050 0000889c: 0178 0058 ;SPR7POS := 0x0058 000088a0: 0170 0060 ;SPR6POS := 0x0060 000088a4: 0178 0068 ;SPR7POS := 0x0068 000088a8: 0170 0070 ;SPR6POS := 0x0070 000088ac: 0178 0078 ;SPR7POS := 0x0078 000088b0: 0170 0080 ;SPR6POS := 0x0080 000088b4: 0178 0088 ;SPR7POS := 0x0088 000088b8: 0170 0090 ;SPR6POS := 0x0090 000088bc: 0178 0098 ;SPR7POS := 0x0098 000088c0: 0170 00a0 ;SPR6POS := 0x00a0 000088c4: 0178 00a8 ;SPR7POS := 0x00a8 000088c8: 0170 00b0 ;SPR6POS := 0x00b0 000088cc: 0178 00b8 ;SPR7POS := 0x00b8 000088d0: 0170 00c0 ;SPR6POS := 0x00c0 000088d4: 0178 00c8 ;SPR7POS := 0x00c8 000088d8: 0170 00d0 ;SPR6POS := 0x00d0 000088dc: 0178 00d8 ;SPR7POS := 0x00d8 000088e0: 4421 fffe ;Wait for vpos >= 0x44 and hpos >= 0x20. 000088e4: 019e 04aa ;COLOR15 := 0x04aa 000088e8: 451d fffe ;Wait for vpos >= 0x45 and hpos >= 0x1c. 000088ec: 01ba 04aa ;COLOR29 := 0x04aa 000088f0: 01bc 07dc ;COLOR30 := 0x07dc 000088f4: 0174 ffd5 ;SPR6DATA := 0xffd5 000088f8: 0176 002a ;SPR6DATB := 0x002a 000088fc: 017c 7fff ;SPR7DATA := 0x7fff 00008900: 017e 8000 ;SPR7DATB := 0x8000 00008904: 0170 0040 ;SPR6POS := 0x0040 00008908: 0178 0048 ;SPR7POS := 0x0048 0000890c: 0170 0050 ;SPR6POS := 0x0050 00008910: 0178 0058 ;SPR7POS := 0x0058 00008914: 0170 0060 ;SPR6POS := 0x0060 00008918: 0178 0068 ;SPR7POS := 0x0068 0000891c: 0170 0070 ;SPR6POS := 0x0070 00008920: 0178 0078 ;SPR7POS := 0x0078 00008924: 0170 0080 ;SPR6POS := 0x0080 00008928: 0178 0088 ;SPR7POS := 0x0088 0000892c: 0170 0090 ;SPR6POS := 0x0090 00008930: 0178 0098 ;SPR7POS := 0x0098 00008934: 0170 00a0 ;SPR6POS := 0x00a0 00008938: 0178 00a8 ;SPR7POS := 0x00a8 0000893c: 0170 00b0 ;SPR6POS := 0x00b0 00008940: 0178 00b8 ;SPR7POS := 0x00b8 00008944: 0170 00c0 ;SPR6POS := 0x00c0 00008948: 0178 00c8 ;SPR7POS := 0x00c8 0000894c: 0170 00d0 ;SPR6POS := 0x00d0 00008950: 0178 00d8 ;SPR7POS := 0x00d8 00008954: 4625 fffe ;Wait for vpos >= 0x46 and hpos >= 0x24. 00008958: 0174 d500 ;SPR6DATA := 0xd500 0000895c: 0176 2aff ;SPR6DATB := 0x2aff 00008960: 017c 0abf ;SPR7DATA := 0x0abf 00008964: 017e f540 ;SPR7DATB := 0xf540 00008968: 0170 0040 ;SPR6POS := 0x0040 0000896c: 0178 0048 ;SPR7POS := 0x0048 00008970: 0170 0050 ;SPR6POS := 0x0050 00008974: 0178 0058 ;SPR7POS := 0x0058 00008978: 0170 0060 ;SPR6POS := 0x0060 0000897c: 0178 0068 ;SPR7POS := 0x0068 00008980: 0170 0070 ;SPR6POS := 0x0070 00008984: 0178 0078 ;SPR7POS := 0x0078 00008988: 0170 0080 ;SPR6POS := 0x0080 0000898c: 0178 0088 ;SPR7POS := 0x0088 00008990: 0170 0090 ;SPR6POS := 0x0090 00008994: 0178 0098 ;SPR7POS := 0x0098 00008998: 0170 00a0 ;SPR6POS := 0x00a0 0000899c: 0178 00a8 ;SPR7POS := 0x00a8 000089a0: 0170 00b0 ;SPR6POS := 0x00b0 000089a4: 0178 00b8 ;SPR7POS := 0x00b8 000089a8: 0170 00c0 ;SPR6POS := 0x00c0 000089ac: 0178 00c8 ;SPR7POS := 0x00c8 000089b0: 0170 00d0 ;SPR6POS := 0x00d0 000089b4: 0178 00d8 ;SPR7POS := 0x00d8 000089b8: 4721 fffe ;Wait for vpos >= 0x47 and hpos >= 0x20. 000089bc: 019e 07dc ;COLOR15 := 0x07dc 000089c0: 481d fffe ;Wait for vpos >= 0x48 and hpos >= 0x1c. 000089c4: 01ba 07dc ;COLOR29 := 0x07dc 000089c8: 01bc 0bff ;COLOR30 := 0x0bff 000089cc: 0174 fafe ;SPR6DATA := 0xfafe 000089d0: 0176 0501 ;SPR6DATB := 0x0501 000089d4: 017c ab7f ;SPR7DATA := 0xab7f 000089d8: 017e 5480 ;SPR7DATB := 0x5480 000089dc: 0170 0040 ;SPR6POS := 0x0040 000089e0: 0178 0048 ;SPR7POS := 0x0048 000089e4: 0170 0050 ;SPR6POS := 0x0050 000089e8: 0178 0058 ;SPR7POS := 0x0058 000089ec: 0170 0060 ;SPR6POS := 0x0060 000089f0: 0178 0068 ;SPR7POS := 0x0068 000089f4: 0170 0070 ;SPR6POS := 0x0070 000089f8: 0178 0078 ;SPR7POS := 0x0078 000089fc: 0170 0080 ;SPR6POS := 0x0080 00008a00: 0178 0088 ;SPR7POS := 0x0088 00008a04: 0170 0090 ;SPR6POS := 0x0090 00008a08: 0178 0098 ;SPR7POS := 0x0098 00008a0c: 0170 00a0 ;SPR6POS := 0x00a0 00008a10: 0178 00a8 ;SPR7POS := 0x00a8 00008a14: 0170 00b0 ;SPR6POS := 0x00b0 00008a18: 0178 00b8 ;SPR7POS := 0x00b8 00008a1c: 0170 00c0 ;SPR6POS := 0x00c0 00008a20: 0178 00c8 ;SPR7POS := 0x00c8 00008a24: 0170 00d0 ;SPR6POS := 0x00d0 00008a28: 0178 00d8 ;SPR7POS := 0x00d8 00008a2c: 4925 fffe ;Wait for vpos >= 0x49 and hpos >= 0x24. 00008a30: 0174 a055 ;SPR6DATA := 0xa055 00008a34: 0176 5faa ;SPR6DATB := 0x5faa 00008a38: 017c 00af ;SPR7DATA := 0x00af 00008a3c: 017e ff50 ;SPR7DATB := 0xff50 00008a40: 0170 0040 ;SPR6POS := 0x0040 00008a44: 0178 0048 ;SPR7POS := 0x0048 00008a48: 0170 0050 ;SPR6POS := 0x0050 00008a4c: 0178 0058 ;SPR7POS := 0x0058 00008a50: 0170 0060 ;SPR6POS := 0x0060 00008a54: 0178 0068 ;SPR7POS := 0x0068 00008a58: 0170 0070 ;SPR6POS := 0x0070 00008a5c: 0178 0078 ;SPR7POS := 0x0078 00008a60: 0170 0080 ;SPR6POS := 0x0080 00008a64: 0178 0088 ;SPR7POS := 0x0088 00008a68: 0170 0090 ;SPR6POS := 0x0090 00008a6c: 0178 0098 ;SPR7POS := 0x0098 00008a70: 0170 00a0 ;SPR6POS := 0x00a0 00008a74: 0178 00a8 ;SPR7POS := 0x00a8 00008a78: 0170 00b0 ;SPR6POS := 0x00b0 00008a7c: 0178 00b8 ;SPR7POS := 0x00b8 00008a80: 0170 00c0 ;SPR6POS := 0x00c0 00008a84: 0178 00c8 ;SPR7POS := 0x00c8 00008a88: 0170 00d0 ;SPR6POS := 0x00d0 00008a8c: 0178 00d8 ;SPR7POS := 0x00d8 00008a90: 4a21 fffe ;Wait for vpos >= 0x4a and hpos >= 0x20. 00008a94: 019e 0bff ;COLOR15 := 0x0bff 00008a98: 4c1d fffe ;Wait for vpos >= 0x4c and hpos >= 0x1c. 00008a9c: 01ba 0bff ;COLOR29 := 0x0bff 00008aa0: 01bc 0fff ;COLOR30 := 0x0fff 00008aa4: 0174 faaf ;SPR6DATA := 0xfaaf 00008aa8: 0176 0550 ;SPR6DATB := 0x0550 00008aac: 017c 6abf ;SPR7DATA := 0x6abf 00008ab0: 017e 9540 ;SPR7DATB := 0x9540 00008ab4: 0170 0040 ;SPR6POS := 0x0040 00008ab8: 0178 0048 ;SPR7POS := 0x0048 00008abc: 0170 0050 ;SPR6POS := 0x0050 00008ac0: 0178 0058 ;SPR7POS := 0x0058 00008ac4: 0170 0060 ;SPR6POS := 0x0060 00008ac8: 0178 0068 ;SPR7POS := 0x0068 00008acc: 0170 0070 ;SPR6POS := 0x0070 00008ad0: 0178 0078 ;SPR7POS := 0x0078 00008ad4: 0170 0080 ;SPR6POS := 0x0080 00008ad8: 0178 0088 ;SPR7POS := 0x0088 00008adc: 0170 0090 ;SPR6POS := 0x0090 00008ae0: 0178 0098 ;SPR7POS := 0x0098 00008ae4: 0170 00a0 ;SPR6POS := 0x00a0 00008ae8: 0178 00a8 ;SPR7POS := 0x00a8 00008aec: 0170 00b0 ;SPR6POS := 0x00b0 00008af0: 0178 00b8 ;SPR7POS := 0x00b8 00008af4: 0170 00c0 ;SPR6POS := 0x00c0 00008af8: 0178 00c8 ;SPR7POS := 0x00c8 00008afc: 0170 00d0 ;SPR6POS := 0x00d0 00008b00: 0178 00d8 ;SPR7POS := 0x00d8 00008b04: 4d1d fffe ;Wait for vpos >= 0x4d and hpos >= 0x1c. 00008b08: 01ba 0fff ;COLOR29 := 0x0fff 00008b0c: 01bc 0bff ;COLOR30 := 0x0bff 00008b10: 0174 afff ;SPR6DATA := 0xafff 00008b14: 0176 5000 ;SPR6DATB := 0x5000 00008b18: 017c ffaa ;SPR7DATA := 0xffaa 00008b1c: 017e 0055 ;SPR7DATB := 0x0055 00008b20: 0170 0040 ;SPR6POS := 0x0040 00008b24: 0178 0048 ;SPR7POS := 0x0048 00008b28: 0170 0050 ;SPR6POS := 0x0050 00008b2c: 0178 0058 ;SPR7POS := 0x0058 00008b30: 0170 0060 ;SPR6POS := 0x0060 00008b34: 0178 0068 ;SPR7POS := 0x0068 00008b38: 0170 0070 ;SPR6POS := 0x0070 00008b3c: 0178 0078 ;SPR7POS := 0x0078 00008b40: 0170 0080 ;SPR6POS := 0x0080 00008b44: 0178 0088 ;SPR7POS := 0x0088 00008b48: 0170 0090 ;SPR6POS := 0x0090 00008b4c: 0178 0098 ;SPR7POS := 0x0098 00008b50: 0170 00a0 ;SPR6POS := 0x00a0 00008b54: 0178 00a8 ;SPR7POS := 0x00a8 00008b58: 0170 00b0 ;SPR6POS := 0x00b0 00008b5c: 0178 00b8 ;SPR7POS := 0x00b8 00008b60: 0170 00c0 ;SPR6POS := 0x00c0 00008b64: 0178 00c8 ;SPR7POS := 0x00c8 00008b68: 0170 00d0 ;SPR6POS := 0x00d0 00008b6c: 0178 00d8 ;SPR7POS := 0x00d8 00008b70: 4e21 fffe ;Wait for vpos >= 0x4e and hpos >= 0x20. 00008b74: 019e 0fff ;COLOR15 := 0x0fff 00008b78: 5e21 fffe ;Wait for vpos >= 0x5e and hpos >= 0x20. 00008b7c: 01bc 0ffb ;COLOR30 := 0x0ffb 00008b80: 0174 fa87 ;SPR6DATA := 0xfa87 00008b84: 0176 0578 ;SPR6DATB := 0x0578 00008b88: 017c fe6f ;SPR7DATA := 0xfe6f 00008b8c: 017e 0190 ;SPR7DATB := 0x0190 ... and continues on ...
Due to heavy use of repeating sprites, the game imposes certain limitations on itself:
- Because the player sprite maybe located on the same line as the repeated sprites, it is not possible to re-use any of the sprites other than the background sprites 6-7. There is simply no DMA time left for the copper!
- This restricts the player to having 2 bullets rendered as sprites.
- The player is drawn with 2 sprites, so can never be more than 32 pixels wide (including gun).
- All enemy objects and platforms in the game must be drawn with the blitter.
These are by no means a problem, and no doubt the programmer was aware of these limitations and designed the game around them.
It is quite interesting to see exactly where the sprites are by disabling only sprite 7. The black background shines through wherever sprite 7 should be:
Popular Sprite Tricks
The 16-colour background layer was created by using all 8 hardware sprites and repositioning them across the screen. The same 64 pixel wide graphics are repeated across the entire play area.
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
Simply very impressive. I can imagine the headache during coding.
Scoose 14/05/2017 8:34pm (8 years ago)
Pure digital magic!
alex76gr 03/04/2015 6:53am (10 years ago)
Please keep teaching! I love learning things like this.
Moose Malloy 05/05/2014 3:16pm (11 years ago)
No one has commented on this page yet.
RSS feed for comments on this page | RSS feed for all comments