Link's Awakening: Rendering the opening cutscene

This article is part of an ongoing “Disassembling Link’s Awakening” series, where I attempt to gain some understanding on how special effects where implemented in this game.

When powering-up the console, after displaying the iconic “Nintendo™” logo, many Game Boy titles jump you right to a title screen.

Zelda: Link’s Awakening does better, and open with a nice opening cutscene, which introduces the plot and the characters of the story. Several smaller animated sequences are also sprinkled through the game – and roughly half-a-dozen were added during the DX remake, as a part of the Photographer sub-quest. The Ending sequence, with its impressive 5-minutes length, also have some nice visual effects exclusive to this segment of the game.

This opening cutscene, as the first sequence of the game, is a good starting point for understanding various special effects used through the game.

The sea sequence, stripped

The original Game Boy was first released in 1989, and has quite basic capabilities. The graphic primitives are based on tiles, background and sprites. Tiles are 8x8 bitmaps, arranged into the grid of a large scrollable background.

This grid is very rigid: that’s 8x8 for you, and nothing else. Fortunately, sprites are objects that can move with smaller increments, positioned over the background.

Note that there is no “direct drawing” mode of some sort: you can’t draw individual pixels on the Game Boy screen, it has to be part of a 8x8 tile.

This severely limits the drawing possibilities. Any advanced effects will have to use complex workarounds.

To understand, let’s have a look at the introduction sea sequence. We’re going to strip it of all special effects, and only use background scrolling, tiles and sprites.

(This can’t normally be seen in the game. But now that we have a limited source code, we can replace some code to disable specific features, re-assemble the ROM, and run it into our favorite emulator.)

Link's Awakening Sea Sequence without special effects

Less dramatic, isn’t it?

However the reduced motion allows us to see more clearly what is going on. What have we here?

Now if we were the developers of Link’s Awakening, what could we add to this scene to spice it up?

Waves in motion

For now the sea looks very static, almost like a solid surface. Nothing remotely menacing, like a deadly sea ready to sink our ship. Breaking the waves into different overlapping parts would be much better.

Unfortunately the Game Boy doesn’t has much control over how the tiles are arranged over the background: a simple 8x8 grid, nothing else.

But luckily we can animate the content of the tiles themselves! And that’s what the developers used: they made a small looping animation of overlapping waves, like an animated GIF.

Link's Awakening Sea Sequence animation loop

Here is how our scene looks with this wave animation.

Link's Awakening Sea Sequence with moving waves

Much better: we can see the waves going one behind each other.

However something looks strange. Due to the way the animation is made, the horizon is now moving up and down. Not very convincing. To avoid this, we’ll need a more complex trick.

Compensating for sea movement

Remember that we are drawing our scene over a scrollable background. The “camera” moving to the right is actually our background window being scrolled on the horizontal axis.

What we could do is also scroll the background up and down over the vertical axis, to compensate the horizon motion. This way the horizon position would appear constant. And this is actually what the game does.

Link's Awakening Sea Sequence Background movement

Nice trick. But one issue remains: although the horizon position looks now fixed, the clouds now appear to be moving up and down.

If only we could move only the lower part of the background, and left the upper part untouched…

Wait, the Game Boy can actually do this – by using the LCD STAT interrupt.

Abusing HBlank

The Game Boy LCD screen renders graphics line by line, sequentially from the top to the bottom. When reaching the end of an horizontal line, the LCD controller makes a small pause (of more-or-less 300 cycles) before drawing the next line: this period between two lines is the Horizontal Blank, or HBlank. (The name comes from the old CRT screens, where the electron beam physically needed to move back from the right of the line to the left of the new line.)

Likewise, when the last line has been rendered, the LCD controller makes a longer pause before jumping again to the top line: this period is the Vertical Blank, or VBlank.

Game Boy scanlines

Manipulating the Video Memory while the screen is being drawn is quite restricted: during this period many operations on the video memory are not possible, or simply ignored. This is why the logic of most games runs during the VBlank period, when nothing is being rendered, and all the video memory can be manipulated freely.

To make it easier, the Game Boy hardware can fire an interrupt when the Vertical Blank period begins (appropriately named the VBLANK interrupt).

But the video memory can also be manipulated at the end of each line, during the HBlank period — although you have very few cycles to do so. One popular manipulation is to change the x coordinates of the background for each line: this allows to create a wave-effect seen in many games (like this one).

