TÓM TẮT

Mở Đầu

Việc vẽ một ngôi nhà trong môi trường ROM (Read‑Only Memory) không chỉ là một thử thách sáng tạo mà còn là cơ hội để khám phá cách thiết kế kiến trúc số trong các hệ thống nhúng, game retro, và các dự án phần mềm nhắm tới tối ưu bộ nhớ. Bài viết này sẽ cung cấp hướng dẫn chi tiết, từng bước một, giúp bạn từ người mới bắt đầu cho tới những lập trình viên có kinh nghiệm có thể tự tin tạo ra một ngôi nhà ROM đẹp mắt, tối ưu và dễ dàng tích hợp vào dự án của mình.

Lưu ý: Bài viết này tập trung vào việc vẽ ngôi nhà trong ROM, tức là dữ liệu đồ họa được lưu trữ dưới dạng tĩnh (không thay đổi) và được truy xuất nhanh chóng trong thời gian chạy. Vì ROM không thể thay đổi nội dung sau khi chương trình được nạp vào, việc thiết kế phải được thực hiện cẩn thận, tối ưu hoá và phù hợp với các hạn chế của phần cứng.

1. Tổng Quan Về ROM và Đồ Họa Trong ROM

1.1 ROM là gì?

  • ROM (Read‑Only Memory) là bộ nhớ không thay đổi, thường được dùng để lưu trữ firmware, BIOS, hoặc dữ liệu tĩnh như sprite, tiles, palette trong các hệ thống game retro.
  • Dữ liệu trong ROM được nạp vào khi thiết bị khởi động và không thể thay đổi trong quá trình chạy (trừ khi có cơ chế flash/EEPROM, nhưng không phải là mục tiêu của chúng ta).

1.2 Đồ họa trong ROM

  • Tileset: Hình ảnh được chia thành các khối (tile) nhỏ, thường kích thước 8×8 hoặc 16×16 pixel.
  • Sprite: Đối tượng di động, có thể bao gồm nhiều tile.
  • Palette: Bảng màu, mỗi màu thường được biểu diễn bằng 1‑2 byte (ví dụ: 15‑bit RGB trong SNES, 4‑bit trong NES).

1.3 Lý Do Vẽ Ngôi Nhà Trong ROM

  1. Tiết kiệm bộ nhớ RAM – Dữ liệu đồ họa được lưu trực tiếp trong ROM, không chiếm RAM.
  2. Tốc độ truy xuất nhanh – Đọc dữ liệu từ ROM thường nhanh hơn so với tải từ đĩa hoặc mạng.
  3. Tính ổn định – Dữ liệu không thay đổi, giảm nguy cơ lỗi do ghi nhầm.
  4. Thích hợp cho game retro – Hầu hết các máy chơi game cũ sử dụng ROM để lưu trữ đồ họa môi trường.

2. Chuẩn Bị Môi Trường Phát Triển

2.1 Công Cụ Vẽ Tiles

Công cụ Đặc điểm Định dạng xuất
Aseprite Giao diện thân thiện, hỗ trợ animation PNG, BMP, GIF
GrafX2 Phong cách pixel art, hỗ trợ đa nền tảng PNG, BMP
Tile Layer Pro Dành riêng cho chỉnh sửa tiles ROM RAW
YY‑CHR Đọc/viết trực tiếp vào ROM, hỗ trợ nhiều hệ thống RAW, HEX

Khuyến nghị: Dùng Aseprite để thiết kế các tile, sau đó xuất ra file PNG và dùng YY‑CHR để chèn vào ROM.

2.2 Trình Biên Dịch và Công Cụ Đánh Bản

  • cc65 (cho NES, Commodore 64)
  • RGBDS (cho Game Boy)
  • z88dk (cho ZX Spectrum, MSX)
  • WLA‑DX (cho SNES, Sega Genesis)

Bạn cần một assembler hoặc compiler phù hợp với nền tảng mục tiêu để biên dịch mã nguồn và nhúng dữ liệu đồ họa vào ROM.

2.3 Mô Phỏng và Kiểm Tra

  • FCEUX (NES)
  • BGB (Game Boy)
  • BizHawk (đa nền tảng)
  • MAME (đa hệ thống)

Sử dụng các công cụ này để kiểm tra ngôi nhà của bạn trong môi trường giả lập trước khi flash lên phần cứng thực.

Cách Vẽ Ngôi Nhà Rom
Cách Vẽ Ngôi Nhà Rom

3. Thiết Kế Ngôi Nhà – Bước Đầu Tiên

3.1 Lập Kế Hoạch Kiến Trúc

Thành phần Mô tả Số lượng tile đề xuất
Mái nhà Đỉnh tam giác hoặc dốc 4‑6
Tường Các bức tường nền 8‑12
Cửa sổ Nhỏ, có khung 2‑4
Cửa ra vào Cửa chính 2‑3
Cột/đỡ Hỗ trợ mái 2‑4
Nền đất Đường, cỏ, đá 4‑8

