|
I have wanted to write about this topic for while
and since several people who took my survey have asked about it,
I figured now would be a good time. There are basically two
systems of graphics used in arcade games: Vector and Raster.
Vector
An example of a vector game is Asteroids. The game
code directly controls the movement and intensity of a beam of light
on the monitor. The picture tube of the monitor has a horizontal
and vertical set of magnets which direct the beam to a specific
coordinate. By specifying two pairs of coordinates with the
proper timing, a line is drawn. In the majority of vector
games, a special circuit takes care of the exact timing of the beam
movement to prevent flicker and take a load off of the CPU.
Specifically, Asteroids has a vector list processor which continuously
draws a list of vectors stored in RAM. The CPU simply updates
the list of vectors to make objects move on the screen. That's
why it is possible for a 1Mhz 6502 to handle the graphics, sound
and gameplay of Asteroids. Vector graphics can be either monochrome
and color (e.g. Tempest). Vector games tend to display stick
figure objects since it would require too much time to move the
beam back and forth to fill in solid objects. You can notice
some flicker on games which try to display too many objects simultaneously;
the display phosphors do not retain the light long enough before
the beam retraces the images. The main advantages of vector
graphics are that they require very little RAM and can display razor
sharp lines and arcs.
To emulate this system of graphics, you will work
from the vector table that the game generates and draw the lines
to a video buffer for display to the user. For Asteroids,
you must emulate the behavior of the vector list processor and execute
the vector instructions to draw the objects. There are many
ways to accomplish this task and many efficient means of only re-drawing
the lines which change. Some of the newer emulators also have
added anti-aliased line drawing which uses different shades of color
to hide the stair-step effect of lines drawn on a limited resolution
raster display. I use a brute force method in HiVE and redraw
the entire scene each frame. I am more interested in the raster
video games and have not devoted any time to optimizing my vector
graphics routines. For a look at how Asteroids graphics can
be emulated, download source.zip
and look in asteroid.c
Raster
Raster graphics come in several flavors, but for all of
them the display is refreshed in basically the same manner.
The video monitor traces a beam from left to right and top to bottom
at a typical rate of 60 frames per second. As this beam is
traced across the display, the color and intensity of any spot is
determined by the contents of RAM. Since RAM retains its contents
from frame to frame, once an image is loaded, it will remain displayed
until changed.
Raster - Pixel Based
Some games use a scheme where each pixel is individually
addressable and generated by 1 or more bits of RAM. An example
of games which do this are the Williams games (Robotron, Joust,
Splat, ...). Since a display of reasonable resolution requires
a relatively large amount of memory (304 x 256 x 4 bits per pixel
= 38912 bytes), the 8-bit CPU's of the past would have a hard time
manipulating that much memory at high speed. To speed up modifying
the display memory, the Williams games use a 'blitter' chip.
What this chip does is a fast block copy of memory from a source
to a destination and can perform various logical operations on the
bits during the process. The game code will typically manipulate
the graphics memory directly as well as make use of the blitter
chip for drawing/erasing the game's moving objects. Some
older / more primitive games such as those that run on the Space
Invaders platform did not have a blitter chip and performed all
graphics by having the CPU change the contents of memory.
In HiVE, I emulate the Williams blitter chip and translate all writes
to video memory. Shown below is a snippet of code taken from
the Williams video write routine. In the following code, usAddr
is the address being written to, ucByte is the byte to write, pBitmap
points to the DIB used to hold the current video frame, and iYOffset
is used to speed up calculating the destination address in the DIB.
HiVE emulates all games into a 256 color bitmap since it is easiest
to work with one byte per pixel. Since a byte of video RAM
holds two pixels, each byte written to video memory must modify
two bytes in my destination bitmap. The offset of 16 added
to each pixel is to match the colors in my identity palette.
x = 2 * (usAddr >> 8);
y = usAddr & 0xff;
cDirtyRect |= 1<< (y >> 5);
bm1 = &pBitmap[iYOffset[y] + x];
*bm1++ = 16 + (ucByte >> 4);
*bm1 = 16 + (ucByte & 0xf);
Some raster games have the pixels oriented 'sideways'
compared to a PC's video display.
Raster - Character / Sprite Based
The majority of video games that I have seen use a combination
of characters and sprites. Character graphics is where one
or two bytes of video memory specify a character pattern retrieved
from ROM by the video controller. This way, a screen full
of graphics may require only 1 or 2K of RAM memory. Each character
will typically map a 8x8 pixel character cell where one byte of
the character memory specifies the pattern and another may specify
the color. Phoenix is an example of a character based video
game. Since the entire screen is mapped to only 1 or 2K of
RAM, a slow 8-bit CPU is able to handle screen updates without having
to modify very much memory.
Since character graphics tend to be rather chunky
and are not addressable on a pixel by pixel basis, one solution
is to add what are generally called sprites. Sprites are graphics
blocks (typically 16x16 pixels) which can be placed at any position
on the display (in pixel coordinates) and are drawn by additional
video hardware. The game code merely has to update 3 pieces
of information to draw a sprite: pattern (bitmap), color, position.
Sprites can number from a few to a hundred per game and are usually
used for the moving objects. Super PacMan is a game which
uses sprites for both moving objects and static objects such as
keys and fruits/pellets. Sprites usually have priority over
characters (the character will be hidden by the sprite drawn on
top of it). Sprites also have transparent parts so that their
edges don't look like square black blocks and objects 'behind' them
can be seen through holes in the object such as eyes. Mappy
and Jr. PacMan are examples of games where characters can have priority
over sprites.
The sprites have priority over each other as well.
The order in which the sprites are drawn determines their priorities
over one another; the last one drawn has the highest priority.
The PacMan games are examples of character/sprite graphics.
PacMan has a memory map of 2K for characters/colors and 6 sprites
used for the moving objects and bonus points display.
One way to handle refreshing the display of a character/sprite
video game each frame is to draw all of the characters and sprites
at the end of each frame. A more efficient way to update the
display which I use is a set of flags to tell me when a character/color/sprite
has changed and only draw the changes from one frame to the next.
A write to video memory causes the flag for that character to be
set. At the end of each frame, only the changed characters/sprites
are drawn and the flags are all reset. This is one of the
reasons my PacMan emulation is so fast. Shown below is the
handler routine for video writes used in my PacMan driver:
if (mem_map[MEM_RAM + usAddr] != ucByte)
{
mem_map[MEM_RAM + usAddr] = ucByte;
cDirtyChar[usAddr & 0x3ff] = 1;
}
For code samples of how to draw sprites and characters,
download source.zip
and look in public.c
Webdesign
by Deep Magic Studios
- HanaHo Games, Inc. Copyright © 2002 |