Provinciano Compresses Retro City Rampage to Run on Real 1989 NES

The Making of: ROM City Rampage (Retro City Rampage) — VblankEntertainment

VblankEntertainment

Rewriting the entire codebase in bare-metal assembly and aggressively compressing tile budgets proves open-world driving games could have functioned on original 1989 console hardware.

AI-assisted summary of The Making of: ROM City Rampage (Retro City Rampage) — original source. Check the original for full context.

Source published:

Key ideas

  • Brian Provinciano ported the core open-world mechanics of Retro City Rampage to execute natively on authentic NES hardware under the title ROM City Rampage. (0:08)
  • Adapting modern PC assets required crunching roughly 30,000 environmental tiles down to under 8,000, and compressing vehicle sprites through horizontal mirroring and lossy perceptual tile merging. (2:12)
  • Because modern C++ could not run on the 1.78 MHz 6502 processor, development was conducted in custom macro assembly paired with bank-switching across a 512 KB cartridge ROM. (4:26)
  • Screen updates were constrained by the console's VBlank window, limiting writes to one or two 32-byte tile rows per frame while hardware scroll registers created smooth scrolling. (5:47)
  • The entire 2.5-hour soundtrack was produced for the NES's five-channel audio architecture using tracker formats, consuming just 1.5 megabytes of total storage. (7:06)

Detailed notes

## Background Published on YouTube by VblankEntertainment on February 27, 2013, this video presentation breaks down the technical engineering behind *ROM City Rampage*. The video description explains how the core of *Retro City Rampage* was scaled down to run on genuine 8-bit NES hardware and illustrates how classic 8-bit games were built.

## TL;DR Developer Brian Provinciano details his journey converting *Retro City Rampage* into a fully functional 8-bit build capable of executing directly on original Nintendo Entertainment System hardware. Constrained by a 1.78 MHz 6502 CPU, 10 KB of RAM, and strict hardware tile and scanline limits, he had to discard high-level code, write a custom macro assembler, and heavily compress environmental and vehicle sprites. The postmortem details the mechanics of hardware tile scrolling during the vertical blanking interval, dynamic memory bank switching, and authentic 5-channel tracker audio composition. Ultimately, the project demonstrates that an open-world driving and shooting game could have legitimately run on a commercial game cartridge in 1989.

## Atmosphere & style The presentation is analytical, pragmatic, and quietly enthusiastic, unfolding like a masterclass in vintage console architecture from a solitary engineering artisan. Provinciano speaks with clear, unpretentious authority, stripping away modern misconceptions about retro aesthetics to reveal the ruthless physical realities of early computing. Watching it feels like peering over a programmer's shoulder into memory maps and assembly routines, capturing the satisfying, puzzle-like joy of squeezing complex gameplay into microscopic hardware limits.

## Bulletin - [00:08](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=8s) Brian Provinciano ported the core open-world mechanics of Retro City Rampage to execute natively on authentic NES hardware under the title ROM City Rampage. - [02:12](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=132s) Adapting modern PC assets required crunching roughly 30,000 environmental tiles down to under 8,000, and compressing vehicle sprites through horizontal mirroring and lossy perceptual tile merging. - [04:26](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=266s) Because modern C++ could not run on the 1.78 MHz 6502 processor, development was conducted in custom macro assembly paired with bank-switching across a 512 KB cartridge ROM. - [05:47](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=347s) Screen updates were constrained by the console's VBlank window, limiting writes to one or two 32-byte tile rows per frame while hardware scroll registers created smooth scrolling. - [07:06](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=426s) The entire 2.5-hour soundtrack was produced for the NES's five-channel audio architecture using tracker formats, consuming just 1.5 megabytes of total storage.

