MEGASAMPLER BONUS 03: Advanced Tilemap Transitions

Standard fade effects on the Genesis usually involve darkening the color palette. However, MEGAPONG uses a more dynamic approach: it manipulates the Tilemap itself to create a "wave" of tiles that ripples across the screen.

1. The Core Concept: Tile Replacement

Instead of changing colors, we are changing which tile is displayed at every position on the screen grid (40x30 tiles).

We have 8 versions of the background tile, ranging from fully black to fully visible (Index values 0 to 7 respectively). By swapping these tiles in a specific pattern, we create an animation. Go into the res > Tiles folder and take a look at each individual tile for reference.

Tile Animation Sequence

The Setup

In megapong.c, we reserve a specific block of VRAM for these 8 transition tiles:

// Starting VRAM index for our 8 fade tiles
#define BG_FADE_INDEX 16

// Animation Array (0 = Black, 7 = Visible)
const Image* animFrames[8] = { ... };

2. The Math: Creating the "Wave"

To make the tiles fade in a wave pattern, we need to calculate a "distance" for every single tile on the screen (x, y).

We use Manhattan Distance, which is simply x + y. This creates a diagonal gradient.

Effect A: The "Draw-In" (Game Start)

Goal: The screen starts black and the game "wipes in" from the Top-Left (0,0) to the Bottom-Right.

The Logic:

  1. Origin: Top-Left (0, 0).
  2. Distance Formula: dist = x + y.
    • At (0,0), distance is 0.
    • At (1,1), distance is 2.
  3. Animation: We want the tiles close to (0,0) to appear first.
// Inside the nested loop (y=0..29, x=0..39)
int dist = x + y;

// Calculate which frame to show (0..7)
// 'timeStep' increases as the animation plays.
// '7 - ...' reverses the logic so we go from Black -> Visible
int frame = 7 - (timeStep - dist);

// Clamp the value so we don't crash
if (frame < 0) frame = 0;
if (frame > 7) frame = 7;
Wave Animation Gif

Effect B: The "Fade-Out" (Game Over)

Goal: The screen starts visible and "wipes out" to black, starting from the Bottom-Right (39, 29).

The Logic:

  1. Origin: Bottom-Right (39, 29).
  2. Distance Formula: We need the distance from the corner.
    • dist = (39 - x) + (29 - y)
  3. Animation: We want the tiles close to the bottom-right to turn black first.
// Calculate distance from bottom-right
int dist = (39 - x) + (29 - y);

// Standard logic: As time increases, 'frame' drops from Visible -> Black
int frame = timeStep - dist;

3. Optimization: The Buffer System

Updating 1,200 tiles (40x30) individually using VDP_setTileMapXY would be too slow and might cause screen tearing.

Instead, megapong.c uses a Buffer Strategy:

  1. Calculate in RAM: We run the loops and write the correct tile ID to a massive array called bg_map_buffer.
u16 bg_map_buffer[40 * 30];

// ... logic to fill buffer ...
bg_map_buffer[x + y * 40] = TILE_ATTR_FULL(...);
  1. Blast to VRAM: Once the entire frame is calculated, we send it to the VDP (Video Display Processor) in one single Direct Memory Access (DMA) command.
VDP_setTileMapDataRect(BG_B, bg_map_buffer, 0, 0, 40, 30, 40, DMA);

4. Putting it Together: The Wave Timer

We don't want the wave to move too fast. megapong.c uses a waveTimer to control the speed.

waveTimer++;

// Only update the screen every 4th frame (60fps / 4 = 15 updates/sec)
if (waveTimer % 4 == 0)
{
    int timeStep = waveTimer / 4;
    // ... run the loops ...
}

Tutorial Summary

  1. Don't just fade colors: You can animate the tilemap itself for cooler transitions.
  2. Use Math for Patterns: x + y creates a diagonal wave. x alone would be a horizontal wipe. y alone would be a vertical wipe.
  3. Buffer Your Writes: Always calculate your tilemap changes in a RAM array first, then send it to the VDP all at once using VDP_setTileMapDataRect. This keeps your game running at a smooth 60 FPS.