This document attempts to explain the inner workings of the
graphics system used in "Metroid". I've spent a great deal of
time trying to figure out how everything works, and a lot of
time writing this document, because I know that many people
want to know more about this topic. In case you haven't
already downloaded my Metroid level editor, which is the
ultimate result of my research, you can do so by clicking
here.
Throughout this document, I will assume that you're not a complete
newbie to ROM hacking. A basic understanding of how NES graphics work is
recommended, but certainly not required, as I will explain it later on.
I've tried not to make too many assumptions, and hopefully most of it is
understandable. If there's something you find hard to understand, drop me
an email and I'll try to clarify.
Just for the record, all my discoveries covered in this
document are the result of observation, experimentation and use of
logical sense. No ASM hacking was required. I believe that mostly
everything which has to do with the visual appearance of a game does
not require changing the data processor (i.e. the game code), only
the data that it processes. Knowledge of the console's hardware can get
you very far. There's no denying that being able to think like a
programmer helps when dealing with this kind of stuff though. I couldn't
have done this without that ability.
Viewed as a whole, the format of the Metroid level data is pretty complex.
But the programmers wisely broke it into several "sub-formats" to make it
easier to handle. Also, this allows us to study the formats separately.
I'll start by explaining the most basic of the formats, and then delve
further into the complexity as I move along.
Part 1: LEVEL MAP
As you've experienced from playing Metroid, the game is in essence a
myriad of long and short horizontal and vertical shafts. Internally,
things work a bit different. At game code level, the areas of Metroid
are just a series of different "rooms" which are pieced together to
create a larger environment. One room as seen in the game is 256x240
pixels (one NES screen) in size. It's very similar to how The Legend of
Zelda works: The difference is that in Metroid, the screen scrolls according
to the position of the main character (Samus), not when you touch a screen
boundary like in Zelda. Therefore, you don't get the impression that you're
travelling from one location on a map to another, but that's what's going
on internally.
Here are some rooms you've surely seen:
These were just a couple of examples; there are many rooms
defined for each area. Now, it is important to understand
that the rooms are independent of eachother.
When Samus is exploring the intricate areas of the planet SR388,
she is continuously moving from one "room" to another, and
changing her position on the internal level map. Which room she
moves to is determined by this map.
The level map is what chains the rooms together so that they form
corridors and shafts; the way you see the game when you're playing it.
Each room has a specific number associated with it. The level map
holds these numbers for each location on the map. The map itself is
32x32 bytes (1K) in size, one byte for each room, and is located at
offset 0254E-0294D in the Metroid ROM. Altering the area
design is as easy as changing the numbers at the appropriate position
in the level map. Note that each area has a finite number of rooms
defined though, and if an entry in the level map exceeds this number,
the game will crash.
Below is the complete level map for Metroid. It is taken directly
from the ROM. Notice that it's almost like looking at a standard
map of the game. The FF bytes are locations in the map which aren't
used, and can't be accessed. They are there to prevent Samus from
moving any further in that direction. They can be changed to different values
though, so in theory all 1024 slots of the map can be used.
Thanks to Charles DuMarr for sending me this image! It was what inspired
me to include a Metroid map viewer within MetEdit.
(Interesting note: The map positions coloured red are rooms which
shouldn't really be there: they are not accessible in the game, and
might be "left-overs" from an early stage of the level design.)
As you can see, the same room can be used multiple times on the map.
You've probably noticed that many of the places in Metroid look very
similar. Well, now you know the reason: technically, they are
the same place! Another important fact is that it's impossible to have
two horizontal shafts or two vertical shafts directly next to eachother.
Each time Samus goes through a door, the game switches to the opposite
scrolling type. The only times that this does not hold true is when you
enter or exit a special item room. In such cases the game continues to
scroll horizontally.
OK, are you still with me? Good, because now it's time to get started on
the juicy stuff: the actual room data.
Part 2: ROOM DATA FORMATS
As you've just learned, the internal level map defines the structure of
the areas in the game. But knowing that isn't enough of course. At a
lower level, there is the actual room data; the data that defines the
visible objects in the rooms that the level map references.
The format of the room data is different from anything I've seen in a
NES game (except for Kid Icarus, which has the exact same format). The
programmers divided it into three separate formats:
1. Tile definitions
I'll explain each of these formats in detail, starting with the cornerstone
of the level data: the tile definitions.
TILE DEFINITIONS
As you probably know, the NES screen is represented in NES PPU memory by a
table of tile index values, 32x30 bytes in size. This table is called a
Name Table. Each byte holds a value which references a tile in the Pattern
Table; tiles themselves are 8x8 pixels each. (See y0shi's "nestech.txt" for
more technical information.) A graphical way of representing NES video memory
is this:
Each square represents a byte in the Name Table, and each byte holds a tile value
ranging from 00 to FF. This value determines what tile will be displayed
in that particular area of the screen.
If you study the screen grid above, you will see that the tiles together form
larger patterns; rocks, vents, columns and so on. Here are some examples:
Notice that each pattern consists of four tiles, forming a 2x2 tile grid.
Since these and many other specific patterns are used many times, and their tile
values always stay the same, specifying the four tile values for a certain pattern
every time that pattern is to appear on the screen would be wasteful. Instead,
the tile values are defined only once, and then each 2x2 tile pattern is referenced
by a byte value, exactly the same way as rooms are referenced in the level map.
This also means that if you change the tile definitions for a certain pattern, every
occurance of that pattern will change in the game. Clever eh?
Well, it's the way almost all (if not absolutely all) games which have much level
data do it. Apart from saving a lot of space in the ROM, it also saves the level designers
a lot of time.
But just defining tile patterns like this wasn't enough for the Metroid programmers. They
had to expand on this concept because of the space constraints and high cost of early NES
carts. Which brings us to the next format:
STRUCTURE DEFINITIONS
If you look beyond the 2x2 tile patterns in the many rooms of Metroid, you will see that
they form even larger patterns, structures as I call them, which are of variable
height and width. Examples of common structures which are repeated many times are:
These structures are also defined only once and then referred to by a byte value in the
object definitions (explained in the next section). The tile definitions described in
the previous section are used to define them. The format of a structure is as follows:
Just like the tile definitions, each structure definition
has a unique byte value, regardless of its individual size.
These values are used by the next and final format:
OBJECT DEFINITIONS (ROOM DATA)
The object definitions are what one might call the
real room data. To save even more space, the Metroid
programmers decided to create a data format which only
stores data for the sections of each room that are
actually used. Initially, when a room is drawn, the whole
Name Table is "cleared" (set to a totally transparent tile),
in other words it's black. Then, the room objects are
laid on top of eachother according to the room data (object definitions).
The room data consists of a number of 3-byte chunks, each chunk
defining a screen object, which are of the following format (values
represented in binary):
Byte 0: %yyyyxxxx yyyy = Y coordinate of graphical structure xxxx = X coordinate of graphical structure The coordinates of the upper left corner of the structure. Multiply by 16 to get the real screen coordinates. Byte 1: %ssssssss This byte holds the value of the graphical structure to display. See explanations in previous section. Byte 2: %------cc cc = Palette number used when the tiles are displayed. Only the lower two bits of this byte are used, the upper six are ignored. The palette bits are written to the NES Attribute Table (see "nestech.txt").
These objects are drawn in the order they appear
in the room data. When the value FD is reached,
it means the entire room has been set up.
Part 3: ROM MAP
The final section of this document is a listing of the
parts of the Metroid ROM that have to do with the graphics.
If you're planning on doing a level editor, or just want to
mess around with the ROM, this listing can be pretty useful. :-)
Area: Brinstar
Area: Norfair
Area: Tourian
Area: Kraid
Area: Ridley
For you fellow programmers out there, the room values
and structure definition values (which both have been
discussed earlier) are just indexes into
their respective pointer tables. For example, value 00
fetches the 1st 16-bit pointer from the table, value 01
fetches the 2nd 16-bit pointer, and so on. As for the
tile definition values: since each tile definition is
four bytes long (2x2 tiles), simply multiply the value
by four to get the offset into the tile definition table.
Also, note that the very first byte of each room's data has unknown
meaning to me. It's a 2-bit value, so my guess is that it
specifies which Name Table the room should be drawn to,
but if you're writing a level editor, you can just skip it.
Well, that should just about cover everything. What's
that? "Enemy data information", you say? Nah, better
save that for my next document.
If you still have any questions, or just want to give me some comments, please direct an email to kentmhan@online.no. Have a nice day. Back to SnowBro Software |