## Key takeaways - [00:08](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=8s) The NES target architecture operates on a Ricoh 2A03 / MOS 6502 8-bit CPU clocked at 1.78 MHz with just 10 KB of total RAM. - [00:08](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=8s) The term '8-bit' historically refers to processor architecture rather than color depth, as the NES displays only up to 13 colors on-screen simultaneously from 2-bit-per-pixel tiles. - [02:12](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=132s) Environmental tiles were reduced from approximately 30,000 to below 8,000 by stripping decorative geometry, bespoke storefronts, and multi-tile sidewalk patterns. - [02:12](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=132s) Pedestrian walking animations were compressed from 16 angles to nine via horizontal hardware flipping, and head variations were restricted to eight cardinal directions. - [02:12](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=132s) Car sprite requirements were reduced below the 128-tile hardware limit using symmetry and an automated algorithm merging tiles with at least 58 matching pixels out of 64. - [02:12](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=132s) NES scanlines drop rendering beyond eight sprites, necessitating frame-by-frame sprite slot cycling to trigger controlled flicker rather than full object disappearance. - [04:26](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=266s) None of the high-level C++ code from Retro City Rampage could be reused, requiring bare-metal 6502 assembly authored via a custom high-level macro assembler. - [04:26](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=266s) A 512 KB program ROM was mapped into the CPU's fixed 32 KB address space by partitioning code across dynamically swapped 8 KB banks. - [05:47](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=347s) VRAM is locked during active raster beam drawing, leaving only the brief VBlank interval to transfer video data and write tile updates. - [05:47](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=347s) Because VBlank only allows updating 1–2 tile rows per frame, historical 8-bit game design heavily favored side-scrollers that stream data at display edges. - [07:06](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=426s) Debugging was achieved by modifying a custom emulator to read assembler-generated symbol maps for real-time variable watch and collision overlay rendering. - [07:06](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=426s) Audio was composed in ModPlug Tracker for the NES's five native sound channels: two pulse waves, one triangle wave, one noise channel, and one 1-bit DPCM channel. - [07:06](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=426s) Tracker compositions had to synchronize tempos perfectly with 50 Hz or 60 Hz frame loops to prevent vibrato and pitch sweeps from detuning. - [07:06](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=426s) Adhering to hardware tracker music compressed over two and a half hours of music into 1.5 MB, helping keep the Nintendo Wii build of Retro City Rampage down to 10 MB. - [09:30](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=570s) The project serves as proof that open-world driving and shooting action could technically run within the authentic physical constraints of a 1989 NES cartridge.

## Detailed walkthrough ### [00:08](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=8s) Origins of ROM City Rampage and the 8-Bit Reality

Before creating *Retro City Rampage*, developer Brian Provinciano was building a genuine 8-bit game engineered to execute directly on original hardware. Over time, the friction of fighting severe system boundaries pulled his attention away from gameplay design, leading him to put the project on ice in order to focus purely on making the richest game possible. Brian Provinciano recalled the pivot: “My focus shifted though as I became less interested in battling the hardware limitations and more in creating the best possible game so I shelved it and started working on RCR.” Once *Retro City Rampage* was shipped and completed, he returned to the dormant codebase to demonstrate exactly what late-1980s console architecture could achieve when pushed to its limits.

The target environment is built around the Ricoh 2A03 / MOS Technology 6502 8-bit processor clocked at 1.78 MHz, the same underlying CPU family found in the Commodore 64, Apple II, and Nintendo Entertainment System. The physical memory boundaries are tight: 10 kilobytes of total system RAM, comprising a 2 KB base supplemented by 8 KB of extended work RAM. Only 32 KB of program ROM can be mapped into active memory at any single moment for code and static data, paired with 4 KB of active sprite graphics ROM. Through cartridge mapper hardware, the project leverages a 256 KB background graphics ROM.

To cope with microscopic memory capacities and cycle budgets, the console uses hardware tile mapping instead of flat framebuffers. Visual scenes are decomposed into grids of 8x8 pixel tiles, and any redundant copies are stripped out of storage. Background visuals can show 13 colors on-screen at once, but tiles are restricted to 2 bits per pixel, meaning an individual tile can only reference four colors. Four distinct palettes are available, each containing three selectable shades alongside a single unified background color. Addressing a common retro gaming misconception, Brian Provinciano explained: “Note that when a game is labeled as 8-bit, it's referring to the CPU.” True 8-bit color depth yields 256 simultaneous colors, an advancement that did not become mainstream until 16-bit consoles and PC VGA graphics arrived.

- **CPU:** 6502 8-bit processor running at 1.78 MHz. - **System Memory:** 10 KB RAM total (2 KB internal base RAM + 8 KB extended RAM). - **ROM Windows:** 32 KB active program ROM window; 4 KB active sprite pattern table. - **Cartridge ROM:** 256 KB background pattern ROM enabled by cartridge banking. - **Tile Architecture:** 8x8 pixel blocks at 2 bits per pixel (4 colors per tile out of 4 selectable palettes sharing 1 common color).

---

[02:12](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=132s) Tile Crunching: Environments, Pedestrians, and Vehicles

Porting the open world of *Retro City Rampage* into NES hardware demanded an aggressive asset diet. The modern game world relied on roughly 30,000 distinct tiles, but the 8-bit target hardware required keeping that budget strictly below 8,000. To clear that threshold, unique single-use tiles like bespoke storefront lettering, decorative statues, and varied foliage were eliminated first. Street geometry had to be normalized; instead of the multi-tile decorative sidewalk paving in the original game, sidewalks were simplified into a single repeating tile. Dynamic environmental props were also removed because the sprite hardware lacked the capacity to display them.

Sprite budgets required equally ruthless compression. For pedestrian characters, 64 tiles were allocated to accommodate seven archetypes walking in 16 directions across a three-frame animation cycle. Because the PPU allows horizontal hardware flipping, walking left and walking right can share identical tile data, shrinking the 16 directional sets down to nine. The North and South walking loops were trimmed from three frames down to two using mirroring tricks. Furthermore, rather than rendering distinct angled head angles for all 16 movement angles, head graphics were only created for the primary eight directions, compressing the nine sets down to five.

Vehicles were even more challenging: each car measures 24x24 pixels (a 3x3 grid of 8x8 tiles) and rotates through 16 driving angles. Factoring in a civilian vehicle and two variations of police cars, a naive implementation required 288 tiles, far surpassing the hard ceiling of 128 tiles. Horizontal mirroring shaved the 16 angles down to nine, dropping the requirement to 162 tiles, and trimming tiles from non-diagonal orientations brought it to 144. To conquer the remaining overrun, an automated perceptual similarity algorithm was implemented: if two 64-pixel tiles shared at least 58 identical pixels, they were collapsed into a single tile. This reduced individual 24x24 car angles from nine unique tiles down to seven. Furthermore, the notorious NES sprite flicker is explained: the PPU can track 64 sprites overall, but can only draw eight per horizontal scanline. Because each car is three sprites wide, placing more than two vehicles on the same horizontal plane exceeds the scanline limit. The console simply drops rendering on the ninth sprite, requiring the game engine's software code to manually cycle sprite draw orders between frames to generate an alternating flicker rather than letting objects disappear completely.

```mermaid flowchart TD accTitle: Vehicle Tile Compression Flow accDescr: Pipeline showing how car sprite tiles are compressed from 288 down to fit under the 128 tile hardware budget.

subgraph Mirroring["Directional Reduction"] A["Raw 16-Angle Cars<br/>288 Tiles"] -->|"Mirror 16 directions to 9"| B["Mirrored Orientations<br/>162 Tiles"] B -->|"Trim non-diagonal tiles"| C["Cardinal Optimization<br/>144 Tiles"] end

subgraph Similarity["Pixel Merging"] C -->|"Compare 8x8 tiles<br/>(Match >= 58/64 px)"| D["Perceptual Tile Merging<br/>7 tiles per car instead of 9"] D --> E["Final Asset Set<br/>Under 128 Tile Limit"] end ```