Firing an interrupt for every HBlank would be quite expensive though – especially considered that usually most lines will be left unmodified. Fortunately the Game Boy provides a smarter primitive for this: the LYC register.

LYC stands for LCD Y Compare: put the number of a scanline in this register, and the LCD Status interrupt (or LCD STAT) will fire whenever HBlank occurs on this line specifically. Almost like setting a breakpoint.

And this is what the game does here.

When the interrupt occurs, the execution pointer will jump to the address $0388, the hardcoded value for this interrupt. The code can then shift the position of the background position after the clouds have been drawn, but before the sea appears.

Link's Awakening Moving the background offset during HBlank

By moving in sync with the waves animation, this gives the illusion that the horizon is stable. Here is what the scene becomes with vertical motion compensated.

Link's Awakening Sea Sequence Background movement

Note that the horizon motion is not perfectly compensated for: sometimes it moves one pixel up or down. I’m not sure if this is a bug or an intentional feature left there on purpose ; but it arguably looks better than having a perfectly stable horizon.

Differential scrolling

This is nice, but still lacks motion. To add some depth, an effect often see in 2D games is differential scrolling: scrolling portions of the background at different rates, to give an illusion of perspective and depth.

But remember, we still only have a static tiled background here. How can we add a differential scrolling effect on this constrained grid?

Well, we previously shifted the position of the background when the rendering reached a specific scanline: the same mechanism can be used again, but to shift the background horizontally.

This time we need to break at several different positions, one for each screen section. For this the game will divide the screen into five horizontal sections – and assign a scanline to each section.

Here is the relevant section of the game code that performs this effect.

    ; List of scanlines to divide the screen in horizontal sections.
    ; This is used to enable differential scrolling during the sea intro sequence.
    db $20, $30, $40, $60, $0  ; upper clouds, lower clouds, sea, upper waves, lower waves

; snip...

    ; Setup the next HBlank interrupt for the Sea intro sequence.
    ; e = Section Index
    ld   hl, $037F     ; hl = $037F + SectionIndex
    add  hl, de        ;
    ld   a, [hl]       ; a = next section scanline
    ld   [rLYC], a     ; Fire LCD Y-compare interrupt when reaching
                       ;   the scanline for the next section.
    ld   a, e          ; a = SectionIndex
    inc  a             ; Increment section index
    cp   $05           ; If SectionIndex != 5
    jr   nz, .return   ;     return
    ; If SectionIndex == 5
    xor  a             ; Reset the section index to 0

What all this means? When the scanline for the next section is reached, the LCD STAT interrupts fire, and the background is moved. Then the game increments the section index, retrieves in a list the scanline for the next section, and reprogram the LYC register with the new value to break when reaching the next section.

The code for this is actually quite straightforward. I was so happy when I found out the meaning of these numbers stored at $037F! It’s actually a table, mapping the screen sections indices with a scanline.

Here is how the background is shifted and moved around when rendering a single frame of the Introduction sequence.

Link's Awakening Sea Sequence Differential scrolling

And here is how the differential scrolling looks in the game.

Link's Awakening Sea Sequence Background movement

Random rain

The last thing missing is the heavy rain pouring over the ship.

These are just three different sprites (long, short, thick) arranged in several horizontal sections, following randomly-chosen predefined patterns.

By the way, the random number generator of the game is quite simple, but does its job well. It’s a function of the global frame counter, the previously generated random number, and the current LY register value (the number of the scanline being rendered at this time). Random enough.

    ; Return a random number in `a`
    push hl
    ld   a, [hFrameCounter]
    ld   hl, WR0_RandomSeed
    add  a, [hl]
    ld   hl, rLY
    add  a, [hl]
    ld   [WR0_RandomSeed], a ; WR0_RandomSeed += FrameCounter + rrca(rLY)
    pop  hl

And finally, with the rain added, here is the Sea intro sequence at it looks like in the game!

Link's Awakening Sea Sequence Background movement

All these effects are not unique to Link’s Awakening: they are of course found in many other games as well. But this game shows a remarkable combination of technical and artistic skills, associated to create a great atmosphere.

For more details, you can browse the annotated assembly code for the LCD Status Interrupt, or the code for the Introduction sequence gameplay.

Athènes, premiers jours

Ménage à Notara

