[stella] How RRampage works

Subject: [stella] How RRampage works
From: "Erik Mooney" <erik@xxxxxxxxxx>
Date: Mon, 12 Apr 2004 12:21:17 -0500
I'm bored at work and can't stop thinking about River Rampage.  So I wrote
up a description of how it works. :)

First, player 1 and missile 1 are used to draw the player and his bullets;
P0 and M0 are used for the enemies and their shots.  This is because P0/M0
have higher display priority than P1/M1; you don't want your bullets to
obscure things that you need to dodge.

The kernel is basically a 4-line loop (it's actually unrolled to 8, but 4
is good enough to describe it):

Line 1: reposition P0 if necessary
Line 2: do a bunch of calculations
Line 3: reposition M0 (this always happens every 4 lines)
Line 4: on every other iteration, HMOVE and display the player's bullets
(so every bullet is 8 scanlines tall)

NUSIZ1 is set to draw the multiple copies of the bullets, of course.  The
trick is that P1 and M1 are never fully repositioned during the screen -
they're only HMOVEd, so we can reposition from one bullet to the next
using only a few instructions instead of an entire scanline for each
object.  But the bullets are independent - what if you shoot, stop
shooting, and shoot again so that there's a large horizontal space between
successive bullets?

The answer is that the game keeps calculating and HMOVEing invisible
bullets on all the inbetween lines, even when you're not shooting, using
GRP1 and ENAM1 to turn them off when appropriate.  It initializes a new
bullet every frame whether or not the joystick button is pressed.

As for P0, I actually only reposition it every *four* lines, yet it still
has single-line resolution.  That's done through the indirect-indexed
pointer to the sprite graphics.  Every scanline does an indirect-indexed
graphics lookup and store to GRP0.  Every enemy sprite image in ROM is
padded with three extra bytes of zeroes; and if necessary the code can
adjust the pointer by up to 3 bytes.[1]  So after the repositioning, we
can keep writing 0 to GRP0 for up to three additional lines until it
really is time to display the object.  Similar idea to the hardware VDEL
registers, but much more flexible and powerful.

To make the GRP0 handling as fast as possible, I'm not even using
SkipDraw.  When the kernel reaches the end of a player object (this check
runs once every 4 lines), it changes the high byte of the 16-bit pointer
to point to an entire ROM page full of just zeroes.  Then all the GRP0
lookups will just grab zeroes until we reach and initialize a new enemy
object while scanning down the screen.  ROM is plentiful, cycles aren't.
:)  This results in being able to have any vertical distance between two
enemies, instead of constricting them to a specific schedule like in River
Raid.

The laser is the ball.  That's just positioned once, offscreen, and when
the kernel gets to the player's sprite, it writes 0 to ENABL.  Cake.

The last trick is how P1 gets repositioned after the bullets to draw the
player's plane, without any interruption to the rest of the repositioning.
This is done in a way that I theorized about years ago. :)  When we reach
the player's plane, the player's bullets are no longer being drawn, so
scanline 4 of the kernel loop is available.  It uses a JMP Indirect to
branch to one of 11 different versions of that scanline based on the
horizontal position of the player.  Each version has its instructions
ordered so that a STA RESP1 is timed to hit at the appropriate time.  That
does the coarse horizontal positioning just as a regular delay loop would,
and HMP1/HMOVE fine-tunes the position as usual, and lets it run right
back into positioning P0 on the next scanline if necessary.

[1]This isn't implemented just yet (which is why that demo doesn't move
anything vertically), as I need to work out exactly how to allocate the
Superchip RAM.  It'll be easiest if I have enough RAM to set up
(offscreen) a separate pointer for each enemy.  Gotta find some time to do
more coding this week...
----------------------------------------------------------------------------------------------
Archives (includes files) at http://www.biglist.com/lists/stella/archives/
Unsub & more at http://www.biglist.com/lists/stella/


Current Thread