- **Environment Tile Reduction:** Slashed from ~30,000 tiles to under 8,000 tiles. - **Pedestrian Sprite Savings:** 16 walk directions compressed to nine via horizontal flipping; North/South walk animations cut to two frames; head rotations restricted to eight primary directions, reducing nine animation sets to five. - **Car Sprite Budget:** 24x24 pixels (3x3 tiles per frame) across two police cars and standard cars dropped from 288 to 144 tiles via directional symmetry, then below 128 tiles using lossy tile merging (treating tiles matching 58 of 64 pixels as identical). - **Scanline Constraint:** Maximum 8 hardware sprites per horizontal scanline; 3-tile-wide vehicles cause dropout if more than two cars align horizontally, requiring game code to rotate sprite slots each frame.

---

[04:26](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=266s) Bare-Metal Assembly, Custom Tooling, and Bank Switching

Standard modern development practices could not bridge the gap to vintage hardware. Brian Provinciano emphasized the absolute break from the PC codebase: “With its 1.78 MHz CPU, high-level languages such as C++ are out of the question; not a single line of code from RCR could be used.” Developers working on the 6502 must program directly in bare-metal assembly. Rather than writing raw, unadorned machine instructions, he engineered an open-source high-level macro assembler that combined the raw execution speed of hand-coded assembly with syntactic abstractions familiar from C.

This proprietary assembler introduced structured control flow constructs, cleaner loop implementations, preprocessor directives, structs, and switch-case syntax. Behind the scenes, these macros expanded into optimal assembly instructions, preserving cycle-level performance while drastically accelerating development.

The architecture also presented major memory management hurdles. The cartridge contained 512 KB of total program ROM, but the 6502 memory map only exposes a 32 KB window partitioned into four 8 KB slots. Accessing the broader library of routines and game data requires swapping 8 KB banks dynamically in and out of those active slots. Whenever routine code or data arrays exceeded a bank’s 8 KB limit, segments had to be split across boundaries. This introduced runtime overhead, as functions had to bank-switch target data into an active window and swap the previous bank back upon completion.

---

[05:47](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=347s) The Vertical Blanking Interval and Hardware Tile Scrolling

Console rendering on classic CRT televisions operates on rigid timing constraints tied to the regional AC power grid, running at either 60 Hz (NTSC) or 50 Hz (PAL). During the majority of each frame, the electron beam is actively drawing the raster image pixel by pixel from top to bottom. The Picture Processing Unit (PPU) locks its internal VRAM bus during active scanline rendering. The only opportunity for the CPU to push new graphical data to video memory occurs during the vertical blanking interval—the brief window when the electron beam turns off and repositions from the bottom-right corner back to the top-left of the display.

Because the system possesses neither the raw clock cycles nor the memory bandwidth to recalculate screen buffers on a per-pixel basis, it relies on tilemaps. The full 256x240 pixel canvas is mapped into a grid of 32x30 bytes representing 8x8 character tiles. Even so, the VBlank duration is so constrained that the CPU cannot write an entire 960-byte frame during a single interval. Instead, the engine can only transfer a couple of tile rows or columns while the beam resets. Brian Provinciano observed how this hardware reality directed the history of game design: “Instead, you were mostly limited to just a couple of rows at a time, but this was perfect for the popular side-scrollers of the day, making them no coincidence.”

By writing a single 32-byte row into video memory during VBlank, the processor updates 256 horizontal pixels. The engine continuously pans the hardware scroll registers up and down. As the camera traverses the world, the tilemap wraps seamlessly across hardware nametables, generating the illusion of an infinite scrolling landscape out of minimal byte transfers.

```mermaid flowchart LR accTitle: NES Frame Timing and VBlank Execution Loop accDescr: Visual flow showing active CRT raster scanning followed by the narrow VBlank window where video memory writes occur.

subgraph ActiveRaster["Active Screen Draw (Majority of Frame)"] A["Electron Beam Draws Screen<br/>Top to Bottom (256x240 px)"] --> B["VRAM Bus Locked<br/>Game Logic & Physics Update"] end

subgraph VBlank["VBlank Interval (Beam Repositioning)"] B --> C["Beam Reaches Bottom<br/>VBlank NMI Fires"] C --> D["Write 1-2 Tile Rows (32 Bytes/Row)<br/>Update Sprite OAM & Scroll Registers"] D --> E["Beam Resets to Top-Left"] end

E --> A ```

- **Frame Rates:** 60 Hz (NTSC) or 50 Hz (PAL). - **VRAM Screen Matrix:** 256x240 pixels governed by 32x30 tile indices (960 bytes). - **VBlank Throughput:** Restricted to updating roughly one or two 32-byte rows per blanking period, rendering 256 screen pixels per row write. - **Scroll Mechanism:** Hardware scroll registers offset the display coordinate across wrapping nametables while incoming map boundaries stream in at the edges.

---

[07:06](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=426s) Emulation Debugging Workarounds and Authentic 5-Channel Audio

Debugging bare-metal NES software poses severe practical hurdles: the hardware provides no native watch windows, source-level debuggers, debug visualization hooks, or even basic `printf` text streaming. Rather than spending months constructing a ground-up development environment, Brian Provinciano repurposed tools he had already developed: “Writing a full emulator and IDE with all of these features would have taken a fair bit of time, so I took a shortcut.” His custom assembler generated memory map files detailing the precise locations of variables, structs, and arrays. He modified his custom emulator to parse these map files at runtime, presenting real-time variable inspections, injecting function hooks, and rendering graphical collision boundaries directly on top of the emulation layer.

Audio development maintained strict adherence to the NES’s Ricoh audio processing unit specifications, which provides five distinct sound channels: - Two pulse/square wave channels for melodies and harmonies - One triangle wave channel primarily utilized for bass lines - One white noise channel for percussive hits - One 1-bit delta pulse-code modulation (DPCM) channel for playback of compressed digital samples

The soundtrack was composed within ModPlug Tracker using the standard Impulse Tracker (`.it`) format, and then converted to play on real hardware via the `IT2NSF` utility. The primary technical hurdle stemmed from song tempos; if tracker tempos failed to divide evenly into the console's 50 Hz or 60 Hz update loop, pitch sweeps and vibrato modulations sounded noticeably off-key.

While the source audio was composed to strictly authentic specs, the runtime engine in *Retro City Rampage* took liberties with channel allocation. Real NES software had to constantly make trade-offs: either sound effects had to temporarily silence an active music channel, or specific channels had to be hard-reserved (such as dedicating triangle and noise channels exclusively to sound effects while leaving the square waves for melody). The PC release circumvented these drops by allowing dynamic fading and multi-channel sound effect playback. Sticking to authentic hardware-targeted tracker music also offered an unexpected file size advantage: over two and a half hours of soundtrack was compressed into a minuscule 1.5 megabytes of tracker data, enabling the entire Nintendo Wii release of *Retro City Rampage* to weigh in at just 10 megabytes.

---

[09:30](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=570s) Engine Optimization, Structural Geometry, and the 1989 Baseline

Reflecting on the code, Brian Provinciano noted that most of the 8-bit codebase was written a decade prior. Rebuilding the architecture from scratch with modern insights would yield far more efficient subroutines and potentially double the runtime frame rate. On vintage hardware, structural design choices directly dictate engine stability; altering the on-screen size of dynamic game objects alone can easily determine whether the renderer sustains 60 frames per second or collapses to 30. He compared the mental challenge of fitting code, bank routines, and pixel art into microscopic limits to classic spatial puzzles: “And while it can get very complicated, it's also very fun figuring out how to make everything fit just right, not unlike a game of Tetris.”

The resulting build, titled *ROM City Rampage*, runs entirely within the operational capabilities of authentic hardware. Side-by-side comparisons demonstrate that while the 8-bit version is visibly stripped of modern lighting, complex pedestrian varieties, and fine decorative map props, its open-world urban driving and shooting core remains intact. The finished project stands as a working proof-of-concept that the underlying game could have physically shipped on an NES cartridge in 1989.

## Notable quotes > [00:08](https://www.youtube.com/watch?v=Hvx4xXhZMrU&t=8s) Note that when a game is labeled as 8-bit, it's referring to the CPU. — Brian Provinciano

