Bài 12: BG scroll


Vậy là đã kết thúc xong phần sprite, từ giờ ta sẽ tập trung vào BG. BG là dữ liệu ảnh nền (bối cảnh) cấu thành nên toàn bộ màn hình. BG không bị hạn chế như sprite là chỉ hiển thị được 8 sprite theo chiều ngang. Một trong những điểm đánh giá tài năng của lập trình viên là xem việc xử lý BG có khéo hay không. Trong số những game Famicom được đánh giá cao thì phần lớn đều là những game vận dụng, xử lý BG rất khéo. Vì không bị giới hạn như sprite nên BG có thể dùng để thể hiện những nhân vật khổng lồ hay vô số vật thể, nhân vật nhỏ li ti. 99,9% text (chữ) trong game cũng là BG.


Name table


Trong bài 6, ta đã biết Pattern table của BG bắt đầu từ địa chỉ $0000 trong VRAM. Cũng giống như sprite, BG là những tile có kích thước 8x8, gồm 256 chủng loại và có thể chứa 4KB. Name table là khu vực tập trung 256 chủng loại tile này lại và chỉ định mỗi loại bằng một byte, từ 00 đến FF.

Nhìn vào Memory trong bài 3, ta thấy có 4 khu vực Name table nhưng bình thường chỉ sử dụng 2 khu vực, còn lại là phần đối xứng gương. Tuy nhiên cũng có game sử dụng cả 4 khu vực này.
Lần này ta sẽ ghi 960 ($3BF) byte vào địa chỉ $2000 (bắt đầu của Name table 0). Con số 960 là tổng số tile của BG, ngang 32 x dọc 30 =960 vì màn hình Famicom có độ phân giải 256x240.
Số tile này được phủ kín màn hình theo thứ tự từ góc trái bên trên cho đến góc phải bên dưới.

Dưới đây là ví dụ trong trường hợp dữ liệu BG số 9 là tile màu đen, số 1 và số 2 là tile có hình ảnh ngôi sao. Star_Tbl là table số tile 0 màu đen ở khoảng cách giữa các ngôi sao. Điều ta làm là ghi 60 lần tile số 0 (màu đen), tiếp theo là ghi ngôi sao #1, tiếp theo là ghi 45 lần màu đen #0, rồi lại ghi ngôi sao #2... Trong trường hợp này sẽ xử lý như bên dưới


; tạo Name table $2000
lda #$20
sta $2006
lda #$00
sta $2006

lda #$00 ; #0 (nền đen)
ldy #$00 ; định dạng Register Y
loadNametable1:
ldx Star_Tbl, y ; đọc giá trị X vào Star Table
loadNametable2:
sta $2007 ; đọc giá trị thuộc tính vào $2007
dex ; giảm X
bne loadNametable2 ; nếu khác 0 thì lặp lại, cho ra màu đen
; lấy giao thoa tile #1 hay #2 từ giá trị của Y
tya ; Y→A
and #1 ; A AND 1
adc #1 ; tính thêm 1 vào A, ghi vào #1 hoặc #2
sta $2007 ; đọc giá trị thuộc tính vào $2007
lda #$00 ; #0 (màu đen)
iny ; tăng Y
cpy #20 ; lặp lại 20 lần (số Star table)
bne loadNametable1

; dữ liệu start table (20 cái)
Star_Tbl .db 60,45,35,60,90,65,45,20,90,10,30,40,65,25,65,35,50,35,40,35


Table thuộc tính

Table thuộc tính là dữ liệu palette của Name table ngay trước đó. Tuy nhiên, tổng số tile trên màn hình là 960 nhưng khu vực Table thuộc tính chỉ có 64 byte. Đó là vì Famicom dùng 1 byte để chỉ định cho một nhóm 4 tile có kích thước 2x2, vậy là tổng 8x8=64. BG có kích thước 32x30 tile nên bề dọc vẫn còn thừa. Vậy còn 1 byte chỉ định palette thì sao? Đối với byte này thì bit 0~1 chỉ định số hiệu palette của nhóm ở trên bên trái, bit 2~3 cho ở trên bên phải, bit 4~5 là ở dưới bên trái, bit 6~7 là ở dưới bên phải.

Điểm cần lưu ý ở đây là chỉ có thể chỉ định 2 bit đầu (xét theo hệ nhị phân). Trong palette BG từ 0~15, nếu dùng palette 0~3 thì đó là 0 trong 00 (00), nếu là palette 4_7 thì là 01 trong 4 (%0100), nếu là palette 8~10 thì là 10 trong 8 (%1000), nếu là palette 12~15 thì là 11 trong 12 (%1100). Tức là sử dụng 1 trong 4 chủng loại (16/6=4) palette.

Hình bên dưới là ví dụ. Chỉ định palette trong table thuộc tính là set 2x2, theo thứ tự góc trên bên trái, trên bên phải, dưới bên trái, dưới bên phải. Địa chỉ tile của Name table được chỉ định lót kín màn hình theo phương ngang từ góc trên bên trái đến góc dưới bên phải.

[​IMG]


Trong số 0~15 của palette thì 0, 4, 8, 12 là màu trong suốt, dù có chỉ định màu gì đi nữa cũng không hiển thị được nên thực chất ta chỉ dùng được 3 màu. Khi cần thể hiện hiệu ứng fade in, fade out cho màn hình thì cần phải có kỹ thuật thay đổi palette.
Điểm hạn chế này cũng giống như palette cho sprite đã giải thích ở bài 6. Đối với sprite thì ta chỉ định bằng bit 0~1 trong 3 số 3 trong số 4 byte thông tin của sprite, và BG cũng giống vậy.
Dưới đây là đoạn code ví dụ có sử dụn lệnh EOR, rất tiện lợi khi muốn thay đổi giá trị một cách giao thoa 0→1→0→1 khi thực hiện lệnh diễn toán XOR. Trong ví dụ này sẽ làm cho palette BG có dạng hoa văn sọc.

; load vào table thuộc tính của $23C0
lda #$23
sta $2006
lda #$C0
sta $2006

ldx #$00 ; clear X Register
lda #000000 ; chọn palette 0
; #0 hay #1
loadAttrib
eor #%01010101 ; chọn 0 hay 1 giao thoa nhau cách 1 dot khi diễn toán XO
sta $2007 ; đọc giá trị thuộc tính ($0 hay $55) vào $2007
; lặp lại 64 lần (tất cả các tile)
inx
cpx #64
bne loadAttrib



Cuốn BG

Dưới đây là giải thích về chức năng cuốn BG. Ta thử cho cuốn 1 dot cứ mỗi 1/60 giây.

; cuốn BG (giả định có biến số Scroll_X, Scroll_Y)
lda $2002 ; clear giá trị cuốn
lda Scroll_X ; load giá trị cuốn X
sta $2005 ; cuốn theo hướng X
lda Scroll_Y ; load giá trị cuốn Y
sta $2005 ; Y cuốn theo hướng Y

inc Scroll_X ; tăng giá trị cuốn X
inc Scroll_Y ; tăng giá trị cuốn Y


Chương trình cuốn BG chỉ đơn giản là vậy. Tuy nhiên đây chỉ là đoạn code đơn giản lặp lại cùng một màn hình, còn trong game bình thường thì khi cuốn, bối cảnh khác sẽ xuất hiện nên cần thường xuyên cập nhật màn hình. Để làm được việc này thì phải vẽ lại màn hình, cách làm sẽ đề cập ở chương sau.


Chương trình cuốn BG theo chiều ngang

Tải đoạn chương trình này về, giải nén và để các file chung với thư mục NESASM, chạy chương trình và và được một game cuốn màn hình đơn giản.

[​IMG]

0 bình luận :

Post a Comment

 
Top