Xác định kích thước ngôi nhà bằng số tile. Ví dụ: một ngôi nhà 4×5 tile (rộng × cao) sẽ yêu cầu 20 tile cho tường, cộng thêm các chi tiết.

3.2 Chọn Palette

  • NES: 4‑bit (16 màu) mỗi palette, 4 palette cho nền, 4 palette cho sprite.
  • Game Boy: 2‑bit (4 màu) – thường dùng 2 palette (background và sprite).
  • SNES: 15‑bit RGB, 8‑16 màu mỗi palette.

Khuyến nghị: Đối với dự án học tập, chọn NES vì giới hạn màu sắc và kích thước tile đơn giản, giúp tập trung vào tối ưu hoá.

3.3 Vẽ Tile Cơ Bản

3.3.1 Tạo Tile Mái

  1. Mở Aseprite, tạo canvas 8×8 pixel.
  2. Chọn màu đỏ cho phần mái, nâu cho viền.
  3. Vẽ tam giác lên trên, để lại khoảng trống ở giữa cho cửa sổ nếu muốn.
  4. Lưu dưới dạng roof_tile.png.

3.3.2 Tạo Tile Tường

  1. Tạo canvas 8×8.
  2. Chọn màu nâu nhạt cho nền, nâu đậm cho viền.
  3. Vẽ một khối vuông, thêm chi tiết gỗ hoặc đá nếu muốn.
  4. Lưu wall_tile.png.

3.3.3 Tạo Tile Cửa Sổ và Cửa

  • Cửa sổ: 8×8, màu nền xanh nhạt, khung màu nâu.
  • Cửa: màu sắc đỏ hoặc nâu, thêm chi tiết tay nắm.

3.4 Tổ Chức Tileset

Sắp xếp các tile theo thứ tự trong file tileset.png:

Index Tile Mô tả
0 roof_tile Mái nhà
1 wall_tile Tường nền
2 window_tile Cửa sổ
3 door_tile Cửa ra vào
4‑7 ground_tile_x Nền đất, cỏ, đá
… … …

Đảm bảo kích thước tổng thể là bội số của 8 (ví dụ: 128×128 pixel cho 256 tile).

4. Chuyển Đổi Tileset Thành Dữ Liệu ROM

4.1 Định Dạng Dữ Liệu Tile

  • NES: Mỗi tile 16 byte (8 byte cho plane 0, 8 byte cho plane 1). Mỗi byte đại diện cho một hàng pixel, mỗi bit là một màu trong palette.
  • Game Boy: Tương tự, nhưng chỉ có 2 plane (2 bit/pixel).

4.2 Sử Dụng YY‑CHR Để Nhập Tileset

  1. Mở YY‑CHR, chọn File → Load ROM (chọn ROM mẫu hoặc tạo mới).
  2. Chọn File → Import → Import PNG và tải tileset.png.
  3. Kiểm tra rằng các tile hiển thị đúng màu theo palette đã chọn.
  4. Lưu lại ROM (File → Save).

4.3 Kiểm Tra Dữ Liệu

Mở ROM bằng hex editor (HxD, Bless) và xác nhận rằng mỗi tile chiếm đúng 16 byte. Đối với tile roof_tile (index 0), các byte đầu tiên sẽ là dữ liệu bitmap của mái.

5. Lập Trình Hiển Thị Ngôi Nhà Trong ROM

Cách Vẽ Ngôi Nhà Rom
Cách Vẽ Ngôi Nhà Rom

5.1 Cấu Trúc Bảng Bố Cục (Map)

Đối với một ngôi nhà 4×5 tile, chúng ta tạo một map array:

; NES example - 2‑bit per pixel, 4‑color palette
; Map width = 4 tiles, height = 5 tiles
HouseMap: .db $00, $01, $01, $00 ; Row 0: Roof (left), Roof (center), Roof (center), Roof (right) .db $02, $03, $03, $02 ; Row 1: Wall + Window, Door, Door, Wall + Window .db $02, $01, $01, $02 ; Row 2: Wall, Roof (fill), Roof (fill), Wall .db $02, $01, $01, $02 ; Row 3: Wall, Roof (fill), Roof (fill), Wall .db $04, $04, $04, $04 ; Row 4: Ground
  • $00 – index tile roof_left.
  • $01 – roof_center.
  • $02 – wall_tile.
  • $03 – door_tile.
  • $04 – ground_tile.

5.2 Code Đặt Bảng Bố Cục Vào PPU (NES)

; Assume PPU address $2000 is the nametable base
LoadHouse: LDX #$00 ; X = row index
LoadRow: LDY #$00 ; Y = column index
LoadCol: LDA HouseMap, X ; Load tile index STA $2006 ; Set PPU address low byte (example) INY CPY #$04 ; 4 columns BNE LoadCol INX CPX #$05 ; 5 rows BNE LoadRow RTS

Lưu ý: Mã trên chỉ là minh hoạ; cần thiết lập PPU address đúng và chuyển đổi sang PPU scroll tùy thuộc vào vị trí muốn hiển thị.

5.3 Đánh Bảng Palette