## Mentioned Brian Provinciano, Retro City Rampage, ROM City Rampage, Ricoh 2A03, MOS Technology 6502, Commodore 64, Apple II, Nintendo Entertainment System, Picture Processing Unit (PPU), ModPlug Tracker, IT2NSF, Nintendo Wii

## Video description How Retro City Rampage's core was crunched down to a REAL 8-BIT game and how 8-BIT games are made. TWITTER: @BriProv / @RetroCR - https://vblank.com

[Source](https://www.youtube.com/watch?v=Hvx4xXhZMrU)

中文简报

Provinciano将《荒野老城》压缩至可在1989年原版NES上运行 完全用裸机汇编重写代码库并极限压缩图块预算,证明了开放世界驾驶游戏原本可以在1989年的原始主机硬件上运行。 开发者Brian Provinciano详细阐述了他将《荒野老城》(Retro City Rampage)转化为可直接在原版任天堂红白机(NES)硬件上运行的全功能8位版本的历程。受限于1.78 MHz的6502 CPU、10 KB RAM以及严苛的硬件图块和扫描线限制,他不得不舍弃高级语言代码,编写了一套自定义宏汇编器,并对环境与载具精灵进行了深度压缩。这篇复盘详细剖析了在垂直消隐期间进行硬件图块滚动、动态内存换页以及原汁原味的5通道Tracker音频合成的机制。该项目最终证明,开放世界驾驶与射击游戏完全有可能在1989年的商业游戏卡带上切实运行。 Brian Provinciano以《ROM City Rampage》为名,将《荒野老城》的核心开放世界机制移植至原版NES硬件上原生运行。 (0:08) 适配现代PC资源需要将约30,000个环境图块压缩至8,000个以下,并通过水平镜像和有损感知图块合并来压缩载具精灵。 (2:12) 由于现代C++无法在1.78 MHz的6502处理器上运行,开发工作是在自定义宏汇编中进行的,并在512 KB卡带ROM中配合使用了内存换页技术。 (4:26) 屏幕更新受限于主机的VBlank窗口,将每帧的写入限制在一到两个32字节的图块行,同时利用硬件滚动寄存器实现平滑滚动。 (5:47) 整部2.5小时的原声带采用Tracker格式针对NES的5通道音频架构制作,总存储占用仅为1.5兆字节。 (7:06)

Source quotes

[0:08] Brian Provinciano: Note that when a game is labeled as 8-bit, it's referring to the CPU.

Original transcript

[0:08] before Retro City Rampage I was [0:09] developing another game a real 8bit game [0:12] which ran on the real thing my focus [0:14] shifted though as I became less [0:16] interested in battling the hardware [0:17] limitations and More in creating the [0:19] best possible game so I shelved it and [0:21] started working on RCR however after [0:24] completing that I decided to dig it up [0:26] again and now you'll be able to see what [0:28] really was possible in the 8s and how a [0:30] real 8bit game is [0:32] [Music] [0:45] made so what are we dealing with here [0:48] the 6502 8bit CPU running at 1.78 mahz [0:53] this was used in the Apple 2 The [0:55] Commodore 64 and of course the NES [1:00] 10 kilobytes of ram a 2K base with 8K [1:03] extended 32k of program ROM at a time [1:06] for both code and data 4K of sprite [1:09] Graphics ROM at a time and a whopping [1:12] 256k of background Graphics ROM thanks [1:15] to the cartridge [1:17] Hardware to make the most of the [1:19] system's limited memory and speed tile [1:22] based Graphics are used images are [1:24] broken up into 8x8 pixel tiles and [1:27] duplicates are discarded as a result the [1:30] required Ramen Ram size is much smaller [1:33] the background can use up to 13 colors [1:35] at once but being only two bits per [1:38] pixel the tiles are actually just four [1:40] colors this is where the pallette comes [1:42] in while each 8 by8 tile can only use [1:45] four different colors which four colors [1:47] it uses can be selected from up to four [1:50] palletes each palette has three unique [1:53] colors and a shared background [1:56] color note that when a game is labeled [1:58] as 8bit it's refer refering to the CPU [2:01] 8bit systems generally only supported [2:03] 2bit or 4bit color 8bit color was [2:06] something of the 16bit and VGA era and [2:09] actually gives you a whopping 256 [2:12] colors the world in RCR used nearly [2:15] 30,000 tiles but this needed to be under [2:17] 8,000 I could either heavily simplify [2:20] the graphics or reduce the size of the [2:22] world and so that's what I [2:23] did the easiest tiles to cut are those [2:26] which are only used once for example [2:28] store signs statues or for foliage there [2:30] also weren't enough Sprites for the [2:32] dynamic props and finally I had to [2:35] simplify the sidewalk pattern to repeat [2:37] a single tile instead of multiple [2:40] ones it finally fit and despite the cuts [2:43] the majority of the detail Still [2:49] Remains I allocated 64 tiles for the [2:52] character sprites this gave me a [2:54] three-frame walk cycle of 16 directions [2:57] and seven different character types [2:59] because you can mirror Sprites you can [3:00] reuse the same tile for walking left as [3:02] walking right so you can get 16 [3:05] directions down into just nine [3:07] sets to Crunch further the North and [3:10] South walk Cycles normally three frames [3:12] could be done with just two also using [3:14] mirroring and while the Sprites could [3:16] move in 16 directions if I stored heads [3:18] only for the primary eight those nine [3:20] sets crunch down to [3:25] five each car is 24x 24 pixels and can [3:28] drive in 16 directions we also need two [3:31] types of helis car and a normal one [3:33] calculated that adds up to 288 tiles [3:36] over twice the limit of 128 mirroring [3:39] the 16 directions to 9 brings it down to [3:41] 162 and ensuring non-diagonal directions [3:43] use less tiles brings us down to 144 but [3:46] we're still over so to Crunch things [3:48] further we need to do more than just [3:50] combine duplicate tiles we need to [3:52] combine similar ones as well in this [3:55] example the Sprite now uses seven unique [3:57] tiles instead of nine each 8 by8 tile is [4:00] 64 pixels and if six of those pixels [4:03] match they're treated as [4:05] duplicates you surely remember the [4:07] Sprite flickering but you might not know [4:09] why it happened well there were 64 [4:11] Sprites available but only a maximum of [4:13] eight per line with cars being three [4:15] Sprites wide more than two results in [4:18] flicker interestingly the game's code [4:21] did the flickering manually the system [4:23] itself just stops rendering after the [4:25] eth with its 1.78 MHz CPU highight level [4:30] languages such as C++ are out of the [4:32] question not a single line of code from [4:34] RCR could be used instead you're down to [4:36] the metal with Assembly Language [4:38] unsatisfied I wrote a high level [4:40] assembler to give me the benefits of [4:42] Both Worlds and also started writing [4:44] macros macros simplify your code [4:46] enabling you to represent multiple lines [4:48] with just one you retain the performance [4:51] of Assembly Language while gaining a [4:53] syntax closer to C I also added many [4:56] other C- like elements to the assembler [4:58] making if statements and loops cleaner [5:00] adding strs adding switch and case and [5:02] familiar pre-processor directives this [5:04] all saved me a huge amount of time note [5:07] that I actually released the assembler [5:09] open source many years ago so if you [5:11] want to Tinker with it go right [5:12] ahead how the code is accessed adds [5:15] another challenge you have 32 Koby of [5:18] program ROM but it's split up into four [5:20] slots 8K each the total ROM size is 512k [5:25] but you can only access it 8K at a time [5:27] by swapping bits and pieces of it in and [5:29] out of these four slots The Limited [5:32] memory adds to the complexity as you'll [5:34] often exceed A banks 8K you'll then need [5:37] to move code or data from one bank to [5:39] another and this slows things down [5:41] because you'll then need to swap its [5:42] Bank in and then out every time you [5:44] access [5:47] it meet the vertical blank or the V [5:51] blank depending on where in the world [5:53] you were located your game would run at [5:55] either 50 or 60 frames per second each [5:58] frame contained two key States [6:00] the first and majority of the frame time [6:02] was spent while the TV was drawing the [6:03] picture pixel by pixel it draws from top [6:06] to bottom once it reaches the end the [6:08] beam moves back up to the top to draw [6:10] the next frame on systems such as the [6:12] NES only during this short period at the [6:15] end of the frame could you change the [6:17] graphics there wasn't enough processing [6:19] power or system memory to draw the [6:21] entire screen pixel by pixel however [6:24] thanks to the 8x8 pixel tiles the entire [6:27] 256x 240 pixel screen was drawn with [6:30] just 32x 30 bytes however it wasn't [6:33] powerful enough to even write that many [6:35] bytes at the end of each frame instead [6:37] you were mostly limited to just a couple [6:38] of rows at a time but this was perfect [6:41] for the popular side scrollers of the [6:43] day making them no coincidence and still [6:46] you got quite a bang for your buck with [6:48] a small 32 by right you were drawing 248 [6:52] pixels this is the screen scrolling as [6:54] you see it and this is what's really [6:57] happening as we write one row at a time [7:00] we Pan the scroll register up and down [7:02] and it loops around displaying as a [7:04] moving Playfield one major programming [7:07] challenge was the lack of a debugger [7:09] there's no Source level debugging no [7:11] watch window no debug renderer not even [7:13] printfs writing a full emulator and IDE [7:16] with all of these features would have [7:17] taken a fair bit of time so I took a [7:19] shortcut I had already written an [7:21] emulator and the assembler exported map [7:24] files which show the location and memory [7:26] of code and data so in my emulator I [7:29] wrote wrote functions to pull this out [7:31] and as the game runs display it the [7:33] variables arrays and structs this [7:36] effectively gave me a watch window and [7:38] the ability to render debug shapes I [7:41] could also hook into functions and [7:42] analyze the game at specific [7:46] points while I never got around to [7:48] adding music playback to the 8bit [7:50] version RCR boasts over 2 and 1 half [7:52] hours of authentic music the music and [7:54] sound effects for RCR were composed in [7:56] impulse tracker format using the free [7:58] tool model plug tracker these can be [8:01] automatically converted to runon [8:03] Hardware using the tool it to [8:05] NSF the only real potential hiccup comes [8:08] from the various tempos used by the [8:10] music to create our widely varied [8:12] soundtrack if the tempo doesn't nicely [8:14] match up to the system's frame rate [8:16] certain modulated effects could sound [8:18] incorrect [8:22] [Music] [8:29] everything was composed to the accurate [8:31] specs with two pulse waves a triangle a [8:34] noise and one bit dpcm for samples the [8:37] only place where the specs were bent is [8:39] in the playback for a better overall [8:41] experience RCR allows for smoother Fades [8:44] and simultaneous playback of multiple [8:46] sounds on a real NES either sounds would [8:49] need to drop for others to play or [8:51] certain channels would need to be [8:52] reserved for each purpose for example [8:55] the sound effects might use the triangle [8:56] and noise channels and the music would [8:58] use the square and [9:07] [Music] [9:19] [Music] [9:20] dpcm chip Tunes are also why the Wii [9:23] version of RCR is only 10 megabytes 2 [9:25] and 1/2 hours of music crams down into [9:27] just 1 and 1/2 Megs [9:31] I wrote most of this 8bit code 10 years [9:33] ago if I were to write it again today [9:35] from scratch I would be able to better [9:37] design the engine and likely double the [9:39] frame rate however this still gives you [9:41] a good idea of what was possible back [9:43] then to completely tap into the system [9:46] everything must be designed in the most [9:47] optimized way the size of objects alone [9:50] for example could mean the difference [9:51] between 30 and 60 frames per second and [9:55] while it can get very complicated it's [9:56] also very fun figuring out how to make [9:58] everything fit just right not unlike a [10:01] game of [10:05] Tetris with all that taken care of the [10:07] game is finally running you can see side [10:10] by side how it compares to RCR much less [10:13] detailed but still impressive especially [10:15] when you realize that it could have [10:17] actually been released in 1989 [10:22] [Music] [10:29] oh [10:31] [Music]