Cette scène de ménage se passe à Notara 26, un centre d’accueil à Athènes qui héberge gratuitement entre 100 et 200 exilés. Un beau projet qui tourne depuis un an, avec uniquement avec des volontaires bénévoles. (D’autres photos ici)

Il y a une semaine, pendant la nuit, un groupe d’assaillants a cassé une vitre extérieure, avant de jeter à l’intérieur des cocktails Molotov puis des bonbonnes de gaz, provoquant des explosions entendues dans tout le quartier.

Heureusement l’incendie a pu être éteint ; il n’y a pas de blessés, mais beaucoup de dégâts.

Incendie à Notara 26

Les attaques incendiaires contre des squats ne sont hélas pas rares à Athènes ; elles sont souvent liées à de membres du parti néo-nazi « Aube dorée » (comme cela semble avoir été le cas cette fois ci).

Comme je suis à Athènes en ce moment, je suis passé voir.

Depuis une semaine des volontaires se relaient pour tout remettre en état : réparer les murs, les portes, les vitres, nettoyer, ranger, repeindre. En espérant que les occupants, répartis dans d’autres lieux, puissent retrouver rapidement un hébergement.

Une salle après beaucoup de travaux et de rangement

Special effects in Link’s Awakening

This article is part of an ongoing “Disassembling Link’s Awakening” series, where I attempt to gain some understanding on how special effects where implemented in this game.

Zelda: Link’s Awakening (1993) is fondly remembered by many players. Whether you played the original black-and-white version or the color remake, you probably remember an oniric story, the whimsical characters, an immersive soundtrack… This is also the game where appeared many iconic elements of the Zelda series: playable tunes on music instruments, compass and boss keys in dungeons, and so on.

When I played this game again recently, I was surprised by the amount of custom gameplay behaviors, one-shot sequences, and graphical effects. The game engine is simple and robust – but on top of it there is a ton of custom coding.

For instance, Link can walk around the map with pixel-per-pixel moves (unlike Pokemon, which moves block-by-block).

Link's Awakening Sub-block physic engine

At some point, you get the Roc Feather, an item that opens a new mechanic: jumping over holes.

Link's Awakening Jumping with the Feather

Or catching items mid-air.

Link's Awakening Catching item mid-air

And also, when waking over a hole, it will attract you, but give you a chance to stand back over firm ground.

Link's Awakening Attracting hole

Later in the game, you can also fly over multiple holes. The physic engine also allows the player to swim, dive…

Link's Awakening Swim and dive

… or to switch from the standard top-down view to a sideway view — including during an epic boss-fight.

Link's Awakening side-scrolling

Some transitions attempt to simulate a 3D-effect (or at least some depth).

Link's Awakening Opening the Eagle Tower

Characters will sometimes follow you. For instance, a ghost.

Ghost following you

Or a dog, attached to you by a semi-translucent chain which moves realistically.

Link's Awakening Bow-wow with realistic chain

When powering-up the console, many Game Boy titles would jump you right to a title screen. Link’s Awakening does better, and open with a nice cinematic, packed with sprites and differential scrolling.

Link's Awakening Introduction Sequence

The game engine also has smooth screen transitions, like a fade-to-white between the interior or the exterior of a map…

Link's Awakening fade-to-white transition

… or even an eerie transition in the Dream House.

Link's Awakening Dream House transition

All these small touches to the physics engine and graphic visual effects seemed natural while playing the game – but it was actually quite amazing for a Game Boy game. Although not all of these effects present technical difficulties, the amount and the coordination of all this custom programming makes for a really immersive experience.

I was recently looking for a disassembly of Link’s Awakening source code, to see how some of the effects where implemented. And although Zelda: A Link to the Past on the Super NES has been mostly reverse-engineered, and Pokemon Red and Blue have been completely disassembled, there is no extensive disassembly of Link’s Awakening source code.

However an open-source project started poking into the game’s disassembly – and although it is still in early stage, it was a really good start.

So I started to look more into the source code, connecting a debugger to the game, setting breakpoints, and try to see how these things worked. Reverse-engineering assembly code is quite slow, but I’ll try to post some findings on this blog.

Category: Disassembling Link’s Awakening

These articles are part of a “Disassembling Link’s Awakening” series, where I attempt to gain some understanding on how special effects where implemented in this game.

  1. Introduction: Special Effects in Link’s Awakening
  2. Link’s Awakening: Rendering the Opening Cutscene