Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Game Development in Eight Bits

Game Development in Eight Bits

Presented at Beer City Code (Grand Rapids, MI, June 1, 2019).

Kevin Zurawel

June 01, 2019
Tweet

More Decks by Kevin Zurawel

Other Decks in Technology

Transcript

  1. NES TECH SPECS ➤ MOS Technologies 6502 CPU (1.79MHz) ➤

    Custom Ricoh “Picture Processing Unit”
 (256x240 resolution, 64 colors) ➤ Custom Ricoh “Audio Processing Unit”
 embedded in CPU (five tone generators)
  2. NES TECH SPECS ➤ 2 KB work RAM +
 2KB

    video RAM ➤ No permanent storage ➤ Read-only cartridges;
 32KB code, 8KB graphics data
  3. Number of bits Possible values 1 2 2 4 3

    8 4 16 5 32 6 64 7 128 8 256
  4. 256 pixels wide
 × 240 pixels tall 61,440 pixels
 per

    screen ÷ 4 pixels per byte 15 KB
 per screen
  5. 256 pixels wide
 × 240 pixels tall 61,440 pixels
 per

    screen ÷ 4 pixels per byte 15 KB
 per screen (!!!)
  6. BACKGROUNDS 32 x 30 grid of tiles 8x8 pixels per

    tile 960 tiles per screen 1 byte per tile
  7. BACKGROUNDS 32 x 30 grid of tiles 8x8 pixels per

    tile 960 tiles per screen 1 byte per tile 960 bytes
 per screen
  8. SPRITES 256 bytes of sprite RAM
 ÷ 4 bytes per

    sprite 
 (tile #, x/y, palette #) 64 sprites at a time
  9. PROBLEM #2 How do you show a lot of action


    with only 8 sprites per line?
  10. 14 screens of graphics
 × 960 bytes per screen ~13

    KB graphics data … for World 1-1 alone
  11. 2. MAKE USE OF REPEATED META-OBJECTS Instead of 24 tiles,

    store “pipe, height 6” and write code that draws pipes
  12. 3. USE BASIC COMPRESSION (RUN-LENGTH ENCODING) Instead of storing 96

    tiles, store “brick tile repeats 32 times” for three rows
  13. { {

  14. ;level 1–1 
 L_GroundArea6: .db $50, $21
 .db $07, $81,

    $47, $24, $57, $00, $63, $01, $77, $01
 .db $c9, $71, $68, $f2, $e7, $73, $97, $fb, $06, $83 
 .db $5c, $01, $d7, $22, $e7, $00, $03, $a7, $6c, $02 
 .db $b3, $22, $e3, $01, $e7, $07, $47, $a0, $57, $06 
 .db $a7, $01, $d3, $00, $d7, $01, $07, $81, $67, $20 
 .db $93, $22, $03, $a3, $1c, $61, $17, $21, $6f, $33 
 .db $c7, $63, $d8, $62, $e9, $61, $fa, $60, $4f, $b3 
 .db $87, $63, $9c, $01, $b7, $63, $c8, $62, $d9, $61 
 .db $ea, $60, $39, $f1, $87, $21, $a7, $01, $b7, $20 
 .db $39, $f1, $5f, $38, $6d, $c1, $af, $26
 .db $fd World 1-1… in 101 bytes! "I AM ERROR", p.131
  15. ;level 1–1 
 L_GroundArea6: .db $50, $21
 .db $07, $81,

    $47, $24, $57, $00, $63, $01, $77, $01
 .db $c9, $71, $68, $f2, $e7, $73, $97, $fb, $06, $83 
 .db $5c, $01, $d7, $22, $e7, $00, $03, $a7, $6c, $02 
 .db $b3, $22, $e3, $01, $e7, $07, $47, $a0, $57, $06 
 .db $a7, $01, $d3, $00, $d7, $01, $07, $81, $67, $20 
 .db $93, $22, $03, $a3, $1c, $61, $17, $21, $6f, $33 
 .db $c7, $63, $d8, $62, $e9, $61, $fa, $60, $4f, $b3 
 .db $87, $63, $9c, $01, $b7, $63, $c8, $62, $d9, $61 
 .db $ea, $60, $39, $f1, $87, $21, $a7, $01, $b7, $20 
 .db $39, $f1, $5f, $38, $6d, $c1, $af, $26
 .db $fd World 1-1… in 101 bytes! Header Footer "I AM ERROR", p.131
  16. ;level 1–1 
 L_GroundArea6: .db $50, $21
 .db $07, $81,

    $47, $24, $57, $00, $63, $01, $77, $01
 .db $c9, $71, $68, $f2, $e7, $73, $97, $fb, $06, $83 
 .db $5c, $01, $d7, $22, $e7, $00, $03, $a7, $6c, $02 
 .db $b3, $22, $e3, $01, $e7, $07, $47, $a0, $57, $06 
 .db $a7, $01, $d3, $00, $d7, $01, $07, $81, $67, $20 
 .db $93, $22, $03, $a3, $1c, $61, $17, $21, $6f, $33 
 .db $c7, $63, $d8, $62, $e9, $61, $fa, $60, $4f, $b3 
 .db $87, $63, $9c, $01, $b7, $63, $c8, $62, $d9, $61 
 .db $ea, $60, $39, $f1, $87, $21, $a7, $01, $b7, $20 
 .db $39, $f1, $5f, $38, $6d, $c1, $af, $26
 .db $fd World 1-1… in 101 bytes! Header Footer Byte pairs (screen location, metatile) "I AM ERROR", p.131
  17. Byte pair Column/ Row Description $07, $81 0, 7 (start

    new screen) 
 "?" block w/ coin $47, $24 4, 7 row of bricks, length 4 $57, $00 5, 7 "?" block 
 w/ power-up item $63, $01 6, 3 "?" block w/ coin "I AM ERROR", p.133
  18. “RANDOM” LEVEL GENERATION Use a random number generator algorithm with

    a fixed seed value
 to generate a predictable
 (and reversible!) stream of bytes Algorithm + seed: 50 bytes
  19. THE “STANDARD” 2D JUMP ALGORITHM Height at time t =

    
 vertical velocity + (acceleration from gravity2 / 2)
  20. MATH ON THE 6502 CPU ADC SBC ASL LSR Add

    (with Carry)
 Subtract (with Carry)
 Arithmetic Shift Left
 (“multiply by 2”) Logical Shift Right
 (“divide by 2”)
  21. SOLUTION: DON’T USE PHYSICS ➤ When player presses jump button,


    check if player is on the ground ➤ If yes, move player up n pixels per frame ➤ Stop moving up when default jump height reached ➤ Then, move player down n pixels per frame ➤ Check for collision with the ground
  22. SUB-PIXEL POSITIONING (“8.8 FIXED-POINT” FORMAT) Represent sprite positions with two

    bytes ➤ Actual pixel position on screen (0-255) ➤ Fraction of a pixel offset (0-255) Two bytes for X, two bytes for Y
 Calculate X and Y movement separately
  23. if (on_ground) { if (button_a) velocity_y = -500; // jump

    if (dpad_left) velocity_x -= 5; // accelerate left if (dpad_right) velocity_x += 5; // accelerate right } position_x += velocity_x; resolve_horizontal_collision(); position_y += velocity_y; resolve_vertical_collision(); velocity_y += 10; // apply gravity http://forums.nesdev.com/viewtopic.php?f=2&t=12434
  24. THE TETRIS SOLUTION: DO IT WITH MATH 16-bit Fibonacci linear

    feedback shift register 
 (LFSR) (XOR bits 1 and 9, store in bit 16, shift right) https://meatfighter.com/nintendotetrisai/#Picking_Tetriminos
  25. THE FINAL FANTASY SOLUTION: USE A LOOKUP TABLE AE D0

    38 8A ED 60 DB 72 5C 59 27 D8 0A 4A F4 34 08 A9 C3 96 56 3B F1 55 F8 6B 31 EF 6D 28 AC 41 68 1E 2A C1 E5 8F 50 F5 3E 7B B7 4C 14 39 12 CD B2 62 8B 82 3C BA 63 85 3A 17 B8 2E B5 BE 20 CB 46 51 2C CF 03 78 53 97 06 69 EB 77 86 E6 EA 74 0C 21 E2 40 D4 5A 3D C7 2B 94 D5 8C 44 FD EE D2 43 00 BB FA C6 1D 98 A0 D3 54 5F 5E DC A8 00 AF 93 A1 E1 6C 04 DE B6 D7 36 16 C5 C8 C4 E4 0F 02 AB E8 33 99 73 11 6A 09 67 F3 FF A2 DF 32 0E 1F 0D 90 25 64 75 B3 65 2F C9 B0 DA 5D 9F EC 29 CE E3 F0 91 7A 58 45 24 1C 47 A4 89 18 2D CC BD 6F 80 F6 81 22 E9 07 70 FB DD AD 35 A6 61 B4 A3 FE B1 30 4B 15 48 6E 4F 5B 13 9C 83 92 01 C2 19 7F 1A 1B 71 B9 3F 4E 9B BF 9E 87 0B 10 57 F2 26 79 9A 05 C0 E0 F7 4D 7D CA 52 9D F9 BC AA FC 8D 7E D1 A5 42 E7 D6 76 A7 84 8E 66 7C 23 88 37 49 D9
  26. “Contra has a single global 8-bit value that it uses

    as the source of randomness throughout the game. …[T]he next random value is generated by spinning in a tight loop during the time that the game is idle and waiting for the next display frame to begin. -Allan Blomquist THE CONTRA SOLUTION: DO SOME REALLY FAST MATH, ALL THE TIME
  27. PROBLEM #9 How do you make writable game 
 media

    that users can’t easily copy?
  28. SOLUTION: WRITE SAVES MULTIPLE TIMES ➤ Store multiple copies of


    the save data with a 
 CRC code (checksum) ➤ On load, check saves one
 by one until you find one 
 that is intact Dragon Warrior (1989)
  29. MMC1 (1987; 225 LICENSED US GAMES) PRG-ROM: up to 512KB

    PRG-RAM: optional, 8KB w/ battery CHR-ROM: up to 128KB Mirroring: switchable on-the-fly
  30. MMC3 (1988; 195 LICENSED US GAMES) PRG-ROM: up to 512KB

    PRG-RAM: optional, 8KB w/ battery CHR-ROM: up to 256KB Mirroring: switchable or 4-screen VRAM
  31. NINJA GAIDEN II: DARK SWORD OF CHAOS (1990, MMC3) Scanline

    IRQs
 to modify
 background
 scroll http://www.dustmop.io/blog/2015/12/18/nes-graphics-part-3/ Sprites
  32. NINJA GAIDEN II: DARK SWORD OF CHAOS (1990, MMC3) Scanline

    IRQs
 to modify
 background
 scroll http://www.dustmop.io/blog/2015/12/18/nes-graphics-part-3/ Sprites
  33. NINTENDO / VIDEO GAME HISTORY BOOKS ➤ Altice, Nathan. “I

    AM ERROR”. MIT Press, 2015. ➤ Bogost, Ian and Montfort, Nick. “Racing the Beam: The 
 Atari Video Computer System”. MIT Press, 2009. ➤ Bagnall, Brian. “On the Edge: The spectacular rise and fall of Commodore”. Variant Press, 2005. ➤ Sheff, David. “Game Over: How Nintendo zapped an American industry, captured your dollars, and enslaved your children”. Random House, 1993.