; Palette for background (NES)
PaletteBG: .db $0F,$21,$30,$0C ; 0: transparent, 1: dark brown, 2: light brown, 3: red roof

Gửi palette tới PPU qua $3F00.

6. Tối Ưu Hóa Dữ Liệu ROM

6.1 Loại Bỏ Tile Không Dùng

Sử dụng YY‑CHR → Tools → Tile Viewer → Delete Unused Tiles. Giảm kích thước ROM, đặc biệt quan trọng trên NES (≤ 32KB CHR).

6.2 Nén RLE (Run‑Length Encoding)

Một số bộ nhớ cho phép nén dữ liệu tile hoặc map. Ví dụ, NES không hỗ trợ nén trực tiếp, nhưng bạn có thể viết routine giải nén RLE trong RAM khi khởi động.

6.3 Sử Dụng Mirror/Flip

Nếu hệ thống hỗ trợ horizontal/vertical flip (NES PPU), bạn có thể dùng cùng một tile cho nhiều vị trí, giảm số tile cần.

; Example: use $00 tile flipped horizontally for right side roof
LDA #$00
STA $2006
LDA #$40 ; attribute byte: horizontal flip
STA $2007

7. Kiểm Tra và Gỡ Lỗi

7.1 Kiểm Tra Trên Emulator

Cách Vẽ Ngôi Nhà Rom
Cách Vẽ Ngôi Nhà Rom
  1. Load ROM vào FCEUX.
  2. Chạy và dừng tại VBlank để xem PPU nametable.
  3. Kiểm tra vị trí các tile: chúng có khớp với HouseMap không?

7.2 Debug Palette

  • Đảm bảo màu sắc đúng: nếu màu không hiển thị, kiểm tra palette index và attribute table.
  • Sử dụng debug console của emulator để xem giá trị thanh ghi PPU.

7.3 Kiểm Tra Kích Thước ROM

  • NES header: PRG ROM và CHR ROM size phải đúng.
  • Đảm bảo không vượt quá 16KB cho CHR nếu không dùng CHR‑RAM.

8. Mở Rộng – Thêm Chi Tiết và Tương Tác

8.1 Thêm Cửa Sổ Nhấp Nháy (Animation)

  • Tạo 2 frame cho cửa sổ: một có rèm, một không.
  • Sử dụng sprite để hiển thị trên nền tường.
  • Thêm routine cập nhật sprite mỗi 30 khung hình.

8.2 Thêm Đèn Hạ Phòng (Light Effect)

  • Dùng palette swapping: thay đổi màu nền từ tối sang sáng khi người chơi vào nhà.
  • Cập nhật palette qua $3F00 trong VBlank.

8.3 Thêm Cửa Ra Vào Di Chuyển

  • Khi nhân vật chạm vào door_tile, thay đổi map offset để chuyển sang bản đồ bên trong.

9. Đưa Ngôi Nhà Lên Thiết Bị Thực

9.1 Flash ROM

  • Sử dụng flash cartridge (例如: NES Power Pad, Game Boy Flash Cart) để nạp ROM.
  • Đảm bảo file .nes hoặc .gb đúng định dạng.

9.2 Kiểm Tra Trên Phần Cứng

  • Kết nối thiết bị, bật nguồn, kiểm tra hiển thị.
  • Nếu gặp vấn đề, kiểm tra pin wiring và voltage.

10. Tổng Kết

Việc vẽ ngôi nhà ROM không chỉ là việc tạo ra một hình ảnh tĩnh mà còn là quá trình tối ưu hoá dữ liệu, lập trình hiển thị, và kiểm tra trên cả phần mềm và phần cứng. Qua các bước:

  1. Hiểu ROM và cấu trúc đồ họa (tiles, palette, map).
  2. Chuẩn bị công cụ: Aseprite, YY‑CHR, assembler, emulator.
  3. Thiết kế tile chi tiết, lựa chọn palette phù hợp.
  4. Chuyển đổi sang định dạng ROM và nhúng vào file.
  5. Lập trình hiển thị qua PPU (hoặc GPU tương tự) và tạo bảng bố cục.
  6. Tối ưu bằng việc loại bỏ tile thừa, dùng flip, nén nếu cần.
  7. Kiểm tra kỹ lưỡng trên emulator, debug palette và map.
  8. Mở rộng tính năng tương tác, animation.
  9. Flash lên phần cứng và kiểm tra thực tế.

Nếu bạn làm theo hướng dẫn này một cách cẩn thận, bạn sẽ có một ngôi nhà ROM hoàn chỉnh, sạch sẽ và tối ưu, sẵn sàng tích hợp vào bất kỳ dự án game retro hay hệ thống nhúng nào. Hãy tiếp tục thử nghiệm, sáng tạo thêm các chi tiết như cây, đồ nội thất, hoặc đèn sáng để làm cho ngôi nhà trở nên sống động hơn.

Chúc bạn thành công trong hành trình vẽ và lập trình ngôi nhà ROM!

Rate this post
Mục nhập này đã được đăng trong Blog. Đánh dấu trang permalink.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *