KITAQ SERIES • 參考版
KITAQFC 函式庫
NES 函式庫與裝置
原始碼快照:2026 年 9 月 14 日 · 繁體中文版:2026 年 9 月 14 日
使用原生編譯器呼叫程式庫
lib/ 包含編入遊戲機 ROM 的 C 標頭與原始碼。PC 編譯器與輔助工具使用 Rust;遊戲原始碼、目標平台程式庫與 API 仍使用 C。提供的 SOURCE_MANIFEST.json 與 LIBRARY_MERGE.json 記錄程式庫原始碼的選擇。
kitaqfc · Rust 原生編譯器與輔助工具 · GitHub Actions
Windows、Linux、macOS ARM 和 macOS Intel 的原生建置及執行驗證均成功。KITAQGB 在每個環境通過 48 項測試與 395 項輔助工具檢查;KITAQFC 通過 55 項測試與 401 項檢查,也驗證了 Rust 1.85。PUBLIC_DISTRIBUTION.json 記錄已配置程式的雜湊與驗證來源。公開 GitHub Actions 會獨立建置及驗證這些原始碼。
保存的參考輸出用於檢查 ROM 位元組、診斷與輔助工具格式。先前的 C# 模擬器驗證保留為對應原始碼指紋的歷史紀錄,並不自動證明所有 Rust API、實體硬體或完整的 FDS BIOS 遊戲啟動。原始 PNG 轉換腳本無法取得,因此依規格重新實作,不能宣稱與原腳本位元組一致。
完整範例程式
程式、共用標頭、提供的 ascii.c 與轉換素材均已附上。m_ 開頭的名稱是本手冊的輔助函式。請搭配預期結果和驗證紀錄閱讀建置命令,並從各並列儲存庫的上層目錄執行。
顯示提供的字元集 fc_font.c
目的: 了解提供的原創字型包含哪些字母、數字與標點符號,以及如何繪製。
運作方式: m_init 準備顯示與字型。m_text 繪製各列,m_put 則以字元碼 34 繪製雙引號。
操作方式與預期結果: 請確認有 26 個大寫字母、26 個小寫字母、10 個數字及 30 個標點符號,並檢查每個字形是否清晰可辨。無須輸入操作。

.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_font.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_font.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Display the letters, digits and punctuation from the supplied ascii.c font.
// Expected: Uppercase, lowercase, numbers and all 30 supplied punctuation glyphs
#include "fc_common.h"
// Lay out every supplied character category, yielding between rows. The final
// m_put uses character code 34 to display the double quote separately.
void main(void) {
m_init();
m_text(2,3,"FONT");
m_text(2,5,"ABCDEFGHIJKLMNOP"); m_wait();
m_text(2,6,"QRSTUVWXYZ"); m_wait();
m_text(2,8,"0123456789"); m_wait();
m_text(2,10,"abcdefghijklmnop"); m_wait();
m_text(2,11,"qrstuvwxyz"); m_wait();
m_text(2,13,"!#$%&'()*+,-./"); m_wait();
m_text(2,14,":;<=>?@[]^_`{}~"); m_wait();
m_put(16,13,34); m_wait();
while (1) { m_wait(); }
}第一次顯示文字 fc_hello.c
目的: 學習啟動 ROM 並在背景繪製文字與數字的基本步驟。
運作方式: m_init 後,m_text 繪製問候文字,m_number 格式化 42。最後的迴圈等待影格並保持畫面顯示。
操作方式與預期結果: 畫面顯示 HELLO WORLD 與 042。前面的零來自三位數十進位格式。

.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_hello.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_hello.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Display a first message on screen.
// Expected: HELLO WORLD and 042
#include "fc_common.h"
// Initialize the display/font, write HELLO WORLD and a three-digit 042,
// then wait for frames so the result remains visible.
void main(void) {
m_init();
m_text(2,3,"HELLO");
m_text(2,5,"HELLO WORLD");
m_number(42);
while (1) { m_wait(); }
}使用較寬型別的中間值運算 fc_arithmetic.c
目的: 學習如何保留超出八位元範圍的中間結果。
運作方式: (u16)200 + 100 的結果為 300。程式先除以 10,再轉為 u8 顯示。請注意,擴大型別的轉型發生在加法之前。
操作方式與預期結果: 030 表示計算結果 30。

.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_arithmetic.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_arithmetic.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Variables, arithmetic and type conversion.
// Expected: 030
#include "fc_common.h"
// Widen before adding 200 + 100, divide the 16-bit sum, and display 30.
// The cast demonstrates avoiding an 8-bit intermediate result.
void main(void) {
m_init();
m_text(2,3,"ARITHMETIC");
u16 sum;
sum = (u16)200 + 100;
m_number((u8)(sum / 10));
while (1) { m_wait(); }
}分支與迴圈 fc_control.c
目的: 在簡單計算中試用 for、continue、while 與 if/else。
運作方式: for 迴圈累加 0 至 7,但跳過 3,得到 25。while 迴圈將值增加至 32;接著的 if 在值相符時指定為 42。
操作方式與預期結果: 042 是最終結果。此程式使用 if/else 分支。

.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_control.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_control.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Conditional branches and loops.
// Expected: 042
#include "fc_common.h"
// Exercise loop control and a final branch, then display the selected value 42.
void main(void) {
m_init();
m_text(2,3,"CONTROL");
u8 i; u8 sum; sum=0;
for (i=0;i<8;i++) { if (i==3) continue; sum=(u8)(sum+i); }
while (sum<32) { sum++; }
if (sum==32) sum=42; else sum=0;
m_number(sum);
while (1) { m_wait(); }
}函式、陣列、結構與指標 fc_aggregate.c
目的: 學習如何將值分組,並透過函式與指標存取。
運作方式: 程式複製包含 (10,20) 的 Point,再透過指標將 1 至 4 寫入陣列。它將函式結果 30 加上陣列值 1、2、4 與常數 5。
操作方式與預期結果: 總和顯示為 042。請追蹤結構複製、ptr[i] 寫入與函式傳回值。
![函式、陣列、結構與指標:總和顯示為 042。請追蹤結構複製、ptr[i] 寫入與函式傳回值。](../verification/fc_aggregate.png)
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_aggregate.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_aggregate.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Functions, arrays, structures and pointers.
// Expected: 042
#include "fc_common.h"
typedef struct { u8 x; u8 y; } Point;
// Add two byte values and explicitly narrow the returned result to u8.
u8 add(u8 a,u8 b) { return (u8)(a+b); }
// Copy a structure, fill an array through a pointer, and combine selected values
// through add() to produce 42. Keep the final screen visible in the idle loop.
void main(void) {
m_init();
m_text(2,3,"AGGREGATE");
Point a; Point b; u8 i; u8 data[4]; u8* ptr;
a.x=10; a.y=20; b=a; ptr=data;
for(i=0;i<4;i++) ptr[i]=(u8)(i+1);
m_number((u8)(add(b.x,b.y)+ptr[0]+ptr[1]+ptr[3]+5));
while (1) { m_wait(); }
}位元旗標與緩衝區複製 fc_bits_memory.c
目的: 將旗標打包成一個位元組,並將緩衝區複製至另一個儲存區。
運作方式: __memset 清除四個位元組。程式設定位元 3、切換位元 1,再以 __memcpy 複製全部四個位元組。
操作方式與預期結果: 目的緩衝區的第一個位元組顯示為 010,其中位元 3 貢獻 8,位元 1 貢獻 2。

.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_bits_memory.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_bits_memory.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Bit operations and memory copying.
// Expected: 010
#include "fc_common.h"
// Clear the source bytes, set bits 3 and 1, copy the buffer, and display 8 + 2 = 10.
void main(void) {
m_init();
m_text(2,3,"BITS MEMORY");
u8 data[4]; u8 copy[4];
__memset(data,0,4); __bit_set(data,3); __bit_toggle(data,1);
__memcpy(copy,data,4); m_number(copy[0]);
while (1) { m_wait(); }
}計算按鈕新按下的次數 fc_input.c
目的: 區分按鈕剛按下與持續按住的狀態。
運作方式: 每個影格都會呼叫 input_update。只有 input_pressed(BTN_A) 為真時,計數器才會增加。
操作方式與預期結果: 初始值為 000。按 A 後變成 001,持續按住不會累加。放開後再按一次便變成 002。此位元組計數器會從 255 回繞至 000。

.\kitaqfc\kitaqfc.exe kitaqfc/lib/input.c kitaq-docs/samples/fc_input.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_input.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Distinguish a new button press from a held button.
// Expected: 000 initially; A increments once per press
#include "fc_common.h"
#include "input.h"
u8 manual_count;
// Sample buttons once per frame and increment only on a new A press.
// Holding A does not repeatedly increment; the byte-sized counter wraps after 255.
void main(void) {
m_init();
m_text(2,3,"INPUT");
input_init();
m_number(0);
while (1) { m_wait(); input_update(); if(input_pressed(BTN_A)) { manual_count++; m_number(manual_count); } }
}Q8.8 定點數相乘 fc_fixed.c
目的: 學習將整數轉為 Q8.8、相乘,再轉回整數。
運作方式: fix_from_int 將 3、4 轉成 Q8.8,fix_mul 將兩者相乘,fix_to_int 再將乘積轉回整數。
操作方式與預期結果: 012 表示 3 × 4 = 12,是轉換後的整數,不是內部放大 256 倍的值。

.\kitaqfc\kitaqfc.exe kitaqfc/lib/fixed.c kitaq-docs/samples/fc_fixed.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_fixed.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Calculate with signed Q8.8 fixed-point values.
// Expected: 012
#include "fc_common.h"
#include "fixed.h"
// Convert 3 and 4 to Q8.8, multiply them, convert the result back to an
// integer, and display 12.
void main(void) {
m_init();
m_text(2,3,"FIXED");
fix8 a; fix8 b; a=fix_from_int(3); b=fix_from_int(4);
m_number((u8)fix_to_int(fix_mul(a,b)));
while (1) { m_wait(); }
}從固定物件池配置 fc_entity.c
目的: 從固定的一組槽位建立物件,無須動態配置記憶體。
運作方式: entity_init 重設物件池。entity_create 在 (20,30) 建立型別 1;程式先檢查失敗 ID 0xFF,再將 vx 設為 2。
操作方式與預期結果: 001 是啟用中的物件數,不是 ID 或座標。此範例不更新或繪製物件,因此不會出現移動角色。

.\kitaqfc\kitaqfc.exe kitaqfc/lib/entity.c kitaq-docs/samples/fc_entity.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_entity.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Allocate an entity from a fixed-capacity object pool.
// Expected: 001
#include "fc_common.h"
#include "entity.h"
// Create one entity and check the 0xFF allocation-failure sentinel before
// accessing its velocity. Display the pool occupancy, not the entity ID.
void main(void) {
m_init();
m_text(2,3,"ENTITY");
u8 id; entity_init(); id=entity_create(1,20,30);
if(id!=0xFF) entity_get(id)->vx=2; m_number(entity_count_active());
while (1) { m_wait(); }
}將診斷值記錄至 RAM fc_debug.c
目的: 將具名遊戲值保存在診斷緩衝區,與畫面顯示分開處理。
運作方式: 程式初始化除錯功能,將影格標記設為 1,並以 HP 為名稱記錄值 42。
操作方式與預期結果: 001 是追蹤項目數。HP=42 存於診斷緩衝區,僅靠畫面無法顯示或驗證該內容。

.\kitaqfc\kitaqfc.exe kitaqfc/lib/debug.c kitaq-docs/samples/fc_debug.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_debug.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Record diagnostic values in the debug trace.
// Expected: 001; trace log contains HP=42
#include "fc_common.h"
#include "debug.h"
// Record HP = 42 with frame tag 1 and display the number of trace entries.
// The trace buffer contains the value; the screen displays the count, not HP.
void main(void) {
m_init();
m_text(2,3,"DEBUG");
debug_init(); debug_set_frame(1); debug_trace_u8("HP",42);
m_number(debug_get_trace_count());
while (1) { m_wait(); }
}儲存位置歷程 fc_chain.c
目的: 學習如何將位置軌跡儲存在環形緩衝區中。
運作方式: chain_init 掛接可容納四個點的陣列,接著 chain_push_head 記錄 (20,30)。
操作方式與預期結果: 042 是固定完成標記,不是座標或數量。請檢查 trail 與 points 以確認儲存的歷史。此程式不繪製跟隨的身體。

.\kitaqfc\kitaqfc.exe kitaqfc/lib/chain.c kitaq-docs/samples/fc_chain.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_chain.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Store a position history in a ring buffer.
// Expected: 042; history contains (20,30)
#include "fc_common.h"
#include "chain.h"
Chain trail; ChainPoint points[4];
// Attach four history slots and record one point. The displayed 42 is a fixed
// completion marker; inspect the chain to verify the stored (20,30) point.
void main(void) {
m_init();
m_text(2,3,"CHAIN");
chain_init(&trail,points,4); chain_push_head(&trail,20,30);
m_number(42);
while (1) { m_wait(); }
}讀取函式庫影格計數器 fc_system.c
目的: 觀察以影格計數的等待如何影響函式庫影格計數器。
運作方式: system_init 後,程式呼叫兩次 system_wait_vblank,再顯示 system_get_frame8。
操作方式與預期結果: 結果為 002。閒置迴圈使用手冊輔助函式 m_wait,因此顯示值不會持續增加。

.\kitaqfc\kitaqfc.exe kitaqfc/lib/system.c kitaq-docs/samples/fc_system.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_system.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Count completed frame waits.
// Expected: 002
#include "fc_common.h"
#include "system.h"
// Reset the library frame count, perform two counted waits, and display 2.
// Subsequent m_wait calls leave that library counter unchanged.
void main(void) {
m_init();
m_text(2,3,"SYSTEM");
system_init(); system_wait_vblank(); system_wait_vblank();
m_number(system_get_frame8());
while (1) { m_wait(); }
}選取目前場景 ID fc_scene.c
目的: 學習如何選取 ID,以區分標題畫面、遊戲進行等場景。
運作方式: 程式登錄兩個以零初始化的 SceneDef 項目,再以 scene_change 選取 ID 1。
操作方式與預期結果: 001 是 scene_get_current 傳回的目前 ID。此範例未註冊場景回呼或轉場繪製。

.\kitaqfc\kitaqfc.exe kitaqfc/lib/runtime.c kitaqfc/lib/scene.c kitaq-docs/samples/fc_scene.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_scene.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// The scene streaming module shares runtime.c queue symbols, even though this demo only changes IDs.
#define MANUAL_FC_RUNTIME 1
// Switch the current scene ID.
// Expected: 001; no callbacks registered
#include "fc_common.h"
#include "scene.h"
SceneDef manual_scenes[2];
// Register two zero-initialized scene entries, select ID 1 and display it.
// No callbacks are registered in this example.
void main(void) {
m_init();
m_text(2,3,"SCENE");
scene_init(manual_scenes,2); scene_change(1);
m_number(scene_get_current());
while (1) { m_wait(); }
}累積 Q5.3 小數位移 fc_subpixel.c
目的: 將次像素移動量保留為餘數,並把整數像素部分累加至位置。
運作方式: 從 X=40 開始,迴圈將 2/8 像素累加八次。右移運算取出整數像素,遮罩則保留餘數。
操作方式與預期結果: 總位移為兩像素,因此畫面將 X=42 顯示為 042。此手動積分範例處理正向移動;負向移動須搭配借位處理。

.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_subpixel.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_subpixel.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Accumulate Q5.3 eighth-pixel motion into an integer coordinate.
// Expected: 042; explicit game-side integration using header constants
#include "fc_common.h"
#include "physics2d.h"
// Integrate eight increments of 2/8 pixel. Carry whole pixels into X and
// retain the fractional remainder with the supplied mask, moving X from 40 to 42.
void main(void) {
m_init();
m_text(2,3,"SUBPIXEL");
KQ2DPosition x; KQ2DFraction frac; KQ2DSpeed speed; u8 i;
// This example demonstrates positive motion only; signed negative motion needs a matching carry/borrow path.
x=40; frac=0; speed=2;
for(i=0;i<8;i++) {
frac=(u8)(frac+speed);
x=(u8)(x+(frac>>KQ2D_SUBPIXEL_BITS));
frac=(u8)(frac & KQ2D_SUBPIXEL_MASK);
}
m_number(x);
while (1) { m_wait(); }
}捲動 NES 背景 fc_scroll.c
目的: 更新 PPU 捲動位置以移動背景。
運作方式: 從 __scroll_set(0,0) 開始,程式每個影格將 phase 遞增一次,並用作水平位置。
操作方式與預期結果: SCROLL 字樣的水平位置會改變。phase 從 255 回繞至 0。這不是跨越多個名稱表的寬幅地圖範例。

.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_scroll.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_scroll.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Scroll the NES background horizontally.
// Expected: title scrolls horizontally
#include "fc_common.h"
u8 phase;
// Advance an 8-bit horizontal scroll position once per frame, wrapping naturally
// after 255. Background motion demonstrates the changing scroll register.
void main(void) {
m_init();
m_text(2,3,"SCROLL");
__scroll_set(0,0);
while (1) { m_wait(); phase++; __scroll_set(phase,0); }
}透過 NMI 套用圖塊更新 fc_vram_queue.c
目的: 由主程式提交 PPU 更新,再由 NMI 處理流程套用。
運作方式: __vramq_put 將圖塊 52 排入名稱表位址 0x2103,__vramq_commit 再提交。該位址對應圖塊座標 (3,8)。
操作方式與預期結果: 背景座標 (3,8) 出現一個 4。提供的字型中,圖塊 52 就是數字 4。

.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_vram_queue.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_vram_queue.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Submit a VRAM update for the NMI handler.
// Expected: 4 at (3,8)
#include "fc_common.h"
// Queue tile 52 at nametable address 0x2103, corresponding to (3,8), and
// commit the queue so the NMI update path displays the digit 4.
void main(void) {
m_init();
m_text(2,3,"VRAM QUEUE");
__vramq_put(0x2103,52); __vramq_commit();
while (1) { m_wait(); }
}顯示 NES OAM 精靈 fc_sprite.c
目的: 準備精靈顏色與 OAM 資料,以繪製獨立於背景的圖像。
運作方式: 程式載入精靈調色盤,將槽位 0 設為位置 (70,80)、圖塊 65、屬性 0,啟用繪製後重複執行 OAM DMA。
操作方式與預期結果: 靜止的字母 A 以精靈顯示。此範例示範 OAM 設定與傳輸,不是動畫。

.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_sprite.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_sprite.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Display a sprite using NES OAM.
// Expected: A sprite on screen
#include "fc_common.h"
// Load the sprite palette, assign font tile 65 to OAM slot zero, enable
// background/sprite display, and transfer OAM after each frame wait.
void main(void) {
m_init();
m_text(2,3,"SPRITE");
__palette_sp_load(manual_pal); __sprite_set(0,70,80,65,0);
__ppu_mask_set(0x1E);
while (1) { m_wait(); __oam_dma(); }
}播放 APU 脈衝音 fc_sound.c
目的: 設定 NES 內建脈衝聲道的控制、計時器與長度值。
運作方式: nes_apu_init 後,程式呼叫 nes_sfx_square1(0xBF,400,20)。控制值 0xBF 選擇固定音量並停止長度計數器,因此聲音持續。20 是長度表索引,不是 20 影格。
操作方式與預期結果: 顯示 042 時持續播放脈波音。呼叫 nes_apu_silence_all 可停止。僅靠畫面標記無法驗證聲音輸出。

.\kitaqfc\kitaqfc.exe kitaqfc/lib/audio.c kitaq-docs/samples/fc_sound.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_sound.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Play a pulse-channel effect on the built-in NES APU.
// Expected: 042 and a pulse tone
#include "fc_common.h"
#include "audio.h"
// Initialize the APU, trigger pulse channel 1 with the chosen timer/length
// values, and leave the screen displaying 42 while the hardware plays the tone.
void main(void) {
m_init();
m_text(2,3,"SOUND");
// Control BF selects constant volume and halts the length counter, so this tone sustains.
// Call nes_apu_silence_all when the game should stop it; 20 is a length-table index, not frames.
nes_apu_init(); nes_sfx_square1(0xBF,400,20);
m_number(42);
while (1) { m_wait(); }
}函式庫 API 辭典
共 294 個項目。展開可查看語法、引數、原始碼說明與範例。呼叫片段依賴周邊初始化,不能單獨建置 ROM。引數傳遞範例只說明如何將備妥的值交給 API,不代表已完成裝置層級驗證。
actor.h — 遊戲 actor 陣列
NesActor 整合世界位置、畫面位置與矩形尺寸。輔助函式可透過相機換算、寫入組合精靈 OAM,以及測試世界空間重疊。速度、畫面外剔除及 OAM DMA 由遊戲管理。
nes_actor_collide
在世界座標中測試角色物件的軸對齊矩形是否重疊。
語法
unsigned char nes_actor_collide(struct NesActor* a, struct NesActor* b);參數
a第一個角色物件。
b第二個角色物件。
回傳值
重疊時傳回 1;分離或僅邊緣接觸時傳回 0。
使用條件與限制
寬與高須為正值,且位置+尺寸≤65535。忽略畫面座標、attr 與 flags。
使用範例
result[3]=nes_actor_collide(&a,&b);nes_actor_set_world(&b,315,95);result[4]=nes_actor_collide(&a,&b);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
將世界 (300,95) 經相機 (268,32) 換算後,紅色與藍色 8×8 部件分別出現在 (32,64) 與 (40,64)。這示範原始 OAM Y=63 會顯示於 64,以及碰撞值由僅邊緣接觸時的零,變成重疊一像素時的一。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_actor.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_actor.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/actor.h:29
Test overlap in world coordinates with exclusive right/bottom edges. Keep position-plus-size sums within u16; touching edges are not collisions. Require positive widths and heights; zero extents are not rejected before the edge tests.
kitaqfc/lib/actor.c:49
unsigned char nes_actor_collide(struct NesActor* a, struct NesActor* b)
{
unsigned short a_right;
unsigned short b_right;
unsigned short a_bottom;
unsigned short b_bottom;
a_right = (unsigned short)(a->world_x + a->width);
b_right = (unsigned short)(b->world_x + b->width);
a_bottom = (unsigned short)(a->world_y + a->height);
b_bottom = (unsigned short)(b->world_y + b->height);
if (a_right <= b->world_x)
{
return 0;
}
if (b_right <= a->world_x)
{
return 0;
}
if (a_bottom <= b->world_y)
{
return 0;
}
if (b_bottom <= a->world_y)
{
return 0;
}
return 1;
}nes_actor_draw_metasprite
使用角色物件快取的畫面座標,將組合精靈寫入影子 OAM。
語法
unsigned char nes_actor_draw_metasprite(struct NesActor* actor, unsigned char oam_index, unsigned char* metasprite);參數
actor指向可寫入 NesActor 的指標。
oam_index第一個插槽,0..63;請為所有組成部分保留空間。
metasprite四位元組記錄 dx,dy,tile,attr;dx=255 表示結束。
回傳值
傳回下一個 OAM 插槽索引,在 64 個插槽末端回捲。
使用條件與限制
請連結 runtime.c。佇列會複製資料,供之後的 NMI 或關閉繪圖時的安全提交使用。生產與消費操作須序列化。多列操作中若容量耗盡,先前成功加入的列仍留在佇列中。
不套用角色物件的 attr/flags 欄位。Y 是原始 OAM 位元組,因此可見頂端會低一個像素。須執行 OAM DMA 才能顯示影子緩衝區內容。
使用範例
result[5]=nes_actor_draw_metasprite(&a,0,parts);result[6]=nes_oam_shadow[3];result[7]=nes_oam_shadow[7];nes_oam_dma(2);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
將世界 (300,95) 經相機 (268,32) 換算後,紅色與藍色 8×8 部件分別出現在 (32,64) 與 (40,64)。這示範原始 OAM Y=63 會顯示於 64,以及碰撞值由僅邊緣接觸時的零,變成重疊一像素時的一。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_actor.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_actor.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/actor.h:25
Draw the byte-stream metasprite at cached screen coordinates and return its next OAM index. Actor attr/flags are not applied by this wrapper.
kitaqfc/lib/actor.c:41
unsigned char nes_actor_draw_metasprite(struct NesActor* actor, unsigned char oam_index, unsigned char* metasprite)
{
return nes_metasprite_draw(oam_index, actor->screen_x, actor->screen_y, metasprite);
}nes_actor_set_world
設定角色物件的世界 X/Y。
語法
void nes_actor_set_world(struct NesActor* actor, unsigned short x, unsigned short y);參數
actor指向可寫入 NesActor 的指標。
x世界 X,0..65535 像素。
y世界 Y,0..65535 像素。
回傳值
無傳回值。
使用條件與限制
不更新 screen_x/screen_y。請呼叫 update_screen,透過相機換算畫面座標。
使用範例
nes_actor_set_world(&a,300,95);nes_actor_set_world(&b,316,95);result[0]=a.world_x;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
將世界 (300,95) 經相機 (268,32) 換算後,紅色與藍色 8×8 部件分別出現在 (32,64) 與 (40,64)。這示範原始 OAM Y=63 會顯示於 64,以及碰撞值由僅邊緣接觸時的零,變成重疊一像素時的一。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_actor.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_actor.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/actor.h:19
Set the actor's 16-bit world position without updating cached screen coordinates.
kitaqfc/lib/actor.c:19
void nes_actor_set_world(struct NesActor* actor, unsigned short x, unsigned short y)
{
actor->world_x = x;
actor->world_y = y;
}nes_actor_update_screen
從世界座標減去相機座標,將低位元組快取為畫面座標。
語法
void nes_actor_update_screen(struct NesActor* actor, unsigned short camera_x, unsigned short camera_y);參數
actor指向可寫入 NesActor 的指標。
camera_x相機的世界 X。
camera_y相機的世界 Y。
回傳值
無傳回值。
使用條件與限制
負值或 ≥256 的結果會回捲。不會隱藏畫面外的角色物件;遊戲須在繪圖前剔除。
使用範例
nes_actor_update_screen(&a,268,32);result[1]=a.screen_x;result[2]=a.screen_y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
將世界 (300,95) 經相機 (268,32) 換算後,紅色與藍色 8×8 部件分別出現在 (32,64) 與 (40,64)。這示範原始 OAM Y=63 會顯示於 64,以及碰撞值由僅邊緣接觸時的零,變成重疊一像素時的一。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_actor.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_actor.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/actor.h:22
Subtract the camera and retain only the low coordinate bytes. This performs wrapping projection, not clipping; callers must hide actors outside the viewport.
kitaqfc/lib/actor.c:27
void nes_actor_update_screen(struct NesActor* actor, unsigned short camera_x, unsigned short camera_y)
{
unsigned short dx;
unsigned short dy;
dx = (unsigned short)(actor->world_x - camera_x);
dy = (unsigned short)(actor->world_y - camera_y);
actor->screen_x = (unsigned char)dx;
actor->screen_y = (unsigned char)dy;
}asset.h — 素材 ID 與資料描述
素材函式庫透過8位元ID查找ROM記憶體區塊中的素材。請包含asset.c;FC版還需要bank.c。緊密排列的AssetDesc占6位元組,依序儲存1位元組類型、1位元組素材區塊編號、16位元位址,以及以位元組計算的長度。描述符表與素材資料可以放在不同區塊。
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
查找RAW或TILES素材,切換至其ROM區塊,使用__vram_write以每次最多128位元組傳送全部資料。最後恢復bank_get_current()保存的區塊。分段傳送不會等待下一影格。
圖案資料須使用可寫入的CHR RAM,大量上傳時應關閉繪製。若在VBlank期間上傳,整個操作必須在可用時間內完成;每次128位元組並不會自動保證這一點。範例使用--mapper=mmc1 --board=surom512。一般板型省略--nes-chr會產生空白CHR ROM,而不是CHR RAM。
asset_get
從已登記表格所在的ROM區塊讀取一筆AssetDesc,複製到呼叫端提供的空間。取得的是素材資訊,而非素材資料本身。
語法
u8 asset_get(u8 asset_id, AssetDesc* out_desc);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。out_desc可寫入一筆6位元組描述符的空間。若為null,會在存取表格之前傳回失敗。
回傳值
複製描述符後傳回1;輸出指標為null或ID超出範圍時傳回0,且不修改輸出空間。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
loaded=asset_get(0,&descriptor);
expect(loaded==1,1);
expect(descriptor.type==ASSET_TYPE_TILES && descriptor.bank==2,2);
expect(descriptor.ptr==asset_shapes && descriptor.len==144,3);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例讀取描述符0,檢查TILES類型、區塊2、素材指標與144位元組長度。超出範圍的ID與null輸出必須失敗;查找失敗時保留輸出空間中的原值。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
FC中,(16,64)的藍色三角形與方框顯示__far_memcpy結果,(16,96)的綠色一對顯示asset_load_raw後再上傳CHR的結果。每對在黑底上占16×8像素,可直接查看複製的圖像位元組是否正確,而非只看數值狀態。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasm實作與原始碼
kitaqfc/lib/asset.h:25
Copy a descriptor from its ROM bank into caller storage. Null output or an out-of-range ID returns zero without reading the table.
kitaqfc/lib/asset.c:18
u8 asset_get(u8 asset_id, AssetDesc* out_desc)
{
if (out_desc == 0) return 0;
if (asset_id >= asset_table_count) return 0;
__far_memcpy((u8*)out_desc, asset_table_bank, (u16)(asset_table + asset_id), sizeof(AssetDesc));
return 1;
}asset_get_bank
從描述符讀取素材資料的區塊編號。這不是描述符表所在的區塊編號,函式返回後也不會保持選取素材區塊。
語法
u8 asset_get_bank(u8 asset_id);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。
回傳值
傳回描述符的8位元bank;查找失敗則為0。有效區塊也可能為0,需要區分成敗時請使用asset_get()。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
每個取得函式都會再次呼叫asset_get並複製描述符。若同時需要區塊、指標與長度,請只呼叫一次asset_get後讀取各欄位。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
payload_bank=asset_get_bank(0);
expect(payload_bank==2,17); // Payload bank, not descriptor-table bank 3.
expect(asset_get_bank(4)==0,18); // Failure sentinel; a valid descriptor may also use bank 0.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例確認即使描述符表位於區塊3,傳回的仍是素材資料的區塊2,也檢查無效ID會傳回0。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
FC中,(16,64)的藍色三角形與方框顯示__far_memcpy結果,(16,96)的綠色一對顯示asset_load_raw後再上傳CHR的結果。每對在黑底上占16×8像素,可直接查看複製的圖像位元組是否正確,而非只看數值狀態。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasm實作與原始碼
kitaqfc/lib/asset.h:33
Return the asset bank or zero on lookup failure; bank zero may also be valid.
kitaqfc/lib/asset.c:74
u8 asset_get_bank(u8 asset_id)
{
AssetDesc desc;
if (asset_get(asset_id, &desc) == 0) return 0;
return desc.bank;
}asset_get_len
從描述符讀取以位元組計算的素材長度。傳回的是登記資訊;函式不檢查素材本身,也不換算為圖塊數、元素數或影格數。
語法
u16 asset_get_len(u8 asset_id);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。
回傳值
傳回以位元組計算的16位元len;查找失敗為0。空素材的長度也是0,區分兩者請使用asset_get()。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
每個取得函式都會再次呼叫asset_get並複製描述符。若同時需要區塊、指標與長度,請只呼叫一次asset_get後讀取各欄位。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
expect(asset_get_len(0)==144,21); // Bytes, not tiles.
expect(asset_get_len(3)==0 && asset_get_len(4)==0,22); // Empty asset and invalid ID both yield zero.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
9個圖塊的素材應傳回144位元組,而非圖塊數9。空素材與無效ID皆應傳回0。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
FC中,(16,64)的藍色三角形與方框顯示__far_memcpy結果,(16,96)的綠色一對顯示asset_load_raw後再上傳CHR的結果。每對在黑底上占16×8像素,可直接查看複製的圖像位元組是否正確,而非只看數值狀態。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasm實作與原始碼
kitaqfc/lib/asset.h:38
Return the descriptor byte length, or zero for an invalid ID.
kitaqfc/lib/asset.c:91
u16 asset_get_len(u8 asset_id)
{
AssetDesc desc;
if (asset_get(asset_id, &desc) == 0) return 0;
return desc.len;
}asset_get_ptr
讀取描述符中保存的16位元的素材位址。傳回的近指標不含區塊編號。讀取其他ROM區塊中的素材時,應搭配asset_get_bank()的結果與跨區塊複製函式使用。
語法
const u8* asset_get_ptr(u8 asset_id);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。
回傳值
傳回保存的const u8*;查找失敗時為null。函式不檢查描述符中的素材指標是否為null,區分查找成敗請使用asset_get()。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
每個取得函式都會再次呼叫asset_get並複製描述符。若同時需要區塊、指標與長度,請只呼叫一次asset_get後讀取各欄位。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
payload_pointer=asset_get_ptr(0);
expect(payload_pointer==asset_shapes,19);
expect(*asset_bank_marker==0xA1,20); // Getting the pointer leaves bank 1 selected.
// Use payload_bank together with payload_pointer for a far copy; do not dereference it here.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
傳回指標必須等於ROM配置完成後的素材位址,同時區塊1中的標記仍可讀取。隨後,範例將此指標與素材區塊2一起傳給跨區塊複製函式。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
FC中,(16,64)的藍色三角形與方框顯示__far_memcpy結果,(16,96)的綠色一對顯示asset_load_raw後再上傳CHR的結果。每對在黑底上占16×8像素,可直接查看複製的圖像位元組是否正確,而非只看數值狀態。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasm實作與原始碼
kitaqfc/lib/asset.h:36
Return the stored address without switching banks. Pair it with the descriptor bank before reading banked ROM; a failed lookup returns null.
kitaqfc/lib/asset.c:83
const u8* asset_get_ptr(u8 asset_id)
{
AssetDesc desc;
if (asset_get(asset_id, &desc) == 0) return 0;
return desc.ptr;
}asset_load_raw
查找素材,從其ROM區塊向可寫入記憶體複製min(desc.len, max_len)位元組。不檢查類型標記;圖塊、地圖與樂曲都依原始位元組複製,不解析格式,也不解壓縮。
語法
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。dst目標可寫入記憶體,容量必須足以容納實際複製的全部位元組。除了零位元組傳送外,不會檢查null或無效目標位址。
max_len最多複製的位元組數,範圍0–65535。小於素材長度時只複製前面一部分;設為0時不複製素材位元組。
回傳值
查找失敗傳回0,否則傳回1,包含只複製部分資料、上限為0或空素材。傳回值不是位元組數,也不表示整份素材都已複製。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
整個來源範圍必須在預期ROM映射中可讀取,整個目標範圍必須可寫入。複製不會在區塊視窗邊界自動切換至下一區塊,不提供memmove式的重疊處理,也不控制VRAM安全寫入時機。寫入VRAM請使用圖形傳送API。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
loaded=asset_load_raw(0,buffer,7); // Success with truncation: copy seven of 144 bytes.
expect(loaded==1 && buffer[7]==0x55,7);
for(i=0;i<7;i++) expect(buffer[(__safe_index u8)i]==expected_shape_byte(i),8);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
對144位元組素材設定7位元組上限,只複製前7位元組,下一位元組仍為0x55,但函式傳回成功。程式也檢查完整複製、上限0、空素材,以及MAP類型素材的原始複製。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
FC中,(16,64)的藍色三角形與方框顯示__far_memcpy結果,(16,96)的綠色一對顯示asset_load_raw後再上傳CHR的結果。每對在黑底上占16×8像素,可直接查看複製的圖像位元組是否正確,而非只看數值狀態。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasm實作與原始碼
kitaqfc/lib/asset.h:28
Copy the smaller of the asset length and max_len using a bank-aware transfer. Return one for a valid ID even when the payload is truncated.
kitaqfc/lib/asset.c:28
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len)
{
AssetDesc desc;
u16 len;
if (asset_get(asset_id, &desc) == 0) return 0;
len = desc.len;
if (len > max_len) len = max_len;
__far_memcpy((u8*)dst, desc.bank, (u16)desc.ptr, len);
return 1;
}asset_load_tiles
查找RAW或TILES素材,切換至其ROM區塊,使用__vram_write以每次最多128位元組傳送全部資料。最後恢復bank_get_current()保存的區塊。分段傳送不會等待下一影格。
語法
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。vram_dstPPU位元組位址,不是CPU位址或圖塊編號。圖塊圖案上傳使用
$0000–$1FFF內可寫入的CHR RAM,每個圖塊16位元組。整個傳送範圍必須位於預期的PPU區域內。
回傳值
ID無效或類型不是RAW/TILES時傳回0;接受並完成傳送後傳回1,長度為0也一樣。成功值不代表已驗證圖塊編碼或VRAM顯示正確。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
上傳只寫入位元組,不會在地圖上放置圖塊、設定顏色或配置VRAM。圖塊地圖與調色盤需要另外設定。範例會關閉繪製後上傳,準備好圖像才啟用顯示。
asset_load_tiles恢復的是bank.c記錄的區塊,而非從映射器讀回的值。請用bank_switch初始化並維護狀態;直接寫入映射器或僅呼叫__bankswitch不會更新函式庫的記錄。跨區塊複製內建函式則另外恢復編譯器保存的狀態。
圖案資料須使用可寫入的CHR RAM,大量上傳時應關閉繪製。若在VBlank期間上傳,整個操作必須在可用時間內完成;每次128位元組並不會自動保證這一點。範例使用--mapper=mmc1 --board=surom512。一般板型省略--nes-chr會產生空白CHR ROM,而不是CHR RAM。
使用範例
loaded=asset_load_tiles(0,0x0010); // 144 bytes: library uploads chunks of 128 and 16 bytes.
expect(loaded==1 && bank_get_current()==1 && *asset_bank_marker==0xA1,24);
// LCD and NMI are off; CHR RAM is writable. The library selects payload bank 2 and restores bank 1.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖塊上傳範例使用9個自製8×8圖案,共144位元組,並檢查MAP類型與無效ID會被拒絕。FC的144位元組傳送同時涵蓋128位元組區塊與剩餘16位元組。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
FC中,(16,64)的藍色三角形與方框顯示__far_memcpy結果,(16,96)的綠色一對顯示asset_load_raw後再上傳CHR的結果。每對在黑底上占16×8像素,可直接查看複製的圖像位元組是否正確,而非只看數值狀態。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasm實作與原始碼
kitaqfc/lib/asset.h:31
Switch to the asset bank, upload tile/raw data in chunks of at most 128 bytes, then restore the bank recorded by this library. The caller supplies safe PPU timing.
kitaqfc/lib/asset.c:41
u8 asset_load_tiles(u8 asset_id, u16 vram_dst)
{
AssetDesc desc;
const u8* src;
u16 len;
u8 chunk;
u8 old_bank;
if (asset_get(asset_id, &desc) == 0) return 0;
if (desc.type != ASSET_TYPE_TILES && desc.type != ASSET_TYPE_RAW) return 0;
// Restoration uses the library shadow, not a mapper readback; initialize and maintain that shadow.
old_bank = bank_get_current();
bank_switch(desc.bank);
src = desc.ptr;
len = desc.len;
// This loop uploads the entire asset synchronously. Chunking does not wait for another frame.
// Use writable CHR RAM for tile data and keep the source bank visible throughout the transfer.
while (len != 0) {
if (len > 128) chunk = 128;
else chunk = (u8)len;
__vram_write(vram_dst, src, chunk);
vram_dst = (u16)(vram_dst + chunk);
src = src + chunk;
len = (u16)(len - chunk);
}
bank_switch(old_bank);
return 1;
}asset_set_table
登記目前描述符表的區塊編號、位址與項目數。同一時間只保留一張表。此函式只保存這三個值,不複製表格、不讀取素材,也不配置記憶體。
語法
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);參數
bank描述符表所在的ROM區塊編號,使用8位元值;不是素材資料的編號。
table指向連續
count筆AssetDesc的近指標。登記有效期間,表格所在區塊中的count * 6位元組必須維持可讀取狀態。count項目數,範圍為0–255。設為0時所有ID皆無效;可用
asset_set_table(0, 0, 0)安全地登記空表。
回傳值
無(void)。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
使用範例
asset_set_table(3,asset_descriptors,4); // Four descriptors in bank 3, payloads in bank 2.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此例登記區塊3中的4筆描述符,非空素材資料位於區塊2。也會登記空表,確認查找失敗時不會讀取位址0。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
FC中,(16,64)的藍色三角形與方框顯示__far_memcpy結果,(16,96)的綠色一對顯示asset_load_raw後再上傳CHR的結果。每對在黑底上占16×8像素,可直接查看複製的圖像位元組是否正確,而非只看數值狀態。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasm實作與原始碼
kitaqfc/lib/asset.h:22
Retain a bank-qualified descriptor table; the caller keeps its storage valid.
kitaqfc/lib/asset.c:9
void asset_set_table(u8 bank, const AssetDesc* table, u8 count)
{
asset_table_bank = bank;
asset_table = table;
asset_table_count = count;
}attribute.h — 名稱表屬性
共用的 64 位元組屬性影子緩衝區佔用 CPU RAM $03E0..$041F,請保留此範圍。一個屬性位元組涵蓋 4×4 圖塊;每個兩位元欄位為一個 2×2 圖塊象限選擇調色盤。
以矩形編輯調色盤象限,只將相交的屬性位元組排入佇列,並檢查 32×30 圖塊邊界。palette_map 輸入是完成打包的 64 位元組屬性表,不是每圖塊一個色彩值。
nes_attr_queue_rect
將涵蓋圖塊矩形的屬性位元組各列複製到佇列。
語法
unsigned char nes_attr_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
tile_x左側圖塊欄,可見範圍為 0..31。
tile_y頂端圖塊列,可見範圍為 0..29。
width寬度,以圖塊為單位。
height高度,以圖塊為單位。
回傳值
全部排入或矩形為空時傳回 1;邊界無效或容量不足時傳回 0。無效邊界不會排入任何資料。
使用條件與限制
共用的 64 位元組屬性影子緩衝區佔用 CPU RAM $03E0..$041F,請保留此範圍。一個屬性位元組涵蓋 4×4 圖塊;每個兩位元欄位為一個 2×2 圖塊象限選擇調色盤。
請連結 runtime.c。佇列會複製資料,供之後的 NMI 或關閉繪圖時的安全提交使用。生產與消費操作須序列化。多列操作中若容量耗盡,先前成功加入的列仍留在佇列中。
一個屬性位元組涵蓋 4×4 圖塊。相交的整個位元組都會傳送,因此須在影子緩衝區保留鄰接象限的正確值。
使用範例
result[5]=nes_attr_queue_rect(0x2000,2,4,4,4);result[6]=nes_vram_queue_used;result[7]=nes_attr_queue_rect(0x2000,10,4,4,4);result[8]=nes_attr_queue_rect(0x2000,30,28,2,2);nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範矩形屬性上傳:在 (16,32) 顯示紅色 32×32、(80,32) 顯示藍色 32×32,右下角 (240,224) 顯示綠色 16×16 圖形。保留相鄰象限,並正確處理最後一個屬性位元組。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_attributes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_attributes.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/attribute.h:15
Queue the attribute bytes covering a tile rectangle within 32x30 tiles. Empty rectangles succeed; invalid bounds fail without queuing. Capacity failure may leave earlier rows queued.
kitaqfc/lib/attribute.c:81
unsigned char nes_attr_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height)
{
unsigned char qx0;
unsigned char qy0;
unsigned char qx1;
unsigned char qy1;
unsigned char row;
unsigned char col;
// The runtime queue copies these local bytes before return; they are not retained pointers.
// Caller coordinates must keep each computed row length within eight bytes.
unsigned char line[8];
unsigned short ppu_addr;
unsigned char len;
if (width == 0 || height == 0) return 1;
if (tile_x >= 32 || tile_y >= 30) return 0;
if (width > (unsigned char)(32 - tile_x) || height > (unsigned char)(30 - tile_y)) return 0;
qx0 = (unsigned char)(tile_x >> 2);
qy0 = (unsigned char)(tile_y >> 2);
qx1 = (unsigned char)((tile_x + width - 1) >> 2);
qy1 = (unsigned char)((tile_y + height - 1) >> 2);
row = qy0;
while (1)
{
len = (unsigned char)(qx1 - qx0 + 1);
col = 0;
while (col != len)
{
line[col] = nes_attr_shadow[(unsigned char)(row * 8 + qx0 + col)];
col = (unsigned char)(col + 1);
}
ppu_addr = (unsigned short)(nes_attr_base_from_nt(nt_base) + (unsigned short)(row * 8 + qx0));
if (nes_vram_queue_try_write(ppu_addr, line, len) == 0)
{
return 0;
}
if (row == qy1)
{
break;
}
row = (unsigned char)(row + 1);
}
return 1;
}nes_attr_shadow_build_from_palette_map
將已打包的 64 個屬性位元組複製到共用影子緩衝區。
語法
void nes_attr_shadow_build_from_palette_map(unsigned char* src64);參數
src64可讀取的 64 位元組打包屬性表,不是逐圖塊的調色盤 ID 陣列。
回傳值
無傳回值。
使用條件與限制
共用的 64 位元組屬性影子緩衝區佔用 CPU RAM $03E0..$041F,請保留此範圍。一個屬性位元組涵蓋 4×4 圖塊;每個兩位元欄位為一個 2×2 圖塊象限選擇調色盤。
使用範例
for(i=0;i<64;i++)table[i]=0;table[0]=0xE4;nes_attr_shadow_build_from_palette_map(table);result[0]=nes_attr_shadow[0];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範矩形屬性上傳:在 (16,32) 顯示紅色 32×32、(80,32) 顯示藍色 32×32,右下角 (240,224) 顯示綠色 16×16 圖形。保留相鄰象限,並正確處理最後一個屬性位元組。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_attributes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_attributes.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/attribute.h:8
KITAQFC phase15 attribute patch helpers. Copy 64 already-packed attribute bytes into shadow storage. This does not convert one palette ID per tile into NES attribute bitfields. The source must expose all 64 packed bytes and stay readable for the duration of this copy.
kitaqfc/lib/attribute.c:26
void nes_attr_shadow_build_from_palette_map(unsigned char* src64)
{
unsigned char i;
i = 0;
while (i != 64)
{
nes_attr_shadow[i] = (unsigned char)(src64[i] & 0xFF);
i = (unsigned char)(i + 1);
}
}nes_attr_shadow_fill_rect
替換矩形觸及的每個 2×2 圖塊象限之調色盤欄位。
語法
void nes_attr_shadow_fill_rect(unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pal_index);參數
tile_x左側圖塊欄,可見範圍為 0..31。
tile_y頂端圖塊列,可見範圍為 0..29。
width寬度,以圖塊為單位。
height高度,以圖塊為單位。
pal_index調色盤索引,只使用最低兩個位元。
回傳值
無傳回值。
使用條件與限制
共用的 64 位元組屬性影子緩衝區佔用 CPU RAM $03E0..$041F,請保留此範圍。一個屬性位元組涵蓋 4×4 圖塊;每個兩位元欄位為一個 2×2 圖塊象限選擇調色盤。
整個矩形須位於 32×30 圖塊範圍內。空矩形或無效矩形不會改變任何內容。奇數邊界會擴展至象限邊界,因此矩形外的鄰接圖塊也可能共用新調色盤。
使用範例
nes_attr_shadow_fill_rect(2,4,4,4,1);nes_attr_shadow_fill_rect(10,4,4,4,2);nes_attr_shadow_fill_rect(30,28,2,2,3);result[1]=nes_attr_shadow[8];result[2]=nes_attr_shadow[9];result[3]=nes_attr_shadow[15];result[4]=nes_attr_shadow[63];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範矩形屬性上傳:在 (16,32) 顯示紅色 32×32、(80,32) 顯示藍色 32×32,右下角 (240,224) 顯示綠色 16×16 圖形。保留相鄰象限,並正確處理最後一個屬性位元組。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_attributes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_attributes.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/attribute.h:11
Apply a palette to every two-by-two tile quadrant touched by the rectangle. Empty or out-of-range rectangles leave the shadow unchanged.
kitaqfc/lib/attribute.c:39
void nes_attr_shadow_fill_rect(unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pal_index)
{
unsigned char qx0;
unsigned char qy0;
unsigned char qx1;
unsigned char qy1;
unsigned char qx;
unsigned char qy;
if (width == 0 || height == 0) return;
if (tile_x >= 32 || tile_y >= 30) return;
if (width > (unsigned char)(32 - tile_x) || height > (unsigned char)(30 - tile_y)) return;
qx0 = nes_attr_rect_left(tile_x);
qy0 = nes_attr_rect_top(tile_y);
qx1 = nes_attr_rect_left((unsigned char)(tile_x + width - 1));
qy1 = nes_attr_rect_top((unsigned char)(tile_y + height - 1));
qy = qy0;
while (1)
{
qx = qx0;
while (1)
{
nes_attr_shadow_set_quad((unsigned char)(qx << 1), (unsigned char)(qy << 1), pal_index);
if (qx == qx1)
{
break;
}
qx = (unsigned char)(qx + 1);
}
if (qy == qy1)
{
break;
}
qy = (unsigned char)(qy + 1);
}
}audio.h — 音樂、音效與音訊控制
直接控制標準 APU 的兩個脈波、三角波、雜訊與 DMC。這不是音樂定序器或自動混音器;時序及通道使用權由遊戲管理。
此輔助函式寫入單通道 APU_STATUS 遮罩,會停用其他聲部,並非多聲部混音器。脈波/三角波的 period 是計時器值,數值越小音高越高。範例音高與時長以 NTSC 時序檢查。
DMC 從 $C000..$FFC0 中的 64 位元組邊界讀取 ROM。長度為 16*n+1 位元組,範圍 1..4081。這些函式不驗證對齊/範圍,也不切換記憶體庫。範例以 __aligned(64) 將原創資料放在固定記憶體庫 0,並在執行時檢查位置。
nes_apu_channel_enable
以指定遮罩取代全部五個 APU 通道的啟用狀態。
語法
void nes_apu_channel_enable(u8 mask);參數
mask完整 APU_STATUS 啟用遮罩。位元 0..4 選擇 pulse1、pulse2、triangle、noise、DMC;高位元會丟棄。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用範例
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}預期結果
依序聽到 pulse1、pulse2、triangle、noise、tick、move。NTSC 下計時器 253 約產生 440 Hz 脈波與 220 Hz 三角波。tick 約 111 Hz;move 約 174 Hz 且較早結束。最後一段為靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:17
Replace all five channel-enable bits in APU_STATUS; this is not an additive enable.
kitaqfc/lib/audio.c:43
void nes_apu_channel_enable(u8 mask)
{
APU_STATUS = (u8)(mask & 0x1F);
}nes_apu_init
停用影格 IRQ,啟用四個聲部並設定靜音控制值。DMC 維持停用。
語法
void nes_apu_init(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用範例
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}預期結果
依序聽到 pulse1、pulse2、triangle、noise、tick、move。NTSC 下計時器 253 約產生 440 Hz 脈波與 220 Hz 三角波。tick 約 111 Hz;move 約 174 Hz 且較早結束。最後一段為靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:15
Disable frame IRQs, enable the four tonal/noise channels and install quiet control defaults. DMC remains disabled.
kitaqfc/lib/audio.c:28
void nes_apu_init(void)
{
APU_FRAME = 0x40;
APU_STATUS = 0x0F;
SQ1_VOL = 0x10;
SQ1_SWEEP = 0x08;
SQ2_VOL = 0x10;
SQ2_SWEEP = 0x08;
TRI_LINEAR = 0x80;
NOISE_VOL = 0x10;
DMC_FREQ = 0x00;
DMC_RAW = 0x00;
}nes_apu_silence_all
停用所有通道,並清除脈波/雜訊音量與 DMC 輸出。
語法
void nes_apu_silence_all(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用範例
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}預期結果
依序聽到 pulse1、pulse2、triangle、noise、tick、move。NTSC 下計時器 253 約產生 440 Hz 脈波與 220 Hz 三角波。tick 約 111 Hz;move 約 174 Hz 且較早結束。最後一段為靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:19
Disable every channel and clear volume/DMC output settings used by this helper.
kitaqfc/lib/audio.c:49
void nes_apu_silence_all(void)
{
APU_STATUS = 0x00;
SQ1_VOL = 0x10;
SQ2_VOL = 0x10;
TRI_LINEAR = 0x80;
NOISE_VOL = 0x10;
DMC_FREQ = 0x00;
DMC_RAW = 0x00;
}nes_dmc_config
設定 DMC 控制/輸出,並將取樣資料位址與長度轉成暫存器單位。
語法
void nes_dmc_config(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);參數
flags_rateDMC 位元 7 為 IRQ、位元 6 為循環,低半位元組為速率索引。範例不啟用 IRQ。
output_level初始 DMC 輸出計數器,範圍 0..127;只寫入低七位元。
sample_addrDMC 資料 CPU 位址,須為 $C000..$FFC0 內的 64 位元組邊界。
sample_len位元組長度為 16*n+1,範圍 1..4081。請勿傳入零或無法表示的長度。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
DMC 從 $C000..$FFC0 中的 64 位元組邊界讀取 ROM。長度為 16*n+1 位元組,範圍 1..4081。這些函式不驗證對齊/範圍,也不切換記憶體庫。範例以 __aligned(64) 將原創資料放在固定記憶體庫 0,並在執行時檢查位置。
使用範例
// A 17-byte original delta pattern, aligned to a 64-byte DMC start boundary.
#include "fc_sound_example.h"
#pragma bank 0
__aligned(64) __prg_rom u8 delta[17]={0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xAA};
void main(void) {
sound_begin("DMC ORIGINAL DELTAS");
sound_result[0]=(u8)(((u16)delta&63)==0);
sound_result[1]=(u8)((u16)delta>=0xC000);
// Loop at NTSC rate index 10; start the output accumulator at its midpoint.
nes_dmc_config(0x4A,64,(u16)delta,17);
nes_dmc_start();
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
nes_dmc_play(0x4C,64,(u16)delta,17);
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
sound_end();
}預期結果
原創差分圖樣以速率 10 播放,暫停後再以較快的速率 12 播放。停止 DMC 會保留輸出計數器,因此間隔中可能有暫態聲。最後操作將整個 APU 靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_dmc.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-dmc.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:38
Convert a CPU sample address and byte length to DMC register units. Supply an address in 0xC000-0xFFC0 aligned to 64 bytes and a representable length 16*n+1 in 1..4081; inputs are narrowed without validation or bank management.
kitaqfc/lib/audio.c:115
void nes_dmc_config(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len)
{
DMC_FREQ = flags_rate;
DMC_RAW = (u8)(output_level & 0x7F);
// Keep the sample bytes mapped at these CPU addresses during playback; this does not select a ROM bank.
DMC_START = (u8)((sample_addr - 0xC000) >> 6);
DMC_LEN = (u8)((sample_len - 1) >> 4);
}nes_dmc_play
設定 DMC 取樣資料並立即開始播放。
語法
void nes_dmc_play(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);參數
flags_rateDMC 位元 7 為 IRQ、位元 6 為循環,低半位元組為速率索引。範例不啟用 IRQ。
output_level初始 DMC 輸出計數器,範圍 0..127;只寫入低七位元。
sample_addrDMC 資料 CPU 位址,須為 $C000..$FFC0 內的 64 位元組邊界。
sample_len位元組長度為 16*n+1,範圍 1..4081。請勿傳入零或無法表示的長度。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
DMC 從 $C000..$FFC0 中的 64 位元組邊界讀取 ROM。長度為 16*n+1 位元組,範圍 1..4081。這些函式不驗證對齊/範圍,也不切換記憶體庫。範例以 __aligned(64) 將原創資料放在固定記憶體庫 0,並在執行時檢查位置。
使用範例
// A 17-byte original delta pattern, aligned to a 64-byte DMC start boundary.
#include "fc_sound_example.h"
#pragma bank 0
__aligned(64) __prg_rom u8 delta[17]={0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xAA};
void main(void) {
sound_begin("DMC ORIGINAL DELTAS");
sound_result[0]=(u8)(((u16)delta&63)==0);
sound_result[1]=(u8)((u16)delta>=0xC000);
// Loop at NTSC rate index 10; start the output accumulator at its midpoint.
nes_dmc_config(0x4A,64,(u16)delta,17);
nes_dmc_start();
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
nes_dmc_play(0x4C,64,(u16)delta,17);
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
sound_end();
}預期結果
原創差分圖樣以速率 10 播放,暫停後再以較快的速率 12 播放。停止 DMC 會保留輸出計數器,因此間隔中可能有暫態聲。最後操作將整個 APU 靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_dmc.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-dmc.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:44
Install sample parameters, then start DMC using the full-channel enable mask.
kitaqfc/lib/audio.c:137
void nes_dmc_play(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len)
{
nes_dmc_config(flags_rate, output_level, sample_addr, sample_len);
nes_dmc_start();
}nes_dmc_start
寫入 APU_STATUS=0x1F,啟用 DMC 與其餘四個聲部。
語法
void nes_dmc_start(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
DMC 從 $C000..$FFC0 中的 64 位元組邊界讀取 ROM。長度為 16*n+1 位元組,範圍 1..4081。這些函式不驗證對齊/範圍,也不切換記憶體庫。範例以 __aligned(64) 將原創資料放在固定記憶體庫 0,並在執行時檢查位置。
使用範例
// A 17-byte original delta pattern, aligned to a 64-byte DMC start boundary.
#include "fc_sound_example.h"
#pragma bank 0
__aligned(64) __prg_rom u8 delta[17]={0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xAA};
void main(void) {
sound_begin("DMC ORIGINAL DELTAS");
sound_result[0]=(u8)(((u16)delta&63)==0);
sound_result[1]=(u8)((u16)delta>=0xC000);
// Loop at NTSC rate index 10; start the output accumulator at its midpoint.
nes_dmc_config(0x4A,64,(u16)delta,17);
nes_dmc_start();
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
nes_dmc_play(0x4C,64,(u16)delta,17);
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
sound_end();
}預期結果
原創差分圖樣以速率 10 播放,暫停後再以較快的速率 12 播放。停止 DMC 會保留輸出計數器,因此間隔中可能有暫態聲。最後操作將整個 APU 靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_dmc.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-dmc.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:40
Enable DMC together with all four other channels by replacing the status mask.
kitaqfc/lib/audio.c:125
void nes_dmc_start(void)
{
APU_STATUS = 0x1F;
}nes_dmc_stop
寫入 APU_STATUS=0x0F,停止 DMC,並設定其餘四個聲部的啟用位元。
語法
void nes_dmc_stop(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
DMC 從 $C000..$FFC0 中的 64 位元組邊界讀取 ROM。長度為 16*n+1 位元組,範圍 1..4081。這些函式不驗證對齊/範圍,也不切換記憶體庫。範例以 __aligned(64) 將原創資料放在固定記憶體庫 0,並在執行時檢查位置。
使用範例
// A 17-byte original delta pattern, aligned to a 64-byte DMC start boundary.
#include "fc_sound_example.h"
#pragma bank 0
__aligned(64) __prg_rom u8 delta[17]={0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xAA};
void main(void) {
sound_begin("DMC ORIGINAL DELTAS");
sound_result[0]=(u8)(((u16)delta&63)==0);
sound_result[1]=(u8)((u16)delta>=0xC000);
// Loop at NTSC rate index 10; start the output accumulator at its midpoint.
nes_dmc_config(0x4A,64,(u16)delta,17);
nes_dmc_start();
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
nes_dmc_play(0x4C,64,(u16)delta,17);
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
sound_end();
}預期結果
原創差分圖樣以速率 10 播放,暫停後再以較快的速率 12 播放。停止 DMC 會保留輸出計數器,因此間隔中可能有暫態聲。最後操作將整個 APU 靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_dmc.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-dmc.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:42
Disable DMC while leaving all four other channel-enable bits set.
kitaqfc/lib/audio.c:131
void nes_dmc_stop(void)
{
APU_STATUS = 0x0F;
}nes_sfx_move_blip
以控制值 0x5A、計時器 0x0280、長度索引 2 觸發脈波 1,產生更高、更短的移動提示聲。
語法
void nes_sfx_move_blip(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此輔助函式寫入單通道 APU_STATUS 遮罩,會停用其他聲部,並非多聲部混音器。脈波/三角波的 period 是計時器值,數值越小音高越高。範例音高與時長以 NTSC 時序檢查。
使用範例
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}預期結果
依序聽到 pulse1、pulse2、triangle、noise、tick、move。NTSC 下計時器 253 約產生 440 Hz 脈波與 220 Hz 三角波。tick 約 111 Hz;move 約 174 Hz 且較早結束。最後一段為靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:33
Trigger the predefined pulse-1 movement effect.
kitaqfc/lib/audio.c:107
void nes_sfx_move_blip(void)
{
nes_sfx_square1(0x5A, 0x0280, 2);
}nes_sfx_noise
只啟用雜訊,寫入包絡、週期/模式與長度索引。
語法
void nes_sfx_noise(u8 volume, u8 period_mode, u8 length_index);參數
volume原始雜訊控制:位元 5 停止長度計數,位元 4 為固定音量,低半位元組為音量或包絡週期。
period_mode雜訊暫存器:位元 7 為短模式,低半位元組為週期表索引。
length_index長度表索引 0..31,不是影格數。只有低五位元寫入暫存器。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此輔助函式寫入單通道 APU_STATUS 遮罩,會停用其他聲部,並非多聲部混音器。脈波/三角波的 period 是計時器值,數值越小音高越高。範例音高與時長以 NTSC 時序檢查。
使用範例
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}預期結果
依序聽到 pulse1、pulse2、triangle、noise、tick、move。NTSC 下計時器 253 約產生 440 Hz 脈波與 220 Hz 三角波。tick 約 111 Hz;move 約 174 Hz 且較早結束。最後一段為靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:29
Enable only noise and load envelope/control, period/mode and length fields.
kitaqfc/lib/audio.c:92
void nes_sfx_noise(u8 volume, u8 period_mode, u8 length_index)
{
APU_STATUS = 0x08;
NOISE_VOL = volume;
NOISE_LO = period_mode;
NOISE_HI = (u8)(length_index << 3);
}nes_sfx_square1
只啟用脈波 1,停用掃頻,並寫入控制、計時器與長度索引。
語法
void nes_sfx_square1(u8 duty_volume, u16 period, u8 length_index);參數
duty_volume原始脈波控制值:位元 7..6 為工作週期,位元 5 停止長度計數,位元 4 啟用固定音量,低半位元組為音量或包絡週期。
period11 位元計時器,範圍 0..2047。脈波頻率為 CPU 時脈/[16*(period+1)],三角波為 CPU 時脈/[32*(period+1)]。
length_index長度表索引 0..31,不是影格數。只有低五位元寫入暫存器。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此輔助函式寫入單通道 APU_STATUS 遮罩,會停用其他聲部,並非多聲部混音器。脈波/三角波的 period 是計時器值,數值越小音高越高。範例音高與時長以 NTSC 時序檢查。
使用範例
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}預期結果
依序聽到 pulse1、pulse2、triangle、noise、tick、move。NTSC 下計時器 253 約產生 440 Hz 脈波與 220 Hz 三角波。tick 約 111 Hz;move 約 174 Hz 且較早結束。最後一段為靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:23
Enable only pulse 1, disable its sweep and load control, 11-bit timer and length-table index. Starting this effect disables the other APU channels.
kitaqfc/lib/audio.c:62
void nes_sfx_square1(u8 duty_volume, u16 period, u8 length_index)
{
APU_STATUS = 0x01;
SQ1_SWEEP = 0x08;
SQ1_VOL = duty_volume;
SQ1_LO = (u8)period;
// Only the low five length-index bits and low eleven timer bits reach the registers.
SQ1_HI = (u8)((u8)(length_index << 3) | (u8)((period >> 8) & 0x07));
}nes_sfx_square2
只啟用脈波 2,停用掃頻,並寫入控制、計時器與長度索引。
語法
void nes_sfx_square2(u8 duty_volume, u16 period, u8 length_index);參數
duty_volume原始脈波控制值:位元 7..6 為工作週期,位元 5 停止長度計數,位元 4 啟用固定音量,低半位元組為音量或包絡週期。
period11 位元計時器,範圍 0..2047。脈波頻率為 CPU 時脈/[16*(period+1)],三角波為 CPU 時脈/[32*(period+1)]。
length_index長度表索引 0..31,不是影格數。只有低五位元寫入暫存器。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此輔助函式寫入單通道 APU_STATUS 遮罩,會停用其他聲部,並非多聲部混音器。脈波/三角波的 period 是計時器值,數值越小音高越高。範例音高與時長以 NTSC 時序檢查。
使用範例
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}預期結果
依序聽到 pulse1、pulse2、triangle、noise、tick、move。NTSC 下計時器 253 約產生 440 Hz 脈波與 220 Hz 三角波。tick 約 111 Hz;move 約 174 Hz 且較早結束。最後一段為靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:25
Enable only pulse 2 and load its control/timer/length fields, disabling other channels.
kitaqfc/lib/audio.c:73
void nes_sfx_square2(u8 duty_volume, u16 period, u8 length_index)
{
APU_STATUS = 0x02;
SQ2_SWEEP = 0x08;
SQ2_VOL = duty_volume;
SQ2_LO = (u8)period;
SQ2_HI = (u8)((u8)(length_index << 3) | (u8)((period >> 8) & 0x07));
}nes_sfx_tick_blip
以控制值 0x9A、計時器 0x03F0、長度索引 4 觸發脈波 1,產生短低音提示聲。
語法
void nes_sfx_tick_blip(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此輔助函式寫入單通道 APU_STATUS 遮罩,會停用其他聲部,並非多聲部混音器。脈波/三角波的 period 是計時器值,數值越小音高越高。範例音高與時長以 NTSC 時序檢查。
使用範例
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}預期結果
依序聽到 pulse1、pulse2、triangle、noise、tick、move。NTSC 下計時器 253 約產生 440 Hz 脈波與 220 Hz 三角波。tick 約 111 Hz;move 約 174 Hz 且較早結束。最後一段為靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:31
Trigger the predefined pulse-1 tick effect; it inherits the exclusive-channel behavior.
kitaqfc/lib/audio.c:101
void nes_sfx_tick_blip(void)
{
nes_sfx_square1(0x9A, 0x03F0, 4);
}nes_sfx_triangle
只啟用三角波,寫入線性計數器、計時器與長度索引。
語法
void nes_sfx_triangle(u8 linear, u16 period, u8 length_index);參數
linear三角波線性計數器:位元 7 為控制/長度停止,低七位元為重載值。
period11 位元計時器,範圍 0..2047。脈波頻率為 CPU 時脈/[16*(period+1)],三角波為 CPU 時脈/[32*(period+1)]。
length_index長度表索引 0..31,不是影格數。只有低五位元寫入暫存器。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此輔助函式寫入單通道 APU_STATUS 遮罩,會停用其他聲部,並非多聲部混音器。脈波/三角波的 period 是計時器值,數值越小音高越高。範例音高與時長以 NTSC 時序檢查。
使用範例
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}預期結果
依序聽到 pulse1、pulse2、triangle、noise、tick、move。NTSC 下計時器 253 約產生 440 Hz 脈波與 220 Hz 三角波。tick 約 111 Hz;move 約 174 Hz 且較早結束。最後一段為靜音。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio.h:27
Enable only triangle and load linear-counter, timer and length fields.
kitaqfc/lib/audio.c:83
void nes_sfx_triangle(u8 linear, u16 period, u8 length_index)
{
APU_STATUS = 0x04;
TRI_LINEAR = linear;
TRI_LO = (u8)period;
TRI_HI = (u8)((u8)(length_index << 3) | (u8)((period >> 8) & 0x07));
}audio_vblank.h — 由 NMI 驅動的四聲道音樂
四聲道音樂在 NMI 中推進。先初始化、設定曲目並預先填入佇列,再啟用 NMI 播放,之後由主程式持續補充。NMI 讀取 RAM 佇列,因此只要及時補充,少量 RAM 也能播放長串流。每個聲道都有獨立的 HOLD/STOP 命令。
每筆記錄包含五個位元組:delay, CH1, CH2, CH3, CH4。延遲值 1~255 表示新狀態持續的 NMI 節拍數;零會結束播放,並忽略其餘四個位元組。音符值 0~71 對應 C2~B7(24=C4)。雜訊值 0~15 選擇長模式的週期,16~31 則選擇短模式。所有聲道均以 255=NES_AUDIO_HOLD 維持原狀,以 254=NES_AUDIO_STOP 靜音。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
延遲結束卻沒有下一筆 BGM 記錄時,會停止 BGM 音符,待資料到達後於 NMI 恢復。獨立播放的 SFX 會繼續。計數的是進入資料不足狀態的次數,而非每個空佇列影格。只插入 HOLD 值不會恢復先前的 BGM 音符。通常應每影格補充一次,並在耗時工作前預先排入足夠長的播放資料。
| 等待時間 | CH1:脈衝波 1 | CH2:脈衝波 2 | CH3:三角波 | CH4:雜訊 |
|---|---|---|---|---|
| 24 | 24 (C4) | 12 (C3) | 0 (C2) | 2 |
nes_audio_vblank_init
初始化 APU 與佇列,重設播放、資料供應狀態及資料不足計數器。
語法
void nes_audio_vblank_init(void);回傳值
無傳回值。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
停用 APU 影格 IRQ、DMC 與脈衝波掃頻。預設設定為:脈衝波 1 使用 50% 占空比、音量 12;脈衝波 2 使用 25% 占空比、音量 10;三角波允許音符發聲;雜訊音量為 8。初始化不會啟動音樂或 NMI。
使用範例
nes_audio_vblank_init();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:19
Reset the queue, feeder and diagnostic counters; silence and initialize the APU. Owns the four basic channels and disables DMC and APU frame IRQs.
kitaqfc/lib/audio_vblank.c:67
void nes_audio_vblank_init(void){
nes_audio_vblank_stop();nav_underruns=0;nav_frame=0x40;
nav_sweep1=8;nav_sweep2=8;nav_dmc_flags=0;nav_dmc_level=0;
nav_timbre[0]=0xBC;nav_timbre[1]=0x7A;nav_timbre[2]=0xFF;nav_timbre[3]=0x38;
}nes_audio_vblank_enqueue
驗證一筆記錄並複製到 RAM 佇列。可用於直接在遊戲程式中產生音樂,而不使用 ROM 資料供應功能。
語法
u8 nes_audio_vblank_enqueue(const u8* record);參數
record五個可讀位元組的位址,必須在呼叫返回前保持有效。返回後即可重複使用來源陣列。null 會被拒絕。
回傳值
接受記錄時傳回 1。佇列已滿、指標為 null,或音符/雜訊值無效時,傳回 0 且不變更佇列。不會驗證結束記錄中的四個聲道位元組。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
40 位元組的 RAM 環狀緩衝區實際有八個槽位,但會保留一個空槽以區分全滿與全空,因此可容納七筆記錄。只允許主程式中的單一生產者寫入;請勿從 NMI 插入、補充或初始化佇列。生產者複製完整記錄後,才公布一位元組的寫入位置,避免 NMI 讀到不完整的記錄。
每筆記錄包含五個位元組:delay, CH1, CH2, CH3, CH4。延遲值 1~255 表示新狀態持續的 NMI 節拍數;零會結束播放,並忽略其餘四個位元組。音符值 0~71 對應 C2~B7(24=C4)。雜訊值 0~15 選擇長模式的週期,16~31 則選擇短模式。所有聲道均以 255=NES_AUDIO_HOLD 維持原狀,以 254=NES_AUDIO_STOP 靜音。
使用範例
result[6]=nes_audio_vblank_enqueue(quiet_record); // Copy five bytes into RAM.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:22
Copy one complete validated record to RAM and publish it atomically last. Return 1 on success, 0 for null/invalid/full. Call from one foreground producer.
kitaqfc/lib/audio_vblank.c:74
u8 nes_audio_vblank_enqueue(const u8* record){
u8 next;u8 i;u8 value;
nav_invalid=0;
if(record==0){nav_invalid=1;return 0;}
next=nav_head+5;if(next==40)next=0;
if(next==nav_tail)return 0;
if(record[0]!=0){
for(i=1;i<5;i++){
value=record[i];
if(value<254){
if(i<4){if(value>71){nav_invalid=1;return 0;}}
else{if(value>31){nav_invalid=1;return 0;}}
}
}
}
for(i=0;i<5;i++)nav_queue[(__safe_index u8)(nav_head+i)]=record[i];
nav_head=next;return 1;
}nes_audio_vblank_queued
傳回 NMI 尚未消耗的記錄數。
語法
u8 nes_audio_vblank_queued(void);回傳值
傳回佇列中的 BGM 記錄數,範圍為 0~7,不包含目前延遲及任何 SFX 記錄。NMI 會持續消耗資料,因此結果只代表讀取當下的狀態。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
40 位元組的 RAM 環狀緩衝區實際有八個槽位,但會保留一個空槽以區分全滿與全空,因此可容納七筆記錄。只允許主程式中的單一生產者寫入;請勿從 NMI 插入、補充或初始化佇列。生產者複製完整記錄後,才公布一位元組的寫入位置,避免 NMI 讀到不完整的記錄。
使用範例
result[1]=nes_audio_vblank_queued(); // Seven records after prefill.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:24
Return queued records (0..7), excluding the record whose delay is in progress.
kitaqfc/lib/audio_vblank.c:94
u8 nes_audio_vblank_queued(void){
u8 head;u8 tail;head=nav_head;tail=nav_tail;
if(head<tail)head=head+40;
return (head-tail)/5;
}nes_audio_vblank_free
傳回佇列中可放入記錄的空槽位數。
語法
u8 nes_audio_vblank_free(void);回傳值
傳回 BGM 可用槽位數 0~7,等於 7−queued()。這是槽位數,每個槽位佔五個位元組。獨立的 35 位元組 SFX 緩衝區不屬於此佇列。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
40 位元組的 RAM 環狀緩衝區實際有八個槽位,但會保留一個空槽以區分全滿與全空,因此可容納七筆記錄。只允許主程式中的單一生產者寫入;請勿從 NMI 插入、補充或初始化佇列。生產者複製完整記錄後,才公布一位元組的寫入位置,避免 NMI 讀到不完整的記錄。
使用範例
result[2]=nes_audio_vblank_free(); // No free slots immediately after prefill.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:26
Return available record slots (0..7), not bytes.
kitaqfc/lib/audio_vblank.c:99
u8 nes_audio_vblank_free(void){return 7-nes_audio_vblank_queued();}nes_audio_vblank_start
啟用 RAM 佇列的消耗處理,下次 NMI 會取出第一筆記錄。
語法
void nes_audio_vblank_start(void);回傳值
無傳回值。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
請先初始化並將記錄放入佇列。此呼叫不會啟用 NMI,也不會改變目前延遲或讀取位置。暫停後須用 pause(0) 恢復;單獨呼叫 start 不會解除暫停。
延遲結束卻沒有下一筆 BGM 記錄時,會停止 BGM 音符,待資料到達後於 NMI 恢復。獨立播放的 SFX 會繼續。計數的是進入資料不足狀態的次數,而非每個空佇列影格。只插入 HOLD 值不會恢復先前的 BGM 音符。通常應每影格補充一次,並在耗時工作前預先排入足夠長的播放資料。
使用範例
nes_audio_vblank_start(); // Consume the copied record on the next NMI.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:28
Enable consumption at the next NMI. Does not enable PPU NMI itself.
kitaqfc/lib/audio_vblank.c:100
void nes_audio_vblank_start(void){nav_active=1;}nes_audio_vblank_stop
停用播放、將四個聲道靜音,並捨棄佇列與 ROM 資料供應狀態。
語法
void nes_audio_vblank_stop(void);回傳值
無傳回值。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
停止 BGM 與 SFX,捨棄佇列、資料供應狀態、兩者的播放位置及暫停狀態。保留音色與資料不足計數器,且不會停用 NMI。若要保留位置,請使用 pause。set_music 與 play_music 內部也會執行此停止處理,因此會取消 SFX。
使用範例
nes_audio_vblank_stop(); // Clear the feeder and queued records; silence now.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:30
Disable consumption, silence, discard queued records and clear the feeder.
kitaqfc/lib/audio_vblank.c:29
void nes_audio_vblank_stop(void){
u8 i;
nav_paused=1;nav_active=0;nav_sfx_active=0;nav_status=0;
nav_delay=0;nav_enabled=0;nav_head=0;nav_tail=0;
nav_source=0;nav_cursor=0;nav_count=0;nav_left=0;nav_starved=0;
nav_previous_mask=0;nav_effective_mask=0;nav_refresh=0;
for(i=0;i<4;i++){nav_notes[(__safe_index u8)i]=254;nav_sfx_notes[(__safe_index u8)i]=254;}
nav_paused=0;
}nes_audio_vblank_set_music
停止播放並將串流設為資料供應來源。複製到佇列與啟動播放是另外兩項操作。
語法
u8 nes_audio_vblank_set_music(const u8* records,u16 count,u8 loop);參數
records串流在可讀 ROM 或 RAM 中的起始位址。請保留資料直到供應完成。函式不會切換記憶體庫,因此呼叫 refill 時必須映射正確的 ROM 記憶體庫。NMI 只會讀取已複製到 RAM 的記錄。
count可讀取的五位元組記錄數,範圍為 1~13107;不是位元組數。全部 count×5 個位元組必須位於連續且有效的 CPU 位址範圍內。
loop零表示播放一次,任何非零值都表示從頭重複播放。循環串流中不可包含延遲值為零的結束記錄。
回傳值
指標與數量有效時傳回 1;指標為 null、數量為零或超過 13107 時傳回 0。即使失敗,也會停止現有播放並捨棄佇列資料。記錄內容會在補充時檢查。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
每筆記錄包含五個位元組:delay, CH1, CH2, CH3, CH4。延遲值 1~255 表示新狀態持續的 NMI 節拍數;零會結束播放,並忽略其餘四個位元組。音符值 0~71 對應 C2~B7(24=C4)。雜訊值 0~15 選擇長模式的週期,16~31 則選擇短模式。所有聲道均以 255=NES_AUDIO_HOLD 維持原狀,以 254=NES_AUDIO_STOP 靜音。
使用範例
result[5]=nes_audio_vblank_set_music(song,8,0); // Attach without starting.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:33
Stop and attach a readable five-byte-record stream; return 0 for null, zero count or a count above 13107. Nonzero loop repeats the stream. Does not start.
kitaqfc/lib/audio_vblank.c:110
u8 nes_audio_vblank_set_music(const u8* records,u16 count,u8 loop){
nes_audio_vblank_stop();
if(records==0||count==0||count>13107)return 0;
nav_source=records;nav_cursor=records;nav_count=count;nav_left=count;nav_loop=loop;
return 1;
}nes_audio_vblank_refill
從已設定的串流取出最多七筆記錄,填入空槽位。主程式執行此操作,便可用小型 RAM 佇列播放長曲目。
語法
u8 nes_audio_vblank_refill(void);回傳值
傳回接受的記錄數 0~7,包含單次播放時自動附加的結束記錄。沒有來源或佇列已滿時傳回 0。遇到無效記錄時,會停止播放、捨棄佇列與資料供應狀態,並傳回 0。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
串流在可讀 ROM 或 RAM 中的起始位址。請保留資料直到供應完成。函式不會切換記憶體庫,因此呼叫 refill 時必須映射正確的 ROM 記憶體庫。NMI 只會讀取已複製到 RAM 的記錄。
零表示播放一次,任何非零值都表示從頭重複播放。循環串流中不可包含延遲值為零的結束記錄。
延遲結束卻沒有下一筆 BGM 記錄時,會停止 BGM 音符,待資料到達後於 NMI 恢復。獨立播放的 SFX 會繼續。計數的是進入資料不足狀態的次數,而非每個空佇列影格。只插入 HOLD 值不會恢復先前的 BGM 音符。通常應每影格補充一次,並在耗時工作前預先排入足夠長的播放資料。
ROM 資料供應與直接插入共用同一個佇列,只有在刻意安排順序時才應混用。補充資料本身不會播放記錄,也不會啟動消費端;但因無效資料而停止時,確實會將 APU 靜音。
使用範例
nes_audio_vblank_refill();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:37
Copy at most seven records from the attached stream. Return copies accepted. A one-shot feeder appends a delay-zero terminator after the last timed record. Keep the stream's ROM bank mapped during this foreground call only.
kitaqfc/lib/audio_vblank.c:118
u8 nes_audio_vblank_refill(void){
u8 copied;copied=0;
while(copied<7&&nav_source!=0){
if(nav_left==0){
if(nav_loop!=0){nav_cursor=nav_source;nav_left=nav_count;}
else {if(nes_audio_vblank_enqueue(nav_end)!=0){copied++;nav_source=0;}return copied;}
}
if(nes_audio_vblank_enqueue(nav_cursor)==0){
// The producer-only flag distinguishes malformed data from full.
// Re-reading occupancy here would race NMI freeing a full queue.
if(nav_invalid!=0){nes_audio_vblank_stop();return 0;}
return copied;
}
copied++;nav_cursor=nav_cursor+5;nav_left--;
}
return copied;
}nes_audio_vblank_play_music
一次呼叫即可設定曲目、預先填入佇列並啟用播放。這是啟動樂句時通常使用的入口。
語法
u8 nes_audio_vblank_play_music(const u8* records,u16 count,u8 loop);參數
records串流在可讀 ROM 或 RAM 中的起始位址。請保留資料直到供應完成。函式不會切換記憶體庫,因此呼叫 refill 時必須映射正確的 ROM 記憶體庫。NMI 只會讀取已複製到 RAM 的記錄。
count可讀取的五位元組記錄數,範圍為 1~13107;不是位元組數。全部 count×5 個位元組必須位於連續且有效的 CPU 位址範圍內。
loop零表示播放一次,任何非零值都表示從頭重複播放。循環串流中不可包含延遲值為零的結束記錄。
回傳值
設定與初次填入成功時傳回 1;設定無效,或初次填入時發現無效資料,則傳回 0。成功不代表整首曲目均已通過驗證;後面的錯誤記錄會在後續 refill 呼叫中才被發現。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
請先呼叫一次 init。play_music 會保留音色與資料不足計數器。較長或循環播放的串流仍須定期呼叫 refill。
使用範例
result[0]=nes_audio_vblank_play_music(song,8,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:39
Set the stream, prefill the queue and start. Return 0 for invalid setup/data.
kitaqfc/lib/audio_vblank.c:135
u8 nes_audio_vblank_play_music(const u8* records,u16 count,u8 loop){
if(nes_audio_vblank_set_music(records,count,loop)==0)return 0;
if(nes_audio_vblank_refill()==0)return 0;
nes_audio_vblank_start();return 1;
}nes_audio_vblank_is_playing
回報是否已啟用 NMI 佇列消耗處理。
語法
u8 nes_audio_vblank_is_playing(void);回傳值
BGM 消費端啟用時傳回 1,包括暫停與資料不足期間;停止或結束後傳回 0。僅有 SFX 播放時仍傳回 0。此值不表示實際是否發聲,也不表示 SFX 是否正在播放。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
延遲結束卻沒有下一筆 BGM 記錄時,會停止 BGM 音符,待資料到達後於 NMI 恢復。獨立播放的 SFX 會繼續。計數的是進入資料不足狀態的次數,而非每個空佇列影格。只插入 HOLD 值不會恢復先前的 BGM 音符。通常應每影格補充一次,並在耗時工作前預先排入足夠長的播放資料。
使用範例
while(nes_audio_vblank_is_playing()!=0){
// example:nes_audio_vblank_refill:start
nes_audio_vblank_refill();
// example:nes_audio_vblank_refill:end
__nmi_wait();
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:41
Return 1 while the BGM consumer is enabled, including a recoverable queue underrun.
kitaqfc/lib/audio_vblank.c:101
u8 nes_audio_vblank_is_playing(void){return nav_active;}nes_audio_vblank_underruns
傳回佇列資料不足事件次數,協助評估補充資料的時間餘裕。
語法
u8 nes_audio_vblank_underruns(void);回傳值
傳回 0~255,達 255 後不再增加。計算的是資料不足事件次數,而非等待中的每個影格。init 會清零,stop 與更換曲目則保留此值。正常的結束記錄不算資料不足。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
延遲結束卻沒有下一筆 BGM 記錄時,會停止 BGM 音符,待資料到達後於 NMI 恢復。獨立播放的 SFX 會繼續。計數的是進入資料不足狀態的次數,而非每個空佇列影格。只插入 HOLD 值不會恢復先前的 BGM 音符。通常應每影格補充一次,並在耗時工作前預先排入足夠長的播放資料。
使用範例
result[4]=nes_audio_vblank_underruns(); // Zero: queued time covered the busy section.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例會播放一次原創四聲道樂句。主程式連續 90 個影格執行整數運算而不補充佇列時,音樂仍會持續。“PHRASE COMPLETE / SILENT” 與 “UNDERRUNS 0 / MATH OK” 表示播放已結束、未發生佇列資料不足,且運算結果符合預期。請聆聽錄製的音訊,確認脈衝波旋律與伴奏、三角波低音及雜訊;結尾應為靜音。影像呈現控制結果,聲音則須透過音訊評估。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:43
Saturating count of starvation episodes, cleared by init; END is not starvation.
kitaqfc/lib/audio_vblank.c:102
u8 nes_audio_vblank_underruns(void){return nav_underruns;}nes_audio_vblank_set_timbre
設定聲道下一個音符的占空比或音量,不會重新觸發目前音符。
語法
u8 nes_audio_vblank_set_timbre(u8 channel,u8 control);參數
channel0=CH1 脈衝波 1、1=CH2 脈衝波 2、2=CH3 三角波、3=CH4 雜訊。4 以上的值會被拒絕。
control脈衝波以位元 7~6 選擇占空比(0=12.5%、1=25%、2=50%、3=75%),位元 3~0 設定固定音量 0~15。雜訊通常也將位元 3~0 當作固定音量。與 NES_AUDIO_NOISE_ENVELOPE(128)做 OR 後,這些位元便改為衰減週期 0~15:下一個雜訊音符從音量 15 開始,衰減一次。週期越大,衰減越慢;15 約需一秒。雜訊長度計數器會讓衰減完成。三角波設為零時,下一個音符靜音;非零則可發聲。
回傳值
聲道有效時傳回 1;值為 4 以上時,不做任何變更並傳回 0。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
使用範例
nes_audio_vblank_set_timbre(3,NES_AUDIO_NOISE_ENVELOPE|15);
result[3]=nes_audio_vblank_play_sfx(noise,1,8); // Bit 3 owns CH4; no BGM needed.
// The slow one-shot envelope fades by itself. It does not loop at zero.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
不需操作輸入。CH1 先播放約 220 Hz 的 BGM,再切換為約 880 Hz 的 SFX,持續 30 個影格後回到當時的 BGM。經過 30 個影格的靜音暫停後,BGM 恢復。第二個音效會在 15 個影格後明確中止。最後,CH4 雜訊會緩慢衰減一次。COMPLETE / ALL CHANNELS OFF 表示結束。請聆聽附加錄音,確認音高變化、靜音暫停及雜訊衰減。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank_effects.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank_effects.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:50
Configure the next note: pulse bits 7..6 select duty and 3..0 select volume; noise uses volume 3..0, or NES_AUDIO_NOISE_ENVELOPE | decay_period (0..15) for a one-shot hardware envelope (larger periods decay more slowly). The next noise note starts at volume 15; its length permits a full decay. Triangle uses zero for silent, nonzero for full level. Return 0 for channel >=4. Hardware has no triangle volume control.
kitaqfc/lib/audio_vblank.c:103
u8 nes_audio_vblank_set_timbre(u8 channel,u8 control){
if(channel>=4)return 0;
if(channel<2)nav_timbre[(__safe_index u8)channel]=(control&0xCF)|0x30;
else if(channel==2){if(control==0)nav_timbre[2]=0x80;else nav_timbre[2]=0xFF;}
else {if((control&128)!=0)nav_timbre[3]=control&15;else nav_timbre[3]=(control&15)|0x30;}
return 1;
}nes_audio_vblank_pause
保留播放位置,同時暫停或恢復 BGM 與 SFX。
語法
void nes_audio_vblank_pause(u8 on);參數
on非零表示暫停,零表示恢復。暫停時會立即停用四個 APU 聲道。
回傳值
無傳回值。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
請從主程式呼叫。NMI 會消耗已複製的 SFX 資料。BGM 與 SFX 都應交由此函式庫管理,請勿同時執行另一個 APU 驅動程式。
暫停時,BGM 的延遲與佇列位置、SFX 的延遲與播放位置都不會前進。主程式仍可補充資料。恢復後的第一次 NMI 會重新觸發目前音符,並推進一般節拍。波形相位及已衰減部分的包絡音量不會保存。is_playing 回報的 BGM 啟用旗標不變。即使已在播放,傳入零仍會要求還原音符,因此不要每影格呼叫。
使用範例
nes_audio_vblank_pause(1); // Freeze BGM and SFX, and mute immediately.
phase=3;wait_frames(30); // Refill may copy data; neither timeline advances.
nes_audio_vblank_pause(0); // Restore held notes on the next NMI.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
不需操作輸入。CH1 先播放約 220 Hz 的 BGM,再切換為約 880 Hz 的 SFX,持續 30 個影格後回到當時的 BGM。經過 30 個影格的靜音暫停後,BGM 恢復。第二個音效會在 15 個影格後明確中止。最後,CH4 雜訊會緩慢衰減一次。COMPLETE / ALL CHANNELS OFF 表示結束。請聆聽附加錄音,確認音高變化、靜音暫停及雜訊衰減。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank_effects.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank_effects.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:54
Any nonzero argument freezes both timelines and mutes immediately. Zero resumes from the stored delays and restores held notes on the next NMI. BGM is_playing remains enabled during pause. Refill may still fill the queue.
kitaqfc/lib/audio_vblank.c:40
void nes_audio_vblank_pause(u8 on){
if(on!=0){nav_paused=1;nav_status=0;}
else{nav_refresh=1;nav_paused=0;}
}nes_audio_vblank_play_sfx
將短音效複製到 RAM,從下次 NMI 起暫時接管所選聲道的輸出。
語法
u8 nes_audio_vblank_play_sfx(const u8* records,u8 count,u8 mask);參數
records五位元組記錄陣列的起始位址。呼叫返回前,須讓 count×5 個位元組保持可讀且已正確映射。複製完成後即可重複使用來源資料。
count1~7 筆記錄,最多 35 個位元組。每筆延遲都必須為 1~255。SFX 不使用延遲為零的結束記錄,而是在指定記錄全部播放完畢後結束。
mask以低四位元選擇聲道:1=CH1、2=CH2、4=CH3、8=CH4。可用 OR 組合多個位元來選擇多個聲道。高位元會被忽略;低四位元遮罩為零時會被拒絕。
回傳值
複製並啟用音效後傳回 1。指標為 null、數量無效、未選取聲道、延遲為零,或音符/雜訊值無效時傳回 0。無效輸入不會改變目前音效。未選取聲道的值也會接受驗證。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
請從主程式呼叫。NMI 會消耗已複製的 SFX 資料。BGM 與 SFX 都應交由此函式庫管理,請勿同時執行另一個 APU 驅動程式。
BGM 仍會在底層持續前進;音效結束後,輸出會回到當時的 BGM 音符。只有一個 SFX 串流,新呼叫會取代它。HOLD/STOP 值與 BGM 相同,但音效保留的音符初始為停止狀態,因此開頭的 HOLD 不會繼承 BGM 音符。SFX 可獨立於 BGM 播放。暫停時加入的音效會等到恢復才播放。音色與 BGM 共用。
使用範例
result[1]=nes_audio_vblank_play_sfx(effect,1,1); // Mask bit 0 owns CH1.
// The BGM timeline keeps advancing; its current CH1 note returns after 30 ticks.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
不需操作輸入。CH1 先播放約 220 Hz 的 BGM,再切換為約 880 Hz 的 SFX,持續 30 個影格後回到當時的 BGM。經過 30 個影格的靜音暫停後,BGM 恢復。第二個音效會在 15 個影格後明確中止。最後,CH4 雜訊會緩慢衰減一次。COMPLETE / ALL CHANNELS OFF 表示結束。請聆聽附加錄音,確認音高變化、靜音暫停及雜訊衰減。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank_effects.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank_effects.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:62
Copy 1..7 timed records. Bits 0..3 select channels temporarily owned by SFX. BGM continues underneath and its current notes return when the effect ends. Return 1 after copying; 0 for null, invalid count/data or an empty low mask. Ignore mask bits 4..7. All fields are validated, even unselected channels. Delay zero is not accepted for SFX. Invalid input preserves the current SFX. Replacement restarts the effect; the first HOLD starts from a stopped note. The source need only stay mapped/readable until this foreground call returns.
kitaqfc/lib/audio_vblank.c:47
u8 nes_audio_vblank_play_sfx(const u8* records,u8 count,u8 mask){
u8 i;u8 ch;u8 value;u8 bytes;
if(records==0||count==0||count>7||(mask&15)==0)return 0;
bytes=(u8)(count+count+count+count+count);
i=0;
while(i<bytes){
if(records[i]==0)return 0;
ch=1;while(ch<5){
value=records[i+ch];
if(value<254){if(ch<4){if(value>71)return 0;}else{if(value>31)return 0;}}
ch++;
}
i=i+5;
}
nav_sfx_active=0;
for(i=0;i<bytes;i++)nav_sfx_queue[(__safe_index u8)i]=records[i];
for(i=0;i<4;i++)nav_sfx_notes[(__safe_index u8)i]=254;
nav_sfx_mask=mask&15;nav_sfx_cursor=0;nav_sfx_length=bytes;nav_sfx_delay=0;
nav_sfx_active=1;return 1;
}nes_audio_vblank_stop_sfx
解除音效的聲道使用權,讓下次 NMI 還原目前的 BGM 音符。
語法
void nes_audio_vblank_stop_sfx(void);回傳值
無傳回值。
使用條件與限制
請包含 audio_vblank.h,並在建置時加入一次 audio_vblank.c。無論使用預設或自訂 NMI 處理常式,編譯器都會讓它呼叫一次音樂掛鉤。請啟用 PPU NMI。主迴圈不必呼叫音樂更新常式。
此四聲道驅動程式針對 NTSC 調校:CH1=脈衝波 1、CH2=脈衝波 2、CH3=三角波、CH4=雜訊,索引為 0~3。不支援 DMC 或擴充音源。請勿與直接寫入 APU 的程式同時使用,例如 audio.c 中的音效。它不提供 PAL 音高表或節奏校正。
請從主程式呼叫。NMI 會消耗已複製的 SFX 資料。BGM 與 SFX 都應交由此函式庫管理,請勿同時執行另一個 APU 驅動程式。
此呼叫不會寫入 APU 暫存器,並保留 BGM 佇列、位置及啟用狀態。若原本只有 SFX 在播放,下次 NMI 會讓聲道回到音符停止狀態。暫停期間的變更會在恢復時生效。若要立即靜音並捨棄兩者的播放位置,請使用 stop。
使用範例
nes_audio_vblank_stop_sfx(); // Release effect ownership at the next NMI.
// BGM continues at its current position; this does not restart the song.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
不需操作輸入。CH1 先播放約 220 Hz 的 BGM,再切換為約 880 Hz 的 SFX,持續 30 個影格後回到當時的 BGM。經過 30 個影格的靜音暫停後,BGM 恢復。第二個音效會在 15 個影格後明確中止。最後,CH4 雜訊會緩慢衰減一次。COMPLETE / ALL CHANNELS OFF 表示結束。請聆聽附加錄音,確認音高變化、靜音暫停及雜訊衰減。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank_effects.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank_effects.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/audio_vblank.h:65
Release effect ownership at the next NMI, restoring current BGM notes. This does not stop or restart the BGM and does not write the APU immediately.
kitaqfc/lib/audio_vblank.c:44
void nes_audio_vblank_stop_sfx(void){nav_sfx_active=0;}bank.h — 考慮 bank 的程式碼與資料存取
ROM 區塊是映射到 CPU 位址空間的一塊卡匣儲存區域。不同區塊可出現在相同 CPU 位址,因此只靠 16 位元指標無法確定跨區塊資料。BankPtr 是緊密排列的三位元組描述子,包含一位元組區塊編號與兩位元組指標。使用 farptr_make 建立,再透過 farptr_read8、farptr_read16 或 farptr_read 存取資料。
FC 範例使用 MMC3 邏輯區塊:區塊 0 的共用程式碼位於 $C000–$FFFF,選定的 16 KiB 區塊映射到 $8000–$BFFF。這是編譯器編號,不是 mapper 以 8 KiB 為單位的原始暫存器值。請用 bank_switch 初始化函式庫記錄。FC 的 far_call 是具名函式呼叫巨集;應傳入函式所在區塊,建議透過 __bankof 取得編號。
bank_get_current
傳回 bank_switch 最後記錄的區塊編號。讀取的是軟體記錄,而非卡匣暫存器。
語法
u8 bank_get_current(void);回傳值
bank_switch 最近保存的 u8 值;初始化前為 0。
使用條件與限制
函式庫記錄初值為 0,不會查詢卡匣啟動時的映射。請用 bank_switch 初始化。直接呼叫切換內建函式或寫入 mapper 不會更新這份獨立記錄,因此 bank_get_current 無法驗證實際硬體映射。
使用範例
starting_bank=bank_get_current(); // Last value recorded by bank_switch.
bank_expect(starting_bank==2,1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
最初的 bank_switch(2) 記錄並選擇區塊 2。之後直接切換到區塊 1,從 home1 讀到 A1,而 bank_get_current 仍回報 2。切回後,home2 再次讀出 B2。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:18
Read this wrapper's bank shadow; arbitrary mapper writes do not update it.
kitaqfc/lib/bank.c:14
u8 bank_get_current(void)
{
return kq_bank_current;
}bank_switch
先在函式庫中記錄要求的區塊編號,再透過編譯器對應目前 mapper 的 PRG 切換程序選取它。
語法
void bank_switch(u8 bank);參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
回傳值
無(void)。
使用條件與限制
持續生效的區塊切換不能使目前程式碼或返回位址失去映射。請如範例所示,將呼叫位置、使用的 bank_switch 本體及後續程式碼放在共用或固定區塊 0。
函式庫記錄初值為 0,不會查詢卡匣啟動時的映射。請用 bank_switch 初始化。直接呼叫切換內建函式或寫入 mapper 不會更新這份獨立記錄,因此 bank_get_current 無法驗證實際硬體映射。
FC 切換編號是編譯器的邏輯編號。0 表示共用 ROM,不是切換目標;輔助程式將 0 視為區塊 1。SUROM512 僅允許 1–30:直接傳給切換內建函式的越界常數會導致建置錯誤;無效執行時值會退回 1 並設定 mapper 故障狀態。共用 ROM 應直接讀取,不要要求切換到區塊 0。
使用範例
bank_switch(2); // Select the payload window and update library bookkeeping.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
最初的 bank_switch(2) 記錄並選擇區塊 2。之後直接切換到區塊 1,從 home1 讀到 A1,而 bank_get_current 仍回報 2。切回後,home2 再次讀出 B2。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:16
Record the bank in the library shadow and invoke the mapper-aware compiler intrinsic.
kitaqfc/lib/bank.c:7
void bank_switch(u8 bank)
{
kq_bank_current = bank;
__bankswitch(bank);
}far_call
展開為 __farcall((bank), func)。此巨集保留編譯器可識別的函式名稱,不執行回呼指標的間接呼叫。
語法
#define far_call(bank, func) __farcall((bank), func)參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
func已宣告的無參數函式名稱。此具名呼叫內建函式不接受保存函式位址的變數。bank 引數不會作為回呼參數傳入。
回傳值
結果型別由被呼叫函式決定。void 回呼不傳回值;u8 與 u16 回呼傳回對應純量值。展示的範例使用 void 回呼。
使用條件與限制
這些呼叫不傳遞使用者引數,也不會自動使回呼可在中斷中重入。請正確管理回呼自身的資料、堆疊與中斷使用。還原區塊的呼叫路徑已測試巢狀及重複呼叫;此範例不涵蓋實機或任意中斷交錯。
FC 切換編號是編譯器的邏輯編號。0 表示共用 ROM,不是切換目標;輔助程式將 0 視為區塊 1。SUROM512 僅允許 1–30:直接傳給切換內建函式的越界常數會導致建置錯誤;無效執行時值會退回 1 並設定 mapper 故障狀態。共用 ROM 應直接讀取,不要要求切換到區塊 0。
使用範例
far_call(3,callback); // No arguments; callback reads payload[0] in bank 3.
bank_expect(callback_count==1 && callback_byte==0xD3,15);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在完整程式的此處,far_call 使 callback_count 達到 1。回呼從區塊 3 讀取 D3。隨後透過近指標讀取 home2 並確認 B2,驗證傳回時已還原區塊 2。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:36
far_data_read
透過遠端記憶體複製內建函式,將指定 ROM 區塊的 len 個位元組複製到呼叫端提供的 RAM,並在傳回前還原原區塊。
語法
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
addr指向所選ROM區塊中可讀取位元組的近指標,指標本身不含區塊編號。
dst目標可寫入記憶體,容量必須足以容納實際複製的全部位元組。除了零位元組傳送外,不會檢查null或無效目標位址。
len位元組數,範圍0–65535。設為0時不複製記憶體,但仍會執行區塊選取與恢復。
回傳值
無(void)。
使用條件與限制
整個來源範圍必須在預期ROM映射中可讀取,整個目標範圍必須可寫入。複製不會在區塊視窗邊界自動切換至下一區塊,不提供memmove式的重疊處理,也不控制VRAM安全寫入時機。寫入VRAM請使用圖形傳送API。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
FC 切換編號是編譯器的邏輯編號。0 表示共用 ROM,不是切換目標;輔助程式將 0 視為區塊 1。SUROM512 僅允許 1–30:直接傳給切換內建函式的越界常數會導致建置錯誤;無效執行時值會退回 1 並設定 mapper 故障狀態。共用 ROM 應直接讀取,不要要求切換到區塊 0。
使用範例
far_data_read(3,payload,buffer,4); // Copy into four writable RAM bytes.
bank_expect(buffer[0]==0xD3 && buffer[1]==0x7A && buffer[2]==0x5C && buffer[3]==0x96,7);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此片段透過 far_data_read 複製 4 個位元組,並將緩衝區與 D3 7A 5C 96 比較。呼叫端的來源描述子或指標維持不變;完整程式還分別檢查零長度複製與區塊還原。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:24
Copy len bytes from banked ROM to caller-owned writable storage.
kitaqfc/lib/bank.c:32
void far_data_read(u8 bank, const void* addr, void* dst, u16 len)
{
__far_memcpy((u8*)dst, bank, (u16)addr, len);
}far_data_read16
透過 __farpeek16 讀取連續兩個位元組,組成小端序字組。第一個位元組對應低 8 位元。
語法
u16 far_data_read16(u8 bank, const void* addr);參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
addr指向所選ROM區塊中可讀取位元組的近指標,指標本身不含區塊編號。
回傳值
以 u16(0–65535)傳回讀到的小端序字組。
使用條件與限制
目標位元組或字組的全部內容必須在選定 CPU 映射中可讀取。這些讀取不檢查指標、不裁切位址,也不會在視窗邊界自動切換到下一個 ROM 區塊。讀取一個字組需要連續兩個有效位元組。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
FC 切換編號是編譯器的邏輯編號。0 表示共用 ROM,不是切換目標;輔助程式將 0 視為區塊 1。SUROM512 僅允許 1–30:直接傳給切換內建函式的越界常數會導致建置錯誤;無效執行時值會退回 1 並設定 mapper 故障狀態。共用 ROM 應直接讀取,不要要求切換到區塊 0。
使用範例
word_value=far_data_read16(3,payload+1); // Little-endian 7A 5C -> 0x5C7A.
bank_expect(word_value==0x5C7A,6);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式片段使用 far_data_read16 讀取區塊 3 中的 payload+1 並檢查 5C7A。完整程式還透過近指標讀取 home2,確認已還原區塊 2 的映射。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:22
Read a 16-bit value through the bank-aware compiler intrinsic.
kitaqfc/lib/bank.c:26
u16 far_data_read16(u8 bank, const void* addr)
{
return __farpeek16(bank, (u16)addr);
}far_data_read8
透過 __farpeek8 從指定 ROM 區塊與位址讀取一個位元組,還原原區塊後傳回該值。
語法
u8 far_data_read8(u8 bank, const void* addr);參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
addr指向所選ROM區塊中可讀取位元組的近指標,指標本身不含區塊編號。
回傳值
以 u8(0–255)傳回讀到的位元組。
使用條件與限制
目標位元組或字組的全部內容必須在選定 CPU 映射中可讀取。這些讀取不檢查指標、不裁切位址,也不會在視窗邊界自動切換到下一個 ROM 區塊。讀取一個字組需要連續兩個有效位元組。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
FC 切換編號是編譯器的邏輯編號。0 表示共用 ROM,不是切換目標;輔助程式將 0 視為區塊 1。SUROM512 僅允許 1–30:直接傳給切換內建函式的越界常數會導致建置錯誤;無效執行時值會退回 1 並設定 mapper 故障狀態。共用 ROM 應直接讀取,不要要求切換到區塊 0。
使用範例
byte_value=far_data_read8(3,payload); // One byte: 0xD3.
bank_expect(byte_value==0xD3,5);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式片段使用 far_data_read8 讀取區塊 3 中的 payload 並檢查 D3。完整程式還透過近指標讀取 home2,確認已還原區塊 2 的映射。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:20
Read one byte from an explicit ROM bank and 16-bit CPU address.
kitaqfc/lib/bank.c:20
u8 far_data_read8(u8 bank, const void* addr)
{
return __farpeek8(bank, (u16)addr);
}farptr_make
將一個位元組的區塊編號與 CPU 可見指標寫入呼叫端的 BankPtr。此操作只建立描述子,不切換區塊,也不讀取指向的資料。
語法
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);參數
out指向可寫入一筆三位元組 BankPtr 的儲存空間。out 為 null 時不執行寫入。
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
ptr要保存到描述子中的 CPU 可見 16 位元位址。依原值保存,不檢查該位址是否存在於指定區塊中。
回傳值
無(void)。
使用範例
farptr_make(&pointer,3,payload+1); // Store a bank and address; do not read ROM.
bank_expect(pointer.bank==3 && pointer.ptr==payload+1,8);
farptr_make(0,1,home1); // A null destination is ignored.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
描述子設為區塊 3 與 payload+1。後續讀取分別得到 7A、5C7A 與三個位元組 7A 5C 96。輸出為 null 的呼叫不得改變狀態。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:26
Store a bank/address pair without reading memory; null output is ignored.
kitaqfc/lib/bank.c:38
void farptr_make(BankPtr* out, u8 bank, const u8* ptr)
{
if (out == 0) return;
out->bank = bank;
out->ptr = ptr;
}farptr_read
從 BankPtr 指向的位置向可寫入 RAM 複製 len 個位元組。描述子以值傳遞,因此呼叫端的指標仍指向來源資料起點。
語法
void farptr_read(BankPtr ptr, void* dst, u16 len);參數
ptr包含 bank 與 ptr 的 BankPtr 值。傳入描述子本身,而非它的位址。呼叫端的描述子不會被修改。
dst目標可寫入記憶體,容量必須足以容納實際複製的全部位元組。除了零位元組傳送外,不會檢查null或無效目標位址。
len位元組數,範圍0–65535。設為0時不複製記憶體,但仍會執行區塊選取與恢復。
回傳值
無(void)。
使用條件與限制
整個來源範圍必須在預期ROM映射中可讀取,整個目標範圍必須可寫入。複製不會在區塊視窗邊界自動切換至下一區塊,不提供memmove式的重疊處理,也不控制VRAM安全寫入時機。寫入VRAM請使用圖形傳送API。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
FC 切換編號是編譯器的邏輯編號。0 表示共用 ROM,不是切換目標;輔助程式將 0 視為區塊 1。SUROM512 僅允許 1–30:直接傳給切換內建函式的越界常數會導致建置錯誤;無效執行時值會退回 1 並設定 mapper 故障狀態。共用 ROM 應直接讀取,不要要求切換到區塊 0。
使用範例
farptr_read(pointer,buffer,3);
bank_expect(buffer[0]==0x7A && buffer[1]==0x5C && buffer[2]==0x96,11);
bank_expect(pointer.bank==3 && pointer.ptr==payload+1,23);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此片段透過 farptr_read 複製 3 個位元組,並將緩衝區與 7A 5C 96 比較。呼叫端的來源描述子或指標維持不變;完整程式還分別檢查零長度複製與區塊還原。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:32
Copy len bytes from a far pointer; the caller provides a sufficiently large destination.
kitaqfc/lib/bank.c:58
void farptr_read(BankPtr ptr, void* dst, u16 len)
{
__far_memcpy((u8*)dst, ptr.bank, (u16)ptr.ptr, len);
}farptr_read16
從 BankPtr 保存的區塊與位址讀取小端序字組。描述子以值傳遞,指標不會向前移動。
語法
u16 farptr_read16(BankPtr ptr);參數
ptr包含 bank 與 ptr 的 BankPtr 值。傳入描述子本身,而非它的位址。呼叫端的描述子不會被修改。
回傳值
以 u16(0–65535)傳回讀到的小端序字組。
使用條件與限制
目標位元組或字組的全部內容必須在選定 CPU 映射中可讀取。這些讀取不檢查指標、不裁切位址,也不會在視窗邊界自動切換到下一個 ROM 區塊。讀取一個字組需要連續兩個有效位元組。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
FC 切換編號是編譯器的邏輯編號。0 表示共用 ROM,不是切換目標;輔助程式將 0 視為區塊 1。SUROM512 僅允許 1–30:直接傳給切換內建函式的越界常數會導致建置錯誤;無效執行時值會退回 1 並設定 mapper 故障狀態。共用 ROM 應直接讀取,不要要求切換到區塊 0。
使用範例
bank_expect(farptr_read16(pointer)==0x5C7A,10);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式片段使用 farptr_read16 讀取區塊 3 中的 pointer.ptr 並檢查 5C7A。完整程式還透過近指標讀取 home2,確認已還原區塊 2 的映射。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:30
Read a 16-bit value using both components of the far pointer.
kitaqfc/lib/bank.c:52
u16 farptr_read16(BankPtr ptr)
{
return __farpeek16(ptr.bank, (u16)ptr.ptr);
}farptr_read8
使用以值傳遞的 BankPtr 之兩個欄位讀取一個位元組。描述子提供一般近指標不包含的區塊編號。
語法
u8 farptr_read8(BankPtr ptr);參數
ptr包含 bank 與 ptr 的 BankPtr 值。傳入描述子本身,而非它的位址。呼叫端的描述子不會被修改。
回傳值
以 u8(0–255)傳回讀到的位元組。
使用條件與限制
目標位元組或字組的全部內容必須在選定 CPU 映射中可讀取。這些讀取不檢查指標、不裁切位址,也不會在視窗邊界自動切換到下一個 ROM 區塊。讀取一個字組需要連續兩個有效位元組。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
FC 切換編號是編譯器的邏輯編號。0 表示共用 ROM,不是切換目標;輔助程式將 0 視為區塊 1。SUROM512 僅允許 1–30:直接傳給切換內建函式的越界常數會導致建置錯誤;無效執行時值會退回 1 並設定 mapper 故障狀態。共用 ROM 應直接讀取,不要要求切換到區塊 0。
使用範例
bank_expect(farptr_read8(pointer)==0x7A,9);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式片段使用 farptr_read8 讀取區塊 3 中的 pointer.ptr 並檢查 7A。完整程式還透過近指標讀取 home2,確認已還原區塊 2 的映射。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 02:far_call 巨集與 __farcall 各執行一次回呼。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/bank.h:28
Read one byte using both the bank and address of the supplied far pointer.
kitaqfc/lib/bank.c:46
u8 farptr_read8(BankPtr ptr)
{
return __farpeek8(ptr.bank, (u16)ptr.ptr);
}chain.h — 位置歷史環狀緩衝區
關節相連的蛇身或繩索請使用 ChainBody,記錄位置歷程則使用 Chain。每個身體關節保存目前位置及 16 種方向之一;彎折每次更新向後傳遞一個關節。身體操作支援場地邊界回捲、複製尾端以增加長度,以及各軸最多兩個像素的修正。
chain_wrap_delta
在兩端相接的軸上,計算目前位置到目標的最短帶正負號位移。可用於跨場地邊界的跟隨或距離比較。
語法
s16 chain_wrap_delta(u8 target, u8 current, u16 size);參數
target目標座標,範圍為 0..size−1。
current目前座標,範圍為 0..size−1。
size循環軸長度為 1..256:X 使用寬度,Y 使用高度。此引數為 16 位元,以便表示 256。
回傳值
以 s16 傳回最短位移:朝座標增加方向為正、減少方向為負、相同位置為零。有效輸入產生 −128..+128。畫面座標向右與向下的位移為正。
使用條件與限制
包含 chain.h 並且只編譯一次 chain.c。不需要初始化 Chain 或 ChainBody。此函式只計算位移,不改變座標陣列、關節數或畫面。
不驗證或正規化輸入。不可傳入 size=0、size>256,或大於等於 size 的座標。來自較大座標系的座標須先回捲至 0..size−1,再呼叫。
兩條路徑等長時,保留直接位移 target−current 的符號。size=160 時,0→80 傳回 +80,80→0 傳回 −80。size=1 時,唯一有效座標為零,結果也為零。
使用範例
distances[0]=chain_wrap_delta(1,159,160); // +2: cross the right edge.
distances[1]=chain_wrap_delta(159,1,160); // -2: cross the left edge.
distances[2]=chain_wrap_delta(80,0,160); // +80: keep the direct sign.
distances[3]=chain_wrap_delta(0,80,160); // -80: same-length routes.
distances[4]=chain_wrap_delta(0,0,1); // 0: the only valid position.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範循環座標。每支箭頭由目前位置指向目標。跨越寬度 160 邊界的結果為 +02/−02,半個場地為 +80/−80,寬度 1 為 +00。前置零只是十進位補位。此範例不繪製或移動物件。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_wrap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_wrap.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/chain.h:39
Return target minus current along the shortest wrapped route. Supply size 1..256 and coordinates in 0..size-1; inputs are not normalized. Exactly half a field retains the direct displacement sign.
kitaqfc/lib/chain.c:103
s16 chain_wrap_delta(u8 target, u8 current, u16 size)
{
s16 delta;
s16 half;
delta = (s16)((s16)target - (s16)current);
half = (s16)(size >> 1);
// At exactly half a field, retain the sign of the direct displacement.
if (((u16)delta & 0x8000) != 0) {
if ((u16)(0 - delta) > (u16)half) delta = (s16)(delta + (s16)size);
} else if ((u16)delta > (u16)half) delta = (s16)(delta - (s16)size);
return delta;
}chain_body_init
連結呼叫端持有的三個關節陣列,將關節數設為零,不配置記憶體。
語法
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。x關節 X 座標陣列。
y關節 Y 座標陣列。
heading關節朝向陣列。
capacity已配置陣列長度,1..255。
width循環場地寬度,1..256。
height循環場地高度,1..256。
回傳值
成功傳回 1,引數無效傳回 0。body 非 null 時若失敗,會將 capacity 與 count 設為零,以停用更新。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
使用範例
chain_body_init(&body,joint_x,joint_y,joint_heading,8,160,144);
// Eight caller-owned slots, including the head, on a wrapped 160x144 field.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/chain.h:57
Attach three non-overlapping capacity-byte arrays. Return 1 on success. Invalid storage, zero capacity or dimensions outside 1..256 disable the body.
kitaqfc/lib/chain.c:127
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height)
{
if (body == 0) return 0;
body->x = x;
body->y = y;
body->heading = heading;
body->count = 0;
body->capacity = 0;
body->width = width;
body->height = height;
if (x == 0 || y == 0 || heading == 0 || capacity == 0) return 0;
if (width == 0 || width > 256 || height == 0 || height > 256) return 0;
body->capacity = capacity;
return 1;
}chain_body_reset
在指定頭部後方排列關節,建立筆直的初始姿態。
語法
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。count包含頭部的關節數,1..capacity。
head_x頭部 X 座標,依場地寬度回捲。
head_y頭部 Y 座標,依場地高度回捲。
heading16 區方向系統中的頭部朝向。
回傳值
成功傳回 1;數量為零、超出容量或 body 為 null 時,傳回 0 且不改變姿態。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
上下左右的間距為四像素。中間方向使用 (4,1)、(3,3)、(1,4) 等整數向量,因此歐氏距離不會恰為四像素。初始姿態可能跨越場地邊界。
使用範例
chain_body_reset(&body,7,48,16,0); // Seven joints, facing right.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/chain.h:61
Seed count joints in a straight pose behind the head; count includes the head. Return 0 without changing the pose if count is zero or exceeds capacity. Coordinates wrap to the playfield and headings are masked to 0..15.
kitaqfc/lib/chain.c:143
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading)
{
// Cache caller storage once; following math and old-heading propagation
// use these local values. Avoid decoding packed struct pointers per joint.
u8* coord_x;u8* coord_y;u8* directions;u16 width;u16 height;
u8 i;
u8 x;
u8 y;
s16 ox;
s16 oy;
if (body == 0) return 0;
if (count == 0 || count > body->capacity) return 0;
coord_x=body->x;coord_y=body->y;directions=body->heading;
width=body->width;height=body->height;
heading = (u8)(heading & 15);
x = chain_body_wrap((s16)head_x, width);
y = chain_body_wrap((s16)head_y, height);
ox = chain_body_offset_x(heading);
oy = chain_body_offset_y(heading);
i = 0;
while (i < count) {
coord_x[(__safe_index u8)i] = x;
coord_y[(__safe_index u8)i] = y;
directions[(__safe_index u8)i] = heading;
x = chain_body_wrap((s16)((s16)x - ox), width);
y = chain_body_wrap((s16)((s16)y - oy), height);
i = (u8)(i + 1);
}
body->count = count;
return 1;
}chain_body_step
設定頭部姿態,逐步將各關節拉向前一關節後方的連接點。方向變化每次更新傳遞一個關節。
語法
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。head_x頭部 X 座標,依場地寬度回捲。
head_y頭部 Y 座標,依場地高度回捲。
heading16 區方向系統中的頭部朝向。
回傳值
無傳回值。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
用前一關節更新後的位置找出目標連接點,再計算各軸跨邊界的最短位移。位移為零時不移動;大小 1..4 時移動一像素,5 以上時移動兩像素。距離恰為場地一半時保留原位移符號。
將各關節更新前保存的朝向傳給下一關節,讓彎折沿身體傳遞。空身體不變。
頭部速度、加速度、碰撞、繪圖與等待由呼叫端處理。通常先更新頭部,再於每個模擬步驟呼叫一次 chain_body_step。此功能是關節跟隨,不是剛體或精確長度約束求解器。
使用範例
chain_body_step(&body,48,20,4); // The head turns down; only joint 1 receives 4.
show_pose(8,34);
for(step=1;step<4;step++) {
chain_body_step(&body,48,(u8)(20+step),4);
}
// After four ticks, the new heading has reached joints 1 through 4.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/chain.h:66
Install the caller's head pose, then pull joints from front to rear. Each joint aims four pixels behind its updated predecessor and receives that predecessor's OLD heading. Each axis moves 1 pixel, or 2 when error exceeds 4. Call once per simulation tick; this does not advance head physics or render.
kitaqfc/lib/chain.c:175
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading)
{
// Cache caller storage once; following math and old-heading propagation
// use these local values. Avoid decoding packed struct pointers per joint.
u8* coord_x;u8* coord_y;u8* directions;u16 width;u16 height;
u8 i;
u8 previous;
u8 pull;
u8 old;
u8 x;
u8 y;
u8 tx;
u8 ty;
s16 sx;
s16 sy;
if (body == 0) return;
if (body->count == 0) return;
coord_x=body->x;coord_y=body->y;directions=body->heading;
width=body->width;height=body->height;
heading = (u8)(heading & 15);
coord_x[0] = chain_body_wrap((s16)head_x, width);
coord_y[0] = chain_body_wrap((s16)head_y, height);
directions[0] = heading;
pull = heading;
i = 1;
while (i < body->count) {
previous = (u8)(i - 1);
old = directions[(__safe_index u8)i];
x = coord_x[(__safe_index u8)i];
y = coord_y[(__safe_index u8)i];
tx = chain_body_wrap((s16)((s16)coord_x[(__safe_index u8)previous] - chain_body_offset_x(pull)), width);
ty = chain_body_wrap((s16)((s16)coord_y[(__safe_index u8)previous] - chain_body_offset_y(pull)), height);
sx = chain_body_correction(chain_wrap_delta(tx, x, width));
sy = chain_body_correction(chain_wrap_delta(ty, y, height));
directions[(__safe_index u8)i] = pull;
coord_x[(__safe_index u8)i] = chain_body_wrap((s16)((s16)x + sx), width);
coord_y[(__safe_index u8)i] = chain_body_wrap((s16)((s16)y + sy), height);
// Save before overwriting: a bend advances by one joint per update.
pull = old;
i = (u8)(i + 1);
}
}chain_body_grow
將尾部目前位置與朝向複製到下一個空槽,數量增加一。
語法
u8 chain_body_grow(ChainBody* body);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。
回傳值
新增關節成功時傳回 1;身體為空、已滿、停用或 null 時傳回 0。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
新尾部起初與原尾部重疊,之後透過 chain_body_step 呼叫分離。成長本身不會移動頭部或其他關節。
使用範例
chain_body_grow(&body); // Copy the tail pose into the eighth slot.
chain_body_step(&body,48,16,0);
chain_body_step(&body,48,16,0);
chain_body_step(&body,48,16,0);
chain_body_step(&body,48,16,0); // Allow the duplicated tail to separate.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/chain.h:69
Append a copy of the current tail; later steps separate the new joint. Return 1 on growth, or 0 for an empty, disabled or full body.
kitaqfc/lib/chain.c:218
u8 chain_body_grow(ChainBody* body)
{
u8 tail;
u8 next;
if (body == 0) return 0;
next = body->count;
if (next == 0 || next >= body->capacity) return 0;
tail = (u8)(next - 1);
body->x[(__safe_index u8)next] = body->x[(__safe_index u8)tail];
body->y[(__safe_index u8)next] = body->y[(__safe_index u8)tail];
body->heading[(__safe_index u8)next] = body->heading[(__safe_index u8)tail];
body->count = (u8)(next + 1);
return 1;
}chain_body_clear
保留陣列與場地設定,將關節數設為零。
語法
void chain_body_clear(ChainBody* body);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。
回傳值
無傳回值。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
不清除陣列位元組。請使用 chain_body_reset 重新開始;清空後立即呼叫 chain_body_grow 不會新增關節。
使用範例
chain_body_clear(&body); // Forget the pose; the three arrays remain owned by us.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/chain.h:71
Remove all joints while retaining caller-owned storage and playfield settings.
kitaqfc/lib/chain.c:233
void chain_body_clear(ChainBody* body)
{
if (body == 0) return;
body->count = 0;
}chain_clear
清除已記錄的歷史,讓同一個底層陣列可再次使用。
語法
void chain_clear(Chain* chain);參數
chain指向已初始化
Chain的指標。
回傳值
無傳回值。
使用條件與限制
將筆數與 head 歸零,不清除或釋放底層陣列。Chain 與點陣列都由呼叫端持有,使用期間必須有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
FC 版本在 chain == 0 時不執行任何動作。
使用範例
chain_clear(&trail);result[11]=chain_get_count(&trail);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例清除四個點的歷史,並確認筆數變為零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/chain.h:24
Forget the recorded points without clearing or freeing the backing storage.
kitaqfc/lib/chain.c:16
void chain_clear(Chain* chain)
{
if (chain == 0) return;
chain->count = 0;
chain->head = 0;
}chain_get_count
讀取目前歷史中可用的位置筆數。
語法
u8 chain_get_count(const Chain* chain);參數
chain指向已初始化
Chain的指標。
回傳值
傳回零至容量之間的筆數;chain 為空指標時傳回零。
使用條件與限制
Chain 與點陣列都由呼叫端持有,使用期間必須保持有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
使用範例
result[4]=chain_get_count(&trail);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四個槽位加入五次資料後,筆數仍為四。清除後變為零;容量為零的歷史也會保持零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/chain.h:33
Return the number of stored points, or zero for a null chain.
kitaqfc/lib/chain.c:66
u8 chain_get_count(const Chain* chain)
{
if (chain == 0) return 0;
return chain->count;
}chain_get_segment
依記錄的新舊順序讀取儲存的位置。
語法
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out);參數
chain指向已初始化
Chain的指標。index點的新舊索引:0 為最新,
count - 1為保留的最舊點。out用來接收結果的獨立、可寫入
ChainPoint;空指標會導致失敗。
回傳值
成功時傳回 1,要求無效時傳回 0。若 out 不是空指標,會在驗證前先設為 (0,0)。
使用條件與限制
out 不可與底層陣列或 Chain 共用記憶體,否則清除輸出時會破壞來源資料。Chain 與點陣列由呼叫端持有,使用期間必須有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
使用範例
result[1]=chain_get_segment(&trail,0,&point);result[2]=point.x;result[3]=point.y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
索引 0 讀取最新點 (40,24),索引 3 讀取最舊點 (16,8);無效索引 4 傳回失敗,輸出為 (0,0)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/chain.h:31
Read a point by age, with index zero denoting the newest point. Return zero for an invalid request and clear a non-null output first. Keep head + index within the 8-bit range: addition is narrowed before the capacity wrap.
kitaqfc/lib/chain.c:42
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out)
{
u8 pos;
// Do not alias out with the backing ring: it is cleared before the requested point is read.
if (out != 0) {
out->x = 0;
out->y = 0;
}
if (out == 0) return 0;
if (chain == 0) return 0;
if (chain->capacity == 0) return 0;
if (index >= chain->count) return 0;
pos = (u8)(chain->head + index);
while (pos >= chain->capacity) {
pos = (u8)(pos - chain->capacity);
}
out->x = chain->points[(__safe_index u8)pos].x;
out->y = chain->points[(__safe_index u8)pos].y;
return 1;
}chain_init
將儲存空間接到位置歷史的環狀緩衝區,並從沒有任何記錄點的狀態開始。
語法
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity);參數
chain要初始化且可寫入的
Chain。storage可容納
capacity個ChainPoint項目的陣列。capacity點槽位數。可用範圍為 1~128;零會停用記錄。
回傳值
無傳回值。
使用條件與限制
Chain 與點陣列都由呼叫端持有,使用期間必須保持有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
FC 版本在 chain == 0 時不執行任何動作。
使用範例
chain_init(&trail,storage,4);result[0]=chain_get_count(&trail);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例連接四個點槽位,並確認初始筆數為零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/chain.h:22
Attach caller-owned ring storage and start with no recorded points. The storage must remain valid for the lifetime of the chain.
kitaqfc/lib/chain.c:5
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity)
{
if (chain == 0) return;
// A nonzero capacity requires writable storage for that many complete ChainPoint records.
chain->points = storage;
chain->capacity = capacity;
chain->count = 0;
chain->head = 0;
}chain_push_head
將最新位置加入歷史的頭端;已滿時取代最舊的點。
語法
void chain_push_head(Chain* chain, s16 x, s16 y);參數
chain指向已初始化
Chain的指標。x新點的帶正負號 X 座標。
y新點的帶正負號 Y 座標。
回傳值
無傳回值。
使用條件與限制
chain 為空指標或容量為零時不執行操作。Chain 與點陣列都由呼叫端持有,使用期間必須有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
使用範例
chain_push_head(&trail,8,8);chain_push_head(&trail,16,8);chain_push_head(&trail,24,16);chain_push_head(&trail,32,16);chain_push_head(&trail,40,24);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
向四個槽位加入五次資料後,最新點為 (40,24),保留的最舊點為 (16,8);原本的 (8,8) 已被取代。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/chain.h:27
Move the ring head backward and store the newest point. Once full, each push replaces the oldest point; zero capacity is a no-op.
kitaqfc/lib/chain.c:25
void chain_push_head(Chain* chain, s16 x, s16 y)
{
if (chain == 0) return;
if (chain->capacity == 0) return;
if (chain->head == 0) chain->head = (u8)(chain->capacity - 1);
else chain->head = (u8)(chain->head - 1);
chain->points[(__safe_index u8)chain->head].x = x;
chain->points[(__safe_index u8)chain->head].y = y;
if (chain->count < chain->capacity) chain->count = (u8)(chain->count + 1);
}collision.h — 矩形與其他碰撞測試
使用無號 16 位元位置,在 FC 世界座標中測試矩形與矩形、矩形與點的重疊。
nes_box16_contains_point
檢查點是否位於 FC 矩形內;包含左邊界與上邊界,不包含右邊界與下邊界。
語法
unsigned char nes_box16_contains_point(struct NesBox16* box, unsigned short px, unsigned short py);參數
box可讀取的
NesBox16;不可傳入 null。px點的 X 座標,為無號 16 位元值。
py點的 Y 座標,為無號 16 位元值。
回傳值
在內部時傳回 1,在外部時傳回 0。
使用條件與限制
x, y 為無號 16 位元座標,寬度與高度各為一個位元組。尺寸必須大於零,座標加上尺寸的總和不得超過 65535。不支援跨越座標回捲邊界的矩形。
使用範例
result[6]=nes_box16_contains_point(&na,9,1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
每個座標單位佔一個圖塊。矩形 A 位於 (1,1),B 位於 (5,4),兩者大小皆為 8×6。僅屬於 A 的格子顯示 A,僅屬於 B 的格子顯示 B;4×3 的重疊區域顯示 12 個 O。A 的右邊界 x=9 不包含在內。CGB 上的 A 為紅色、B 為藍色、O 為綠色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_geometry.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/collision.h:18
Test a half-open box: left/top edges are included and right/bottom edges excluded. Callers provide valid pointers and non-overflowing edge coordinates.
kitaqfc/lib/collision.c:49
unsigned char nes_box16_contains_point(struct NesBox16* box, unsigned short px, unsigned short py)
{
unsigned short right;
unsigned short bottom;
right = (unsigned short)(box->x + box->w);
bottom = (unsigned short)(box->y + box->h);
if (px < box->x)
{
return 0;
}
if (py < box->y)
{
return 0;
}
if (px >= right)
{
return 0;
}
if (py >= bottom)
{
return 0;
}
return 1;
}nes_box16_intersects
檢查以指標傳入的兩個 FC 矩形是否有面積大於零的重疊區域。
語法
unsigned char nes_box16_intersects(struct NesBox16* a, struct NesBox16* b);參數
a可讀取的第一個
NesBox16;不可傳入 null。b可讀取的第二個
NesBox16。
回傳值
有重疊時傳回 1,分離或僅邊緣接觸時傳回 0。
使用條件與限制
x, y 為無號 16 位元座標,寬度與高度各為一個位元組。尺寸必須大於零,座標加上尺寸的總和不得超過 65535。不支援跨越座標回捲邊界的矩形。
使用範例
result[5]=nes_box16_intersects(&na,&nb);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
每個座標單位佔一個圖塊。矩形 A 位於 (1,1),B 位於 (5,4),兩者大小皆為 8×6。僅屬於 A 的格子顯示 A,僅屬於 B 的格子顯示 B;4×3 的重疊區域顯示 12 個 O。A 的右邊界 x=9 不包含在內。CGB 上的 A 為紅色、B 為藍色、O 為綠色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_geometry.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/collision.h:15
Test two axis-aligned world boxes using exclusive right/bottom edges. Coordinate-plus-size sums must fit u16; touching edges return false. Both boxes must have positive dimensions; the overlap test has no separate empty-box guard.
kitaqfc/lib/collision.c:15
unsigned char nes_box16_intersects(struct NesBox16* a, struct NesBox16* b)
{
unsigned short a_right;
unsigned short b_right;
unsigned short a_bottom;
unsigned short b_bottom;
a_right = (unsigned short)(a->x + a->w);
b_right = (unsigned short)(b->x + b->w);
a_bottom = (unsigned short)(a->y + a->h);
b_bottom = (unsigned short)(b->y + b->h);
if (a_right <= b->x)
{
return 0;
}
if (b_right <= a->x)
{
return 0;
}
if (a_bottom <= b->y)
{
return 0;
}
if (b_bottom <= a->y)
{
return 0;
}
return 1;
}danmaku — 64 顆子彈的物件池
danmaku 是使用固定小數點的 64 顆子彈物件池。初始化並產生子彈後,呼叫 step 處理移動與碰撞,再呼叫 draw 建立 OAM,最後於 VBlank 執行 DMA。玩家輸入、傷害、計分及音效由遊戲程式處理。範例將原創菱形圖塊上傳至 CHR RAM;函式庫本身也可使用 CHR ROM 精靈。
danmaku_reset
停用所有子彈,並重設命中/擦彈事件、最高及累計數量,以及配置與繪製順序游標。
語法
void danmaku_reset(void);回傳值
無傳回值。
使用條件與限制
保留玩家位置與 dm_invulnerable。此操作不會清除 OAM 或畫面;若要移除可見子彈,請繪製空物件池並執行 DMA,或另外隱藏 OAM。
請在卡匣可寫入的 PRG RAM 中保留 $6000–$627F(640 位元組),供 64 顆子彈使用,並在卡匣映射器中啟用該 RAM。此函式庫共用內部狀態,因此不支援重入。
dm_count 是目前有效子彈數,dm_peak 是曾達到的最高數量。16 位元計數器 dm_spawned 與 dm_rejected 分別記錄產生成功及失敗次數,超過 65535 後回到零。dm_x 與 dm_y 是中心座標;dm_active 為零時,請忽略其值。
KUROSAKI 會以四種編譯器設定檢查所有像素、子彈數量與位置、預留 OAM 以及輪替的繪製順序。另以數值檢查命中、擦彈、移除畫面外子彈及物件池已滿的情況。尚未在實機上測試。
使用範例
danmaku_reset();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側四顆黃色子彈從 (48,64) 分別向上、下、左、右移動了 16 像素。右側十六顆黃色子彈在距離 (160,104) 約 32 像素處形成圓環。(112,192) 的青色玩家使用預留的 OAM 槽位零。此範例執行十六次邏輯更新後保留畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.png實作與原始碼
kitaqfc/lib/danmaku.h:26
Reset the pool, counters and rotating OAM priority. Player settings survive.
kitaqfc/lib/danmaku.c:40
void danmaku_reset(void) {
danmaku_clear();
dm_peak=0;dm_spawned=0;dm_rejected=0;dm_cursor=0;dm_draw_phase=0;
}danmaku_clear
停用所有子彈,並將 dm_count、dm_hit、dm_graze 清零。可用於遊戲中途清除子彈。
語法
void danmaku_clear(void);回傳值
無傳回值。
使用條件與限制
保留 dm_peak、dm_spawned、dm_rejected、配置與繪製順序游標及玩家設定。範例產生一顆子彈後將其清除:有效子彈數變為零,但累計產生數仍為一。OAM 須另行更新。
請在卡匣可寫入的 PRG RAM 中保留 $6000–$627F(640 位元組),供 64 顆子彈使用,並在卡匣映射器中啟用該 RAM。此函式庫共用內部狀態,因此不支援重入。
dm_count 是目前有效子彈數,dm_peak 是曾達到的最高數量。16 位元計數器 dm_spawned 與 dm_rejected 分別記錄產生成功及失敗次數,超過 65535 後回到零。dm_x 與 dm_y 是中心座標;dm_active 為零時,請忽略其值。
KUROSAKI 會以四種編譯器設定檢查所有像素、子彈數量與位置、預留 OAM 以及輪替的繪製順序。另以數值檢查命中、擦彈、移除畫面外子彈及物件池已滿的情況。尚未在實機上測試。
使用範例
danmaku_clear();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側四顆黃色子彈從 (48,64) 分別向上、下、左、右移動了 16 像素。右側十六顆黃色子彈在距離 (160,104) 約 32 像素處形成圓環。(112,192) 的青色玩家使用預留的 OAM 槽位零。此範例執行十六次邏輯更新後保留畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.png實作與原始碼
kitaqfc/lib/danmaku.h:28
Remove all bullets and step events; preserve lifetime/peak counters.
kitaqfc/lib/danmaku.c:35
void danmaku_clear(void) {
u8 i;
for(i=0;i<64;i++)dm_active[i]=0;
dm_count=0;dm_hit=0;dm_graze=0;
}danmaku_spawn
循環搜尋物件池中的空槽位,初始化位置、速度及尚未擦彈的狀態。單純產生子彈不會讓它移動,也不會檢查碰撞。
語法
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);參數
x水平中心座標,單位為像素;接受範圍為 8~247。
y垂直中心座標,單位為像素;接受範圍為 24~231。
vx帶正負號 Q4.4 格式的水平速度。16 表示每次更新移動一像素,−16 表示向反方向移動一像素。−128~127 對應 −8~+7.9375 像素。
vy帶正負號 Q4.4 格式的垂直速度。16 表示每次更新移動一像素,−16 表示向反方向移動一像素。−128~127 對應 −8~+7.9375 像素。
回傳值
成功時傳回 1;位置無效或 64 個槽位全滿時傳回 0。成功會增加 dm_count 與 dm_spawned,並視需要更新 dm_peak;失敗則增加 dm_rejected。
使用條件與限制
請在卡匣可寫入的 PRG RAM 中保留 $6000–$627F(640 位元組),供 64 顆子彈使用,並在卡匣映射器中啟用該 RAM。此函式庫共用內部狀態,因此不支援重入。
dm_count 是目前有效子彈數,dm_peak 是曾達到的最高數量。16 位元計數器 dm_spawned 與 dm_rejected 分別記錄產生成功及失敗次數,超過 65535 後回到零。dm_x 與 dm_y 是中心座標;dm_active 為零時,請忽略其值。
KUROSAKI 會以四種編譯器設定檢查所有像素、子彈數量與位置、預留 OAM 以及輪替的繪製順序。另以數值檢查命中、擦彈、移除畫面外子彈及物件池已滿的情況。尚未在實機上測試。
使用範例
danmaku_spawn(48,64,16,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側四顆黃色子彈從 (48,64) 分別向上、下、左、右移動了 16 像素。右側十六顆黃色子彈在距離 (160,104) 約 32 像素處形成圓環。(112,192) 的青色玩家使用預留的 OAM 槽位零。此範例執行十六次邏輯更新後保留畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.png實作與原始碼
kitaqfc/lib/danmaku.h:31
Allocate a bullet at pixel-center x/y with signed 1/16-pixel velocities. Return one on success, zero outside the playfield or when all 64 slots are full.
kitaqfc/lib/danmaku.c:44
u8 danmaku_spawn(u8 x,u8 y,s8 vx,s8 vy) {
u8 i,n;
if(x<8 || x>=248 || y<24 || y>=232){dm_rejected++;return 0;}
i=dm_cursor;
for(n=0;n<64;n++) {
if(dm_active[i]==0) {
dm_x[i]=x;dm_y[i]=y;dm_fraction_x[i]=0;dm_fraction_y[i]=0;
// Expand signed Q4.4 to a two-byte two's-complement Q8.8 step.
dm_vx_integer[i]=(u8)((s16)vx>>4);dm_vx_fraction[i]=(u8)((u8)vx<<4);
dm_vy_integer[i]=(u8)((s16)vy>>4);dm_vy_fraction[i]=(u8)((u8)vy<<4);
dm_grazed[i]=0;dm_active[i]=1;dm_cursor=(u8)((i+1)&63);
dm_count++;if(dm_count>dm_peak)dm_peak=dm_count;
dm_spawned++;return 1;
}
i=(u8)((i+1)&63);
}
dm_rejected++;return 0;
}danmaku_fan
以固定步幅改變方向並產生子彈。調整步幅與數量可形成扇形或完整圓環。
語法
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);參數
x水平中心座標,單位為像素;接受範圍為 8~247。
y垂直中心座標,單位為像素;接受範圍為 24~231。
direction初始方向,一圈分為 32 階:0 向右、8 向下、16 向左、24 向上。只使用低五位元。
step每顆子彈之後增加的方向步幅,以模 32 循環。零表示所有子彈朝相同方向發射。
count嘗試產生的次數。大於 64 時限制為 64;零則不執行任何操作。
speed速率大小,單位為每次更新的十六分之一像素:16 為一像素,32 為兩像素。大於 64 時限制為 64。
回傳值
無傳回值。
使用條件與限制
速度來自整數正弦表,並向零截斷,因此斜向速率與半徑會有量化誤差。物件池已滿也不會取消剩餘嘗試;每次失敗都會增加 dm_rejected。
請在卡匣可寫入的 PRG RAM 中保留 $6000–$627F(640 位元組),供 64 顆子彈使用,並在卡匣映射器中啟用該 RAM。此函式庫共用內部狀態,因此不支援重入。
dm_count 是目前有效子彈數,dm_peak 是曾達到的最高數量。16 位元計數器 dm_spawned 與 dm_rejected 分別記錄產生成功及失敗次數,超過 65535 後回到零。dm_x 與 dm_y 是中心座標;dm_active 為零時,請忽略其值。
KUROSAKI 會以四種編譯器設定檢查所有像素、子彈數量與位置、預留 OAM 以及輪替的繪製順序。另以數值檢查命中、擦彈、移除畫面外子彈及物件池已滿的情況。尚未在實機上測試。
使用範例
danmaku_fan(160,104,0,2,16,32);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側四顆黃色子彈從 (48,64) 分別向上、下、左、右移動了 16 像素。右側十六顆黃色子彈在距離 (160,104) 約 32 像素處形成圓環。(112,192) 的青色玩家使用預留的 OAM 槽位零。此範例執行十六次邏輯更新後保留畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.png實作與原始碼
kitaqfc/lib/danmaku.h:34
Emit up to 64 bullets. Angles wrap in 32 steps: 0 right, 8 down, 16 left, 24 up. Speed is in 1/16 pixel, clamped to 64. Each failed allocation counts.
kitaqfc/lib/danmaku.c:62
void danmaku_fan(u8 x,u8 y,u8 direction,u8 step,u8 count,u8 speed) {
u8 i,angle;s16 vx,vy;
if(count>64)count=64;if(speed>64)speed=64;
angle=(u8)(direction&31);
for(i=0;i<count;i++) {
vx=(s16)Danmaku_Sin[(u8)((angle+8)&31)]*(s16)speed;
vy=(s16)Danmaku_Sin[angle]*(s16)speed;
danmaku_spawn(x,y,(s8)(vx/64),(s8)(vy/64));
angle=(u8)((angle+step)&31);
}
}danmaku_step
將每顆有效子彈前進一次,移除畫面外子彈,並判斷玩家命中與擦彈。子彈的時間隨呼叫次數推進,不依實際經過時間計算。
語法
void danmaku_step(void);回傳值
無傳回值。
使用條件與限制
呼叫前,請將 dm_player_x 與 dm_player_y 設為玩家中心座標。移動後,兩軸距離都不超過三像素時視為命中。若 dm_invulnerable 為零,便將 dm_hit 設為一並移除子彈;無敵狀態下則保留子彈。
在命中區域外,兩軸距離都不超過十一像素時,每顆子彈可產生一次擦彈。dm_hit 與 dm_graze 會在函式開始時重設,只代表本次更新。玩家無敵時,位於命中區域內的子彈不算擦彈。
此函式不會寫入 OAM,也不會呼叫傷害或音效回呼。請在遊戲程式中讀取 dm_hit 與 dm_graze,更新玩家狀態或分數。
請在卡匣可寫入的 PRG RAM 中保留 $6000–$627F(640 位元組),供 64 顆子彈使用,並在卡匣映射器中啟用該 RAM。此函式庫共用內部狀態,因此不支援重入。
dm_count 是目前有效子彈數,dm_peak 是曾達到的最高數量。16 位元計數器 dm_spawned 與 dm_rejected 分別記錄產生成功及失敗次數,超過 65535 後回到零。dm_x 與 dm_y 是中心座標;dm_active 為零時,請忽略其值。
KUROSAKI 會以四種編譯器設定檢查所有像素、子彈數量與位置、預留 OAM 以及輪替的繪製順序。另以數值檢查命中、擦彈、移除畫面外子彈及物件池已滿的情況。尚未在實機上測試。
使用範例
danmaku_step();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側四顆黃色子彈從 (48,64) 分別向上、下、左、右移動了 16 像素。右側十六顆黃色子彈在距離 (160,104) 約 32 像素處形成圓環。(112,192) 的青色玩家使用預留的 OAM 槽位零。此範例執行十六次邏輯更新後保留畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.png實作與原始碼
kitaqfc/lib/danmaku.h:38
Move all live bullets once. Remove offscreen/hitting bullets. Hit uses a +/-3-pixel box; graze uses +/-11, once per bullet. Events describe this step. This updates logic only; it neither writes OAM nor calls a game damage handler.
kitaqfc/lib/danmaku.c:73
void danmaku_step(void) {
// Byte arrays let the 6502 move every slot without multiplying a structure
// index. Carry propagates fractional motion into the signed integer step.
__asm {
LDX #0
STX dm_count
STX dm_hit
STX dm_graze
dm_tick_loop:
LDA dm_active,X
BNE dm_tick_live
JMP dm_tick_next
dm_tick_live:
CLC
LDA dm_fraction_x,X
ADC dm_vx_fraction,X
STA dm_fraction_x,X
LDA dm_x,X
ADC dm_vx_integer,X
STA dm_x,X
CMP #8
BCC dm_tick_kill
CMP #248
BCS dm_tick_kill
CLC
LDA dm_fraction_y,X
ADC dm_vy_fraction,X
STA dm_fraction_y,X
LDA dm_y,X
ADC dm_vy_integer,X
STA dm_y,X
CMP #24
BCC dm_tick_kill
CMP #232
BCS dm_tick_kill
// Unsigned absolute distances avoid false collisions across screen wrap.
LDA dm_x,X
SEC
SBC dm_player_x
BCS dm_tick_dx
EOR #255
CLC
ADC #1
dm_tick_dx:
STA dm_distance_x
LDA dm_y,X
SEC
SBC dm_player_y
BCS dm_tick_dy
EOR #255
CLC
ADC #1
dm_tick_dy:
STA dm_distance_y
CMP #4
BCS dm_tick_graze
LDA dm_distance_x
CMP #4
BCS dm_tick_graze
LDA dm_invulnerable
BNE dm_tick_count
LDA #1
STA dm_hit
dm_tick_kill:
LDA #0
STA dm_active,X
JMP dm_tick_next
dm_tick_graze:
LDA dm_grazed,X
BNE dm_tick_count
LDA dm_distance_x
CMP #12
BCS dm_tick_count
LDA dm_distance_y
CMP #12
BCS dm_tick_count
LDA #1
STA dm_grazed,X
INC dm_graze
dm_tick_count:
INC dm_count
dm_tick_next:
INX
CPX #64
BEQ dm_tick_done
JMP dm_tick_loop
dm_tick_done:
}
}danmaku_draw
依子彈中心建立 8×8 精靈,寫入指定的 OAM 暫存副本範圍;不會移動子彈或檢查碰撞。
語法
u8 danmaku_draw(u8 first_oam, u8 slots, u8 tile, u8 attributes);參數
first_oam第一個 OAM 槽位(0~63)。值為 64 以上時,不寫入任何資料並傳回零。範例從一開始,以將槽位零保留給玩家。
slots可用的連續槽位數,上限為 64−first_oam。零表示不寫入資料,但繪製優先順序仍會前進。
tile所有子彈共用的 8×8 圖樣圖塊。請設定為 8×8 精靈模式;此呼叫會讓所有子彈使用相同形狀。
attributes所有子彈共用的 NES 精靈屬性:位元 0~1 為調色盤,位元 5 為背景後方,位元 6 為水平翻轉,位元 7 為垂直翻轉。
回傳值
傳回寫入 OAM 的子彈數,即有效子彈數與可用槽位數中的較小值。
使用條件與限制
每次呼叫將起始子彈槽位以模 64 前進 13,避免固定幾顆子彈總是優先。要求範圍內未使用的槽位會以 Y=240 隱藏,範圍外的 OAM 保持不變。
中心 X 減四、中心 Y 減五;硬體會對 OAM Y 加一,使精靈對準中心。請自行在 VBlank 期間呼叫 __oam_dma。每條掃描線最多八個精靈的硬體限制仍然適用。
請在卡匣可寫入的 PRG RAM 中保留 $6000–$627F(640 位元組),供 64 顆子彈使用,並在卡匣映射器中啟用該 RAM。此函式庫共用內部狀態,因此不支援重入。
dm_count 是目前有效子彈數,dm_peak 是曾達到的最高數量。16 位元計數器 dm_spawned 與 dm_rejected 分別記錄產生成功及失敗次數,超過 65535 後回到零。dm_x 與 dm_y 是中心座標;dm_active 為零時,請忽略其值。
KUROSAKI 會以四種編譯器設定檢查所有像素、子彈數量與位置、預留 OAM 以及輪替的繪製順序。另以數值檢查命中、擦彈、移除畫面外子彈及物件池已滿的情況。尚未在實機上測試。
使用範例
bullet_result[9]=danmaku_draw(1,24,1,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側四顆黃色子彈從 (48,64) 分別向上、下、左、右移動了 16 像素。右側十六顆黃色子彈在距離 (160,104) 約 32 像素處形成圓環。(112,192) 的青色玩家使用預留的 OAM 槽位零。此範例執行十六次邏輯更新後保留畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.png實作與原始碼
kitaqfc/lib/danmaku.h:43
Write up to slots consecutive shadow-OAM entries starting at first_oam. Rotate bullet priority by 13 modulo 64 and hide unused entries in that range. tile is an 8x8 sprite centered at (4,4). Return the number emitted. DMA is caller-owned and belongs in VBlank. Hardware's eight-per-scanline limit remains.
kitaqfc/lib/danmaku.c:162
u8 danmaku_draw(u8 first_oam,u8 slots,u8 tile,u8 attributes) {
u8 i,n,drawn;
if(first_oam>=64)return 0;
if(slots>(u8)(64-first_oam))slots=(u8)(64-first_oam);
dm_draw_phase=(u8)((dm_draw_phase+13)&63);i=dm_draw_phase;drawn=0;
for(n=0;n<64;n++) {
if(dm_active[i]!=0 && drawn<slots) {
__sprite_set((u8)(first_oam+drawn),(u8)(dm_x[i]-4),(u8)(dm_y[i]-5),tile,attributes);
drawn++;
}
i=(u8)((i+1)&63);
}
for(n=drawn;n<slots;n++)__sprite_hide((u8)(first_oam+n));
return drawn;
}debug.h — RAM 紀錄與斷言
將名稱、數值及影格標記寫入固定容量的 RAM 記錄。斷言會保留診斷資訊,並讓程式繼續執行。
debug_assert_fail
保留斷言失敗代碼,並嘗試加入一筆 ASSERT 記錄。
語法
void debug_assert_fail(u16 code);參數
code要保留的 16 位元錯誤識別碼。
回傳值
無傳回值。
使用條件與限制
執行會繼續。即使記錄已滿,最後一次斷言代碼仍會更新。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_assert_fail(42);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例先記錄代碼 42,填滿記錄後再記錄代碼 999。筆數維持 32,但最後代碼變為 999。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:36
Store the assertion code even if the log is full, then attempt an ASSERT entry. The helper records failure but does not stop execution.
kitaqfc/lib/debug.c:67
void debug_assert_fail(u16 code)
{
kq_debug_last_assert = code;
debug_push(debug_assert_label, code);
}debug_get_last_assert
讀取最近的斷言代碼,不受記錄剩餘空間影響。
語法
u16 debug_get_last_assert(void);回傳值
傳回最近的 16 位元代碼,初始化後的初值為零。
使用條件與限制
零也是初始值,因此無法區分「尚未失敗」與「以代碼零記錄的失敗」。讀取不會清除代碼。
使用範例
result[22]=debug_get_last_assert();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例確認斷言巨集產生的 77、記錄填滿後的 999,以及重新初始化後的零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:42
Read the latest assertion code, initially zero after debug_init.
kitaqfc/lib/debug.c:86
u16 debug_get_last_assert(void)
{
return kq_debug_last_assert;
}debug_get_trace_count
讀取追蹤陣列中有效的項目筆數。
語法
u8 debug_get_trace_count(void);回傳值
傳回零至 DEBUG_TRACE_MAX 之間的筆數。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
result[1]=debug_get_trace_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例確認最初十筆記錄,以及繼續寫入後的上限 32;滿時筆數不會溢位回繞。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:38
Read the number of valid entries in the fixed trace buffer.
kitaqfc/lib/debug.c:74
u8 debug_get_trace_count(void)
{
return kq_debug_trace_count;
}debug_get_trace_log
取得內部陣列的參照,以檢視已記錄的名稱、數值與影格標記。
語法
const DebugTraceEntry* debug_get_trace_log(void);回傳值
傳回指向內部 DebugTraceEntry 陣列的唯讀指標。
使用條件與限制
這不是複本。只可讀取 debug_get_trace_count() 回報的筆數;初始化後殘留的舊位元組不是有效記錄。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
entries=debug_get_trace_log();for(i=0;i<10;i++){result[2+i]=entries[i].value;result[12+i]=entries[i].frame;}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例讀取全部十筆的數值與影格欄位,並確認 BEGIN 標籤的首字元為 B。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:40
Borrow the internal trace array; bound inspection by debug_get_trace_count.
kitaqfc/lib/debug.c:80
const DebugTraceEntry* debug_get_trace_log(void)
{
return kq_debug_trace_log;
}debug_init
初始化有效記錄長度、影格標記與最後一次斷言代碼。
語法
void debug_init(void);回傳值
無傳回值。
使用條件與限制
不會清除既有項目的位元組。請在寫入第一筆記錄前呼叫。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_init();result[0]=debug_get_trace_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例先確認初始筆數為零,再重設已有內容的記錄,確認筆數與斷言代碼歸零,而陣列中的舊值仍保留。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:25
Build the RAM-resident ASSERT label and reset log length, frame tag and last assertion code. Old log storage bytes are not erased.
kitaqfc/lib/debug.c:14
void debug_init(void)
{
debug_assert_label[0] = 'A';
debug_assert_label[1] = 'S';
debug_assert_label[2] = 'S';
debug_assert_label[3] = 'E';
debug_assert_label[4] = 'R';
debug_assert_label[5] = 'T';
debug_assert_label[6] = 0;
kq_debug_trace_count = 0;
kq_debug_frame = 0;
kq_debug_last_assert = 0;
}debug_mark_frame
記錄具名的影格標記,用來辨識流程中的特定位置。
語法
void debug_mark_frame(const u8* label);參數
label以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
回傳值
無傳回值。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_mark_frame("BEGIN");這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
加入 BEGIN 標記時,會記錄數值 65535(0xFFFF)與影格標記 513。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:29
Append a named marker with the reserved marker value 0xFFFF.
kitaqfc/lib/debug.c:48
void debug_mark_frame(const u8* label)
{
debug_push(label, 0xFFFF);
}debug_set_frame
設定之後各筆記錄要使用的影格標記。
語法
void debug_set_frame(u16 frame);參數
frame後續記錄使用的 16 位元影格編號。
回傳值
無傳回值。
使用條件與限制
不會等待影格,也不會自動遞增標記。請明確傳入遊戲的影格計數器。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_set_frame(513);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例將標記設為 513、寫入十筆記錄,再讀回全部十個影格欄位確認標記。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:27
Choose the frame tag stored in subsequent debug entries.
kitaqfc/lib/debug.c:29
void debug_set_frame(u16 frame)
{
kq_debug_frame = frame;
}debug_trace_u16
記錄具名的 16 位元分數或計數器。
語法
void debug_trace_u16(const u8* name, u16 value);參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value要記錄的值,範圍為 0~65535。
回傳值
無傳回值。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_trace_u16("WORD",4660);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
WORD 項目儲存 4660(0x1234),範例再讀回以確認兩個位元組。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:33
Append a 16-bit value with the current frame tag.
kitaqfc/lib/debug.c:60
void debug_trace_u16(const u8* name, u16 value)
{
debug_push(name, value);
}debug_trace_u8
將八位元狀態值連同名稱與目前影格標記一起記錄。
語法
void debug_trace_u8(const u8* name, u8 value);參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value範圍為 0~255 的值,以零擴展後存入記錄的 16 位元欄位。
回傳值
無傳回值。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_trace_u8("BYTE",255);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
BYTE 項目記錄 255,並確認記錄中的 16 位元數值欄位也包含 255。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:31
Widen a byte value into the trace entry's 16-bit value field.
kitaqfc/lib/debug.c:54
void debug_trace_u8(const u8* name, u8 value)
{
debug_push(name, (u16)value);
}KITAQGB_ASSERT
可作為陳述式使用的巨集,條件為假時記錄斷言代碼 1。
語法
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)參數
cond預期應成立的條件;零表示失敗。
回傳值
無傳回值。
使用條件與限制
條件只計算一次。為真時不記錄,為假時記錄失敗但不中止執行。採用 do…while (0) 形式,因此可在 if…else 中當作單一陳述式使用。
使用範例
KITAQGB_ASSERT(1);KITAQGB_ASSERT(0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
一個成立與一個不成立的斷言,合計只產生一筆代碼為 1 的記錄。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:48
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)KITAQGB_ASSERT_CODE
僅在條件為假時記錄指定的斷言代碼。
語法
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)參數
cond預期應成立的條件。
code失敗時才計算、並轉換為 16 位元的代碼運算式。
回傳值
無傳回值。
使用條件與限制
條件只計算一次;代碼運算式只在失敗時才計算。記錄後仍繼續執行。
使用範例
KITAQGB_ASSERT_CODE(1,++side_effect);KITAQGB_ASSERT_CODE(0,77);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
條件為真時不計算代碼運算式 ++side_effect,變數維持零。條件為假時記錄代碼 77。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:49
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)KITAQGB_MARK_FRAME
將標籤轉型為字串指標,並加入數值為 0xFFFF 的影格標記。
語法
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))參數
label以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
回傳值
無傳回值。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
KITAQGB_MARK_FRAME("END");這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
確認 END 標記的數值為 65535,影格標記為 513。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:47
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))KITAQGB_TRACE
將值明確轉換為 16 位元後,連同名稱一起記錄。
語法
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value記錄前會轉換為 16 位元的運算式。
回傳值
無傳回值。
使用條件與限制
巨集始終啟用,不會因建置設定而自動停用。其 16 位元記錄行為與 KITAQGB_TRACE_U16 相同。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
KITAQGB_TRACE("SCORE",600);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例記錄 600,再從記錄中讀回以驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:46
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))KITAQGB_TRACE_U16
將值明確轉換為 16 位元後,連同名稱一起記錄。
語法
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value記錄前會轉換為 16 位元的運算式。
回傳值
無傳回值。
使用條件與限制
巨集始終啟用,不會因建置設定而自動停用。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
KITAQGB_TRACE_U16("WORD2",500);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例記錄 500,再從記錄中讀回以驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:45
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))KITAQGB_TRACE_U8
將值明確轉換為八位元後,連同名稱一起記錄。
語法
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value記錄前會轉換為八位元的運算式。
回傳值
無傳回值。
使用條件與限制
巨集始終啟用,不會因建置設定而自動停用。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
KITAQGB_TRACE_U8("CAST",0x1234);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例記錄 52,僅保留 0x1234 的低位元組 0x34。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/debug.h:44
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))entity.h — 固定陣列物件池
entity 是以固定陣列管理敵人、子彈、道具等狀態的物件池。配置空閒槽位後,以 ID 存取;物件不再需要時,便可重複使用該槽位。它不會配置堆積記憶體。座標與速度的單位、移動、碰撞處理及計時器更新均由遊戲定義。
請包含 entity.h,並將 entity.c 編譯一次。先呼叫 entity_init,再確認 entity_create 未傳回 0xFF。ENTITY_MAX 預設為 16。ID 可支援 1~255 個槽位,但實際可配置數量取決於可用 RAM。所有編譯單元必須使用相同的容量定義。
entity_get 傳回的指標指向可重複使用的物件池儲存空間。釋放後,相同 ID 可能代表另一個物件,因此 ID 和指標都不是永久身分識別。entity_destroy 只會停用槽位。呼叫端必須自行隱藏或釋放精靈,並清理其他資源。sprite 欄位只記錄管理資訊,不會自動更新 OAM。
entity_update_all 與 entity_draw_all 依 ID 遞增順序巡訪啟用的槽位,並呼叫 fn(id)。實際更新或繪製工作請放在回呼中。回呼為 null 時不執行任何工作。在回呼內建立或釋放後面的槽位,會影響本次巡訪。先更新再繪製,可將兩項職責分開。
請將回呼放在共用 PRG 記憶體庫 0 中,或在整個呼叫期間維持其記憶體庫映射。函式指標只包含 16 位元 CPU 位址,不會切換記憶體庫。FC 函式的參數和區域變數使用固定記憶體,因此不要遞迴呼叫實體走訪,也不要從中斷重新進入同一走訪程序。
entity_clear_all
釋放所有實體,重設各欄位,包括未配置精靈的標記。
語法
void entity_clear_all(void);回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
將所有槽位的 active,type,x,y,vx,vy,state,timer 清為 0,sprite 設為 0xFF。不會隱藏或釋放硬體精靈,繪圖資源需另外清理。
使用範例
entity_clear_all();
after_clear = entity_count_active();
if (after_clear != 0 || entity_get(reused) != 0) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
FC 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm實作與原始碼
kitaqfc/lib/entity.h:47
Release every entity and restore deterministic defaults, including the no-sprite sentinel.
kitaqfc/lib/entity.c:14
void entity_clear_all(void)
{
u8 i;
i = 0;
while (i < ENTITY_MAX) {
entity_pool[(__safe_index u8)i].active = 0;
entity_pool[(__safe_index u8)i].type = 0;
entity_pool[(__safe_index u8)i].x = 0;
entity_pool[(__safe_index u8)i].y = 0;
entity_pool[(__safe_index u8)i].vx = 0;
entity_pool[(__safe_index u8)i].vy = 0;
entity_pool[(__safe_index u8)i].state = 0;
entity_pool[(__safe_index u8)i].timer = 0;
entity_pool[(__safe_index u8)i].sprite = 0xFF;
i = (u8)(i + 1);
}
}entity_count_active
回傳使用中的實體槽位數,不改變狀態。
語法
u8 entity_count_active(void);回傳值
active 位元組非零的槽位數,範圍為 0~ENTITY_MAX。表示占用數量,不是最大已配置 ID 或畫面上的精靈數量。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
使用範例
created = entity_count_active();
if (created != 2) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
FC 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm實作與原始碼
kitaqfc/lib/entity.h:45
Count occupied slots without changing entity state.
kitaqfc/lib/entity.c:94
u8 entity_count_active(void)
{
u8 i;
u8 count;
i = 0;
count = 0;
while (i < ENTITY_MAX) {
if (entity_pool[(__safe_index u8)i].active != 0) count = (u8)(count + 1);
i = (u8)(i + 1);
}
return count;
}entity_create
依指定類型與位置配置實體,回傳可重用的 ID;沒有空位時回傳 0xFF。
語法
u8 entity_create(u8 type, s16 x, s16 y);參數
type由遊戲定義的類型編號,範圍 0~255。池僅儲存此值,不會據此選擇行為或繪圖函式。
x, y帶正負號的 16 位元座標(
-32768~32767)。像素或 Q8.8 等單位由遊戲決定;池不轉換單位、裁切位置或自動套用速度。
回傳值
回傳編號最小的空閒槽位 ID(0~ENTITY_MAX-1),無空位時回傳 0xFF。成功時設 active=1,儲存類型與位置,清零速度、狀態、計時器,並設 sprite=0xFF。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
使用範例
first = entity_create(1, 2, 12);
second = entity_create(2, 6, 12);
if (first == 0xFF || second == 0xFF) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
FC 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm實作與原始碼
kitaqfc/lib/entity.h:32
Returns a reusable slot ID, or 0xFF if no slot is free.
kitaqfc/lib/entity.c:34
u8 entity_create(u8 type, s16 x, s16 y)
{
u8 i;
i = 0;
while (i < ENTITY_MAX) {
if (entity_pool[(__safe_index u8)i].active == 0) {
entity_pool[(__safe_index u8)i].active = 1;
entity_pool[(__safe_index u8)i].type = type;
entity_pool[(__safe_index u8)i].x = x;
entity_pool[(__safe_index u8)i].y = y;
entity_pool[(__safe_index u8)i].vx = 0;
entity_pool[(__safe_index u8)i].vy = 0;
entity_pool[(__safe_index u8)i].state = 0;
entity_pool[(__safe_index u8)i].timer = 0;
entity_pool[(__safe_index u8)i].sprite = 0xFF;
return i;
}
i = (u8)(i + 1);
}
return 0xFF;
}entity_destroy
釋放 id 對應的實體槽位;保留的資料會在重新配置時初始化。
語法
void entity_destroy(u8 id);參數
id可重用的槽位索引,範圍為 0~
ENTITY_MAX-1。範圍外 ID 無效;釋放無效 ID 不產生效果,查詢則回傳 null。
回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
釋放操作僅將 active 清為 0,不清除其他欄位,也不釋放精靈或素材。之後可能將相同 ID 與位址重用於另一實體。關聯資源由遊戲負責清理。
使用範例
entity_destroy(first);
after_free = entity_count_active();
if (entity_get(first) != 0 || after_free != 1) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
FC 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm實作與原始碼
kitaqfc/lib/entity.h:35
Release a valid slot without clearing its payload. Reallocation resets the payload; a saved pointer or ID must not be treated as a persistent entity identity.
kitaqfc/lib/entity.c:58
void entity_destroy(u8 id)
{
if (id >= ENTITY_MAX) return;
entity_pool[(__safe_index u8)id].active = 0;
}entity_draw_all
走訪使用中實體,將每個 ID 傳給繪圖回呼。走訪方式與 entity_update_all 相同;只有回呼提交繪圖資料時,才會繪製精靈或像素。
語法
void entity_draw_all(EntityFn fn);參數
fn簽章為
void fn(u8 id)的函式指標。接收槽位 ID,可用entity_get(id)存取欄位。允許 null,此時不呼叫。
回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
走訪到槽位時才檢查其使用狀態。回呼可停用後面的槽位使其被略過,也可啟用後面的槽位使其在本輪被走訪。並非走訪開始時使用中集合的快照。
請將回呼放在共用 PRG 記憶體庫 0 中,或在整個呼叫期間維持其記憶體庫映射。函式指標只包含 16 位元 CPU 位址,不會切換記憶體庫。FC 函式的參數和區域變數使用固定記憶體,因此不要遞迴呼叫實體走訪,也不要從中斷重新進入同一走訪程序。
使用範例
void demo_draw(u8 id) {
Entity* entity;
entity = entity_get(id);
if (entity != 0) {
m_put((u8)entity->x, (u8)entity->y, (u8)('A' + entity->type - 1));
draw_calls++;
}
}
// From main(), after creating two entities:
draw_calls = 0;
entity_draw_all(demo_draw);
automatic_draws = draw_calls;
if (automatic_draws != 2) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
FC 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm實作與原始碼
kitaqfc/lib/entity.h:43
Call the drawing callback for each active slot, using the same traversal rules as update. The callback submits drawing data; the pool does not allocate sprites.
kitaqfc/lib/entity.c:88
void entity_draw_all(EntityFn fn)
{
entity_update_all(fn);
}entity_get
回傳有效使用中實體的指標;ID 無效或未使用時回傳 null。池內空間可能再次配置。
語法
Entity* entity_get(u8 id);參數
id可重用的槽位索引,範圍為 0~
ENTITY_MAX-1。範圍外 ID 無效;釋放無效 ID 不產生效果,查詢則回傳 null。
回傳值
回傳可寫入的使用中槽位指標;ID 無效或未使用時回傳 null。記憶體由池擁有,請勿自行釋放,也不要將指標當作跨越刪除與重新配置的永久身分。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
釋放操作僅將 active 清為 0,不清除其他欄位,也不釋放精靈或素材。之後可能將相同 ID 與位址重用於另一實體。關聯資源由遊戲負責清理。
使用範例
current_entity = entity_get(first);
if (current_entity != 0) { current_entity->vx = 5; }
else { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
FC 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm實作與原始碼
kitaqfc/lib/entity.h:37
Returns null for an invalid or inactive ID; the returned pointer aliases reusable pool storage.
kitaqfc/lib/entity.c:66
Entity* entity_get(u8 id)
{
if (id >= ENTITY_MAX) return 0;
if (entity_pool[(__safe_index u8)id].active == 0) return 0;
return &entity_pool[(__safe_index u8)id];
}entity_init
初始化實體池的所有槽位。
語法
void entity_init(void);回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
將所有槽位的 active,type,x,y,vx,vy,state,timer 清為 0,sprite 設為 0xFF。不會隱藏或釋放硬體精靈,繪圖資源需另外清理。
使用範例
entity_init();
if (entity_count_active() != 0) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
FC 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm實作與原始碼
kitaqfc/lib/entity.h:30
Reset every slot before the game starts using the pool.
kitaqfc/lib/entity.c:8
void entity_init(void)
{
entity_clear_all();
}entity_update_all
依 ID 遞增順序走訪使用中槽位,對每個呼叫一次 fn(id)。移動、碰撞或計時器邏輯由回呼實作,池本身不提供這些邏輯。回呼為 null 時不執行任何操作。
語法
void entity_update_all(EntityFn fn);參數
fn簽章為
void fn(u8 id)的函式指標。接收槽位 ID,可用entity_get(id)存取欄位。允許 null,此時不呼叫。
回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
走訪到槽位時才檢查其使用狀態。回呼可停用後面的槽位使其被略過,也可啟用後面的槽位使其在本輪被走訪。並非走訪開始時使用中集合的快照。
請將回呼放在共用 PRG 記憶體庫 0 中,或在整個呼叫期間維持其記憶體庫映射。函式指標只包含 16 位元 CPU 位址,不會切換記憶體庫。FC 函式的參數和區域變數使用固定記憶體,因此不要遞迴呼叫實體走訪,也不要從中斷重新進入同一走訪程序。
使用範例
void demo_update(u8 id) {
Entity* entity;
entity = entity_get(id);
if (entity != 0) { entity->x = entity->x + 1; update_calls++; }
}
// From main(), after creating two entities:
update_calls = 0;
entity_update_all(demo_update);
automatic_updates = update_calls;
if (automatic_updates != 2) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
FC 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm實作與原始碼
kitaqfc/lib/entity.h:40
Call fn(id) for each active slot in ascending order. A null callback does nothing. Changes to later slots take effect during the same traversal. Do not reenter this traversal.
kitaqfc/lib/entity.c:75
void entity_update_all(EntityFn fn)
{
u8 i;
if (fn == 0) return;
i = 0;
while (i < ENTITY_MAX) {
if (entity_pool[(__safe_index u8)i].active != 0) fn(i);
i = (u8)(i + 1);
}
}FDS 檔案與固定大小的存檔槽位
fds_file.h 提供將檔案載入遊戲緩衝區,以及寫入磁碟預留存檔槽位的功能。fds_save.h 引入相同的宣告。呼叫覆疊程式碼時,請使用 fds_overlay.h。
__fds_load_file() / __fds_save_file()
fds_file_io.c fds_file_io_manifest.json fds_file_io_payload.bin
fds_sound.h
宣告供 64 階波形、調變表、音高、音量與包絡使用的編譯器內建函式,由 KITAQFC 產生實作。
以 --mapper=fds 建置 .fds 映像。此範例不進行磁碟 I/O,只操作聲音。錄音使用 KUROSAKI 的 RAM 直接啟動與音訊模型。測試使用的空韌體未實作 BIOS 常式,也不隨附散布。一般磁碟啟動與實機需要適當的啟動環境。
函式參考: __fds_sound_enable, __fds_wave_load, __fds_mod_load, __fds_freq_set, __fds_volume_set, __fds_env_set
fixed.h — Q8.8 定點運算與矩形
Q8.8 運算以整數表示含小數的座標與速度,並提供矩形及點的碰撞測試。請確認各項運算的精度與範圍限制。
fix_div
降低運算元精度後執行 Q8.8 除法。
語法
fix8 fix_div(fix8 a, fix8 b);參數
aQ8.8 格式的左運算元。
bQ8.8 格式的右運算元。
回傳值
傳回 Q8.8 商;b == 0 時傳回零。
使用條件與限制
運算式為 ((a >> 4) * 256) / (b >> 4)。非零除數在位移後仍須非零,因此不可傳入原始值 1~15 的正數。放大後的分子也必須能以 16 位元表示。
使用範例
result[3]=fix_div(768,512);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
3.0 除以 2.0 得到 1.5(原始值 384)。另有檢查確認除數恰為零時的明確傳回行為。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:35
Scale the reduced-precision quotient back to 8.8 and return zero for b == 0. Callers must also ensure (b >> 4) is nonzero; the explicit check only tests b. The intermediate product must fit the compiler's integer arithmetic.
kitaqfc/lib/fixed.c:26
fix8 fix_div(fix8 a, fix8 b)
{
if (b == 0) return 0;
return (fix8)(((a >> 4) * 256) / (b >> 4));
}fix_from_int
將整數座標或速度轉換為 Q8.8,讓後續運算保留小數部分。
語法
fix8 fix_from_int(s16 n);參數
n要轉換的整數,範圍為 −128~127。
回傳值
傳回原始值 n × 256。
使用條件與限制
fix8 是帶正負號的 Q8.8 格式,原始值 256 代表 1.0。中間值與結果都必須維持在 16 位元範圍內。
使用範例
result[0]=fix_from_int(-3);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例轉換 −3。畫面上的 −00768 表示 Q8.8 的原始結果 −768。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:26
Convert an integer to signed 8.8 fixed point by moving it into the high byte. The caller must keep the result within the representable 16-bit range.
kitaqfc/lib/fixed.c:5
fix8 fix_from_int(s16 n)
{
return (fix8)(n << 8);
}fix_lerp
使用八位元權重,從一個 Q8.8 值朝另一個值進行內插。
語法
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8);參數
aQ8.8 格式的左運算元。
bQ8.8 格式的右運算元。
t_q8內插權重,範圍為 0~255。
回傳值
傳回近似內插所得的 Q8.8 值。
使用條件與限制
差值與權重各向右移四位,因此權重只有 16 個等級,即使指定 255 也不一定能到達終點。b - a 與最終結果均須保持在 16 位元範圍內。
使用範例
result[4]=fix_lerp(0,1024,128);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 0 與 4.0 之間使用權重 128,得到 2.0(原始值 512)。權重 255 則得到 3.75(原始值 960),顯示結果未到達終點。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:38
Interpolate toward b using a quantized Q0.8 weight. Both shifts discard low bits, so small changes may vanish and a weight of 255 need not reach b.
kitaqfc/lib/fixed.c:34
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8)
{
fix8 d;
// The endpoint difference must fit s16 before the reduced-precision interpolation.
d = (fix8)(b - a);
return (fix8)(a + (fix8)((d >> 4) * (s16)(t_q8 >> 4)));
}fix_mul
以運算成本較低的近似方法將兩個 Q8.8 值相乘。
語法
fix8 fix_mul(fix8 a, fix8 b);參數
aQ8.8 格式的左運算元。
bQ8.8 格式的右運算元。
回傳值
以 Q8.8 格式傳回乘積。
使用條件與限制
相乘前會將兩個運算元各向右移四位,捨去各自的低四位元,因此精確度低於完整的 16×16 位元乘法。fix8 是帶正負號的 Q8.8,原始值 256 代表 1.0。中間值與結果都須保持在 16 位元範圍內。
使用範例
result[2]=fix_mul(384,512);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
1.5 乘以 2.0 得到 3.0(原始值 768)。程式也檢查量化情況:原始值 271 乘以原始值 271,結果為 256。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:31
Approximate 8.8 multiplication by discarding four low bits from each operand before multiplying. This trades precision for a smaller intermediate product.
kitaqfc/lib/fixed.c:18
fix8 fix_mul(fix8 a, fix8 b)
{
return (fix8)((a >> 4) * (b >> 4));
}fix_to_int
捨去 Q8.8 的小數位元以取得整數座標。負數會朝負無限大方向取整。
語法
s16 fix_to_int(fix8 x);參數
x要轉換為整數的 Q8.8 值。
回傳值
傳回帶正負號的整數。
使用條件與限制
fix8 是帶正負號的 Q8.8 格式,原始值 256 代表 1.0。中間值與結果都必須維持在 16 位元範圍內。
使用範例
result[1]=fix_to_int(-384);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
傳入原始值 −384(−1.5)會得到 −2,顯示為 −00002。邊界檢查也確認原始值 −1 會轉換為 −1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:28
Discard the eight fractional bits using a signed right shift.
kitaqfc/lib/fixed.c:11
s16 fix_to_int(fix8 x)
{
return (s16)(x >> 8);
}kq_abs_s16
求帶正負號之 16 位元值的絕對值。
語法
s16 kq_abs_s16(s16 v);參數
v要求絕對值的帶正負號 16 位元值。
回傳值
傳回非負的絕對值,但 −32768 的絕對值無法以此型別表示。
使用條件與限制
正值 32768 無法存入 s16。若要求結果必須非負,請排除輸入 −32768。
使用範例
result[0]=kq_abs_s16(-123);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例將 −123 轉為 123,可用於求座標差的大小。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math_limits.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:41
Return the magnitude in s16. The most-negative s16 has no positive s16 representation and must be excluded by callers needing a nonnegative result.
kitaqfc/lib/fixed.c:44
s16 kq_abs_s16(s16 v)
{
if (v < 0) return (s16)(0 - v);
return v;
}kq_clamp_s16
將座標或速度限制在包含兩端的區間內。
語法
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi);參數
v要限制範圍的帶正負號值。
lo下限,包含此值。
hi上限,包含此值。
回傳值
低於區間時傳回 lo,高於區間時傳回 hi,位於區間內則傳回 v。
使用條件與限制
請提供符合 lo <= hi 的有效區間。
使用範例
result[3]=kq_clamp_s16(25,-10,10);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
將 25 限制在 −10~10 之間會得到 10。檢查也涵蓋下限外的 −11→−10,以及區間內的 3→3。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math_limits.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:47
Clamp to an inclusive interval; callers must provide lo <= hi.
kitaqfc/lib/fixed.c:65
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi)
{
if (v < lo) return lo;
if (v > hi) return hi;
return v;
}kq_max_s16
選取兩個帶正負號 16 位元值中較大者。
語法
s16 kq_max_s16(s16 a, s16 b);參數
a第一個要比較的帶正負號值。
b第二個要比較的帶正負號值。
回傳值
傳回選取的運算元。
使用條件與限制
比較時會考慮正負號。兩個運算元相等時傳回該值;兩個輸入都不會被修改。
使用範例
result[2]=kq_max_s16(-7,4);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
比較 −7 與 4 得到 4。負數結果會顯示負號。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math_limits.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:45
Select the larger signed value.
kitaqfc/lib/fixed.c:58
s16 kq_max_s16(s16 a, s16 b)
{
if (a > b) return a;
return b;
}kq_min_s16
選取兩個帶正負號 16 位元值中較小者。
語法
s16 kq_min_s16(s16 a, s16 b);參數
a第一個要比較的帶正負號值。
b第二個要比較的帶正負號值。
回傳值
傳回選取的運算元。
使用條件與限制
比較時會考慮正負號。兩個運算元相等時傳回該值;兩個輸入都不會被修改。
使用範例
result[1]=kq_min_s16(-7,4);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
比較 −7 與 4 得到 -7。負數結果會顯示負號。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math_limits.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:43
Select the smaller signed value.
kitaqfc/lib/fixed.c:51
s16 kq_min_s16(s16 a, s16 b)
{
if (a < b) return a;
return b;
}kq_point_in_rect
檢查點是否位於矩形內,包含左邊界與上邊界。
語法
u8 kq_point_in_rect(s16 x, s16 y, KQRect r);參數
x點的 X 座標,使用矩形的座標系。
y點的 Y 座標。
r要檢查的矩形,以值傳遞。
回傳值
位於內部時傳回 1,外部時傳回 0。
使用條件與限制
尺寸必須為正,座標加尺寸的結果須能以 s16 表示。右邊界與下邊界不包含在內。函式不會明確拒絕面積為零的矩形。
使用範例
result[1]=kq_point_in_rect(9,1,a);
for(gy=0;gy<11;gy++){for(gx=0;gx<15;gx++){
inside_a=kq_point_in_rect(gx,gy,a);inside_b=kq_point_in_rect(gx,gy,b);
tile=0;if(inside_a){tile=65;result[3]=result[3]+1;}if(inside_b)tile=66;if(inside_a && inside_b){tile=79;result[4]=result[4]+1;}
m_put(1+gx,2+gy,tile);__vramq_commit();__vramq_exec();
}}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
每個座標單位佔一個圖塊。矩形 A 位於 (1,1),B 位於 (5,4),兩者大小皆為 8×6。僅屬於 A 的格子顯示 A,僅屬於 B 的格子顯示 B;4×3 的重疊區域顯示 12 個 O。A 的右邊界 x=9 不包含在內。CGB 上的 A 為紅色、B 為藍色、O 為綠色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_geometry.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:54
Test a half-open rectangle: left/top edges are included, right/bottom excluded. The coordinate-plus-size sums must remain representable as s16.
kitaqfc/lib/fixed.c:86
u8 kq_point_in_rect(s16 x, s16 y, KQRect r)
{
if (x < r.x) return 0;
if (y < r.y) return 0;
if (x >= (s16)(r.x + r.w)) return 0;
if (y >= (s16)(r.y + r.h)) return 0;
return 1;
}kq_rect_intersect
檢查兩個與座標軸對齊的矩形是否具有面積大於零的重疊區域。
語法
u8 kq_rect_intersect(KQRect a, KQRect b);參數
a以值傳遞的第一個矩形:
x, y為左上角位置,w, h為寬度與高度。b與 A 使用相同座標系的第二個矩形。
回傳值
重疊時傳回 1;分離或僅邊緣接觸時傳回 0。
使用條件與限制
尺寸必須為正,座標加尺寸的結果須能以 s16 表示。右邊界與下邊界不包含在內。函式不會明確拒絕面積為零的矩形。
使用範例
result[0]=kq_rect_intersect(a,b);result[2]=kq_rect_intersect(a,touch);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
每個座標單位佔一個圖塊。矩形 A 位於 (1,1),B 位於 (5,4),兩者大小皆為 8×6。僅屬於 A 的格子顯示 A,僅屬於 B 的格子顯示 B;4×3 的重疊區域顯示 12 個 O。A 的右邊界 x=9 不包含在內。CGB 上的 A 為紅色、B 為藍色、O 為綠色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_geometry.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/fixed.h:51
Test overlap using exclusive right/bottom edges; touching edges do not collide. Require positive dimensions and edge sums that fit s16; zero-sized rectangles are not explicitly rejected and may be reported as overlapping.
kitaqfc/lib/fixed.c:75
u8 kq_rect_intersect(KQRect a, KQRect b)
{
if ((s16)(a.x + a.w) <= b.x) return 0;
if ((s16)(b.x + b.w) <= a.x) return 0;
if ((s16)(a.y + a.h) <= b.y) return 0;
if ((s16)(b.y + b.h) <= a.y) return 0;
return 1;
}input.h — 按鈕狀態、按下、放開及重複
連續移動用 input_down,單次動作用 input_pressed,放開時停止用 input_released,選單重複操作用 input_repeat。初始化一次,每個輸入週期更新一次,再依需求查詢。btn_down、btn_pressed、btn_released、btn_repeat 分別是這四個查詢函式的別名。
透過 __pad_read1_safe 讀取控制器 1,將 NES 位元順序轉換為共用 BTN_* 格式,保存前次狀態,並計算按下、放開及重複觸發遮罩。不處理控制器 2。每個輸入週期呼叫一次。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
btn_down
btn_down 是 input_down 的別名,檢查所選按鈕是否至少有一個目前被按住。
判斷 mask 選取的按鈕是否至少有一個正被按住。
語法
u8 btn_down(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (btn_down(BTN_A)!=0) held_ticks++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_aliases.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:53
#define btn_down input_downkitaqfc/lib/input.c:85
u8 input_down(u8 mask) { return (u8)((kq_input_keys & mask) != 0); }btn_pressed
btn_pressed 是 input_pressed 的別名,檢查最近一次輸入更新時,所選按鈕是否至少有一個剛被按下。
判斷最近一次輸入更新中,遮罩選取的按鈕是否從放開變成按下。
語法
u8 btn_pressed(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (btn_pressed(BTN_A)!=0) {
press_count++; seen_press=1;
first_down=btn_down(BTN_A); first_press=btn_pressed(BTN_A);
first_repeat=btn_repeat(BTN_A);
first_current=input_current(); // Only A held: BTN_A, or decimal 16.
first_previous=input_previous(); // No buttons in the preceding sample: 0.
if (first_down!=1 || first_press!=1 || first_repeat!=1) failures++;
if (first_current!=BTN_A || first_previous!=0) failures++;
if (btn_down(BTN_A|BTN_B)!=1 || btn_down(0)!=0) failures++;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_aliases.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:54
#define btn_pressed input_pressedkitaqfc/lib/input.c:87
u8 input_pressed(u8 mask) { return (u8)((kq_input_press_keys & mask) != 0); }btn_released
btn_released 是 input_released 的別名,檢查最近一次輸入更新時,所選按鈕是否至少有一個被放開。
判斷最近一次輸入更新中,遮罩選取的按鈕是否從按下變成放開。
語法
u8 btn_released(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (btn_released(BTN_A)!=0) {
release_result=btn_released(BTN_A);
last_current=input_current(); last_previous=input_previous();
if (btn_down(BTN_A)!=0 || btn_pressed(BTN_A)!=0 || btn_repeat(BTN_A)!=0) failures++;
break;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_aliases.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:55
#define btn_released input_releasedkitaqfc/lib/input.c:89
u8 input_released(u8 mask) { return (u8)((kq_input_release_keys & mask) != 0); }btn_repeat
btn_repeat 是 input_repeat 的別名,檢查首次按下,或持續按住期間按排程發出的重複訊號。
判斷遮罩選取的按鈕是否產生首次按下或定時重複輸入。
語法
u8 btn_repeat(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
使用範例
if (btn_repeat(BTN_A)!=0) {
// The initial press is pulse 1. Defaults then wait 19 updates, followed by 6.
if (repeat_count==1 && held_ticks-previous_pulse!=19) failures++;
if (repeat_count>1 && held_ticks-previous_pulse!=6) failures++;
previous_pulse=held_ticks; repeat_count++;
if (btn_repeat(BTN_A)!=1) failures++; // Reading again does not consume it.
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_aliases.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:56
#define btn_repeat input_repeatkitaqfc/lib/input.c:91
u8 input_repeat(u8 mask) { return (u8)((kq_input_repeat_keys & mask) != 0); }input_current
回傳最近一次輸入更新取得的全部按住按鈕位元遮罩。
語法
u8 input_current(void);回傳值
共用 BTN_* 格式的 8 位元遮罩。多個按鈕可以同時設為 1;0 表示沒有按鈕。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
first_current=input_current(); // Only A held: BTN_A, or decimal 16.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:49
Read the complete translated held-button mask.
kitaqfc/lib/input.c:93
u8 input_current(void) { return kq_input_keys; }input_down
判斷 mask 選取的按鈕是否至少有一個正被按住。
語法
u8 input_down(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (input_down(BTN_A)!=0) held_ticks++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:41
Return true when any masked logical button is held.
kitaqfc/lib/input.c:85
u8 input_down(u8 mask) { return (u8)((kq_input_keys & mask) != 0); }input_init
將目前、前次、按下、放開及重複觸發遮罩清為 0,並將八個重複計時器重設為 INPUT_REPEAT_DELAY。本函式初始化輸入函式庫,但不讀取控制器。接著第一次更新時按住的按鈕會被視為新按下。
語法
void input_init(void);回傳值
無(void)。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
使用範例
input_init();
if (input_current()!=0 || input_previous()!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:35
Clear held/edge/repeat masks and reset each independent repeat countdown.
kitaqfc/lib/input.c:34
void input_init(void)
{
u8 i;
kq_input_prev_keys = 0;
kq_input_keys = 0;
kq_input_press_keys = 0;
kq_input_release_keys = 0;
kq_input_repeat_keys = 0;
i = 0;
while (i < 8) {
input_repeat_timer[i] = INPUT_REPEAT_DELAY;
i = (u8)(i + 1);
}
}input_pressed
判斷最近一次輸入更新中,遮罩選取的按鈕是否從放開變成按下。
語法
u8 input_pressed(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (input_pressed(BTN_A)!=0) {
press_count++; seen_press=1;
first_down=input_down(BTN_A); first_press=input_pressed(BTN_A);
first_repeat=input_repeat(BTN_A);
first_current=input_current(); // Only A held: BTN_A, or decimal 16.
first_previous=input_previous(); // No buttons in the preceding sample: 0.
if (first_down!=1 || first_press!=1 || first_repeat!=1) failures++;
if (first_current!=BTN_A || first_previous!=0) failures++;
if (input_down(BTN_A|BTN_B)!=1 || input_down(0)!=0) failures++;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:43
Return true when any masked button became pressed in the latest input update.
kitaqfc/lib/input.c:87
u8 input_pressed(u8 mask) { return (u8)((kq_input_press_keys & mask) != 0); }input_previous
回傳最近一次更新之前保存的按住按鈕位元遮罩。
語法
u8 input_previous(void);回傳值
共用 BTN_* 格式的 8 位元遮罩。多個按鈕可以同時設為 1;0 表示沒有按鈕。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
first_previous=input_previous(); // No buttons in the preceding sample: 0.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:51
Read the translated held-button mask from before the latest update.
kitaqfc/lib/input.c:95
u8 input_previous(void) { return kq_input_prev_keys; }input_released
判斷最近一次輸入更新中,遮罩選取的按鈕是否從按下變成放開。
語法
u8 input_released(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (input_released(BTN_A)!=0) {
release_result=input_released(BTN_A);
last_current=input_current(); last_previous=input_previous();
if (input_down(BTN_A)!=0 || input_pressed(BTN_A)!=0 || input_repeat(BTN_A)!=0) failures++;
break;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:45
Return true when any masked button became released in the latest update.
kitaqfc/lib/input.c:89
u8 input_released(u8 mask) { return (u8)((kq_input_release_keys & mask) != 0); }input_repeat
判斷遮罩選取的按鈕是否產生首次按下或定時重複輸入。
語法
u8 input_repeat(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
使用範例
if (input_repeat(BTN_A)!=0) {
// The initial press is pulse 1. Defaults then wait 19 updates, followed by 6.
if (repeat_count==1 && held_ticks-previous_pulse!=19) failures++;
if (repeat_count>1 && held_ticks-previous_pulse!=6) failures++;
previous_pulse=held_ticks; repeat_count++;
if (input_repeat(BTN_A)!=1) failures++; // Reading again does not consume it.
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:47
Return true for a masked initial press or scheduled repeat pulse.
kitaqfc/lib/input.c:91
u8 input_repeat(u8 mask) { return (u8)((kq_input_repeat_keys & mask) != 0); }input_update
透過 __pad_read1_safe 讀取控制器 1,將 NES 位元順序轉換為共用 BTN_* 格式,保存前次狀態,並計算按下、放開及重複觸發遮罩。不處理控制器 2。每個輸入週期呼叫一次。
語法
void input_update(void);回傳值
無(void)。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
safe 版本成對讀取全部按鈕,直到兩次遮罩相同。每次讀取都會對 $4016 發出選通信號,將兩個控制器的序列讀取位置重設為開頭。重試次數沒有上限。此一致性檢查不代表已驗證所有 DMC 與周邊裝置組合。
使用範例
input_update(); // One update per input tick, followed by any number of queries.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input.h:39
Read controller 1 through the safe intrinsic, translate its bit order and derive press/release edges. Repeat delays count calls to this function, so call it once per intended input tick.
kitaqfc/lib/input.c:52
void input_update(void)
{
u8 i;
u8 raw;
kq_input_prev_keys = kq_input_keys;
raw = __pad_read1_safe();
kq_input_keys = input_translate_pad(raw);
kq_input_press_keys = (u8)(kq_input_keys & (u8)(kq_input_keys ^ kq_input_prev_keys));
kq_input_release_keys = (u8)(kq_input_prev_keys & (u8)(kq_input_keys ^ kq_input_prev_keys));
kq_input_repeat_keys = kq_input_press_keys;
i = 0;
while (i < 8) {
u8 mask;
mask = input_mask_for_index(i);
if ((kq_input_keys & mask) != 0) {
if ((kq_input_press_keys & mask) != 0) {
input_repeat_timer[i] = INPUT_REPEAT_DELAY;
} else if (input_repeat_timer[i] != 0) {
input_repeat_timer[i] = (u8)(input_repeat_timer[i] - 1);
} else {
kq_input_repeat_keys = (u8)(kq_input_repeat_keys | mask);
input_repeat_timer[i] = INPUT_REPEAT_RATE;
}
} else {
input_repeat_timer[i] = INPUT_REPEAT_DELAY;
}
i = (u8)(i + 1);
}
}input_repeat.h — 長按重複輸入
本函式庫與 pad.c 搭配,為控制器 1 的各按鈕提供獨立重複計數器。執行時設定等待與間隔,讀取手把後,每個輸入週期推進一次重複狀態。新按下、放開與按住查詢使用手把快照;只有重複查詢依賴 nes_pad_repeat_step() 的結果。
初始倒數值,範圍 0~255。新按下立即觸發後,再經過 delay + 1 次重複更新觸發下一次。單位為 nes_pad_repeat_step() 的呼叫次數,只有每影格恰好呼叫一次時才等於影格數。
後續觸發之間的倒數值,範圍 0~255。實際間隔為 interval + 1 次重複更新;0 表示初始等待結束後,每次按住更新都觸發。八個按鈕獨立計數。
nes_pad_held
篩選控制器 1 最近一次的按住遮罩,適合在選中按鈕持續按住時連續執行動作。只讀取快取,不會再次讀取硬體。
語法
unsigned char nes_pad_held(unsigned char mask);參數
mask依 NES 原始位元順序指定要保留的按鈕,需要時以
|組合。0 表示不選任何按鈕。這是位元篩選遮罩,不是控制器連接埠編號。
回傳值
回傳快取遮罩中符合條件的位元,保留原本的位置。結果可能不是 1;0 表示沒有符合的按鈕。讀取不會消耗事件。
使用條件與限制
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
第一次讀取前,將四個 nes_pad1_* 狀態位元組初始化為 0。之後每個輸入週期讀取一次。pressed = current & ~previous,released = previous & ~current,兩者表示最近一次讀取發生的變化。重複狀態需另行呼叫 nes_pad_repeat_step() 更新。
使用範例
if (nes_pad_held(0x02)!=0) held_ticks++; // B is bit 1 in NES raw format.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範輪詢→更新連發→查詢狀態的順序,並說明NES查詢函式回傳對應位元,而非布林值1。使用nes_pad_repeat_config(3, 1),按住B達40次更新後放開。FIRST HELD、FIRST TRIGGER、FIRST REPEAT為2,HELD TICKS為40,PULSE COUNT為19,RELEASE BITS為2。初次按下的脈衝之後經過4次更新產生首次連發,隨後每2次更新產生一次。FAILED CHECKS應為0。改變按住的時間會改變脈衝計數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input_repeat.h:28
Return the requested currently-held bits in the NES pad layout.
kitaqfc/lib/input_repeat.c:103
unsigned char nes_pad_held(unsigned char mask)
{
return (unsigned char)(nes_pad1_cur & mask);
}nes_pad_release
篩選控制器 1 最近一次的放開遮罩,識別前次按住、這次已放開的選中按鈕。繼續保持放開,不會在下次讀取時再次產生放開事件。
語法
unsigned char nes_pad_release(unsigned char mask);參數
mask依 NES 原始位元順序指定要保留的按鈕,需要時以
|組合。0 表示不選任何按鈕。這是位元篩選遮罩,不是控制器連接埠編號。
回傳值
回傳快取遮罩中符合條件的位元,保留原本的位置。結果可能不是 1;0 表示沒有符合的按鈕。讀取不會消耗事件。
使用條件與限制
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
第一次讀取前,將四個 nes_pad1_* 狀態位元組初始化為 0。之後每個輸入週期讀取一次。pressed = current & ~previous,released = previous & ~current,兩者表示最近一次讀取發生的變化。重複狀態需另行呼叫 nes_pad_repeat_step() 更新。
使用範例
if (nes_pad_release(0x02)!=0) {
release_bits=nes_pad_release(0x02); // Returns the released B bit, 2.
if (nes_pad_held(0x02)!=0 || nes_pad_trigger(0x02)!=0 || nes_pad_repeat(0x02)!=0) failures++;
break;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範輪詢→更新連發→查詢狀態的順序,並說明NES查詢函式回傳對應位元,而非布林值1。使用nes_pad_repeat_config(3, 1),按住B達40次更新後放開。FIRST HELD、FIRST TRIGGER、FIRST REPEAT為2,HELD TICKS為40,PULSE COUNT為19,RELEASE BITS為2。初次按下的脈衝之後經過4次更新產生首次連發,隨後每2次更新產生一次。FAILED CHECKS應為0。改變按住的時間會改變脈衝計數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input_repeat.h:26
Return the requested newly-released bits from the latest pad poll.
kitaqfc/lib/input_repeat.c:97
unsigned char nes_pad_release(unsigned char mask)
{
return (unsigned char)(nes_pad1_released & mask);
}nes_pad_repeat
篩選最近一次 nes_pad_repeat_step() 產生的重複觸發位元,包含新按下與按住後的定時重複。呼叫此查詢函式不會推進計時。
語法
unsigned char nes_pad_repeat(unsigned char mask);參數
mask依 NES 原始位元順序指定要保留的按鈕,需要時以
|組合。0 表示不選任何按鈕。這是位元篩選遮罩,不是控制器連接埠編號。
回傳值
回傳快取遮罩中符合條件的位元,保留原本的位置。結果可能不是 1;0 表示沒有符合的按鈕。讀取不會消耗事件。
使用條件與限制
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
第一次讀取前,將四個 nes_pad1_* 狀態位元組初始化為 0。之後每個輸入週期讀取一次。pressed = current & ~previous,released = previous & ~current,兩者表示最近一次讀取發生的變化。重複狀態需另行呼叫 nes_pad_repeat_step() 更新。
使用範例
if (nes_pad_repeat(0x02)!=0) {
if (pulse_count==1 && held_ticks-previous_pulse!=4) failures++;
if (pulse_count>1 && held_ticks-previous_pulse!=2) failures++;
previous_pulse=held_ticks; pulse_count++;
if (nes_pad_repeat(0x02)!=2) failures++; // Querying again preserves the pulse.
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範輪詢→更新連發→查詢狀態的順序,並說明NES查詢函式回傳對應位元,而非布林值1。使用nes_pad_repeat_config(3, 1),按住B達40次更新後放開。FIRST HELD、FIRST TRIGGER、FIRST REPEAT為2,HELD TICKS為40,PULSE COUNT為19,RELEASE BITS為2。初次按下的脈衝之後經過4次更新產生首次連發,隨後每2次更新產生一次。FAILED CHECKS應為0。改變按住的時間會改變脈衝計數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input_repeat.h:24
Return the requested repeat-pulse bits from the latest repeat step.
kitaqfc/lib/input_repeat.c:91
unsigned char nes_pad_repeat(unsigned char mask)
{
return (unsigned char)(nes_pad1_repeat & mask);
}nes_pad_repeat_config
設定執行時的初始等待與重複間隔,將 nes_pad1_repeat 清為 0,並將八個獨立按鈕計數器重設為 delay。不讀取控制器,也不清除按住、按下或放開遮罩。
語法
void nes_pad_repeat_config(unsigned char delay, unsigned char interval);參數
delay初始倒數值,範圍 0~255。新按下立即觸發後,再經過
delay + 1次重複更新觸發下一次。單位為nes_pad_repeat_step()的呼叫次數,只有每影格恰好呼叫一次時才等於影格數。interval後續觸發之間的倒數值,範圍 0~255。實際間隔為
interval + 1次重複更新;0 表示初始等待結束後,每次按住更新都觸發。八個按鈕獨立計數。
回傳值
無(void)。
使用條件與限制
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
使用範例
nes_pad_repeat_config(3,1); // Next pulse after 4 held updates, then every 2.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範輪詢→更新連發→查詢狀態的順序,並說明NES查詢函式回傳對應位元,而非布林值1。使用nes_pad_repeat_config(3, 1),按住B達40次更新後放開。FIRST HELD、FIRST TRIGGER、FIRST REPEAT為2,HELD TICKS為40,PULSE COUNT為19,RELEASE BITS為2。初次按下的脈衝之後經過4次更新產生首次連發,隨後每2次更新產生一次。FAILED CHECKS應為0。改變按住的時間會改變脈衝計數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input_repeat.h:16
Set initial/repeat countdowns and clear repeat output. Zero countdowns are allowed and cause a repeat on the next held-button step. A fresh press emits immediately. Held repeats follow after delay+1 and then interval+1 steps. These are call counts, not milliseconds; use one fresh pad poll before each step.
kitaqfc/lib/input_repeat.c:21
void nes_pad_repeat_config(unsigned char delay, unsigned char interval)
{
unsigned char i;
nes_pad_repeat_delay = delay;
nes_pad_repeat_interval = interval;
nes_pad1_repeat = 0;
i = 0;
while (i != 8)
{
nes_pad1_repeat_counter[i] = delay;
i = i + 1;
}
}nes_pad_repeat_step
依最近讀取的按住與按下遮罩重建 nes_pad1_repeat,將各按鈕倒數推進一次。先呼叫 nes_pad_poll(),再呼叫本函式一次。反覆使用舊的按下遮罩會反覆重設初始等待,並不斷產生新按下事件。
語法
void nes_pad_repeat_step(void);回傳值
無(void)。
使用條件與限制
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
第一次讀取前,將四個 nes_pad1_* 狀態位元組初始化為 0。之後每個輸入週期讀取一次。pressed = current & ~previous,released = previous & ~current,兩者表示最近一次讀取發生的變化。重複狀態需另行呼叫 nes_pad_repeat_step() 更新。
使用範例
nes_pad_repeat_step(); // Once after each fresh poll; getters do not advance time.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範輪詢→更新連發→查詢狀態的順序,並說明NES查詢函式回傳對應位元,而非布林值1。使用nes_pad_repeat_config(3, 1),按住B達40次更新後放開。FIRST HELD、FIRST TRIGGER、FIRST REPEAT為2,HELD TICKS為40,PULSE COUNT為19,RELEASE BITS為2。初次按下的脈衝之後經過4次更新產生首次連發,隨後每2次更新產生一次。FAILED CHECKS應為0。改變按住的時間會改變脈衝計數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input_repeat.h:20
Generate per-button repeat bits from the most recently polled pad state. Poll first, then call once per tick; a countdown reaching zero emits on the following step, so an interval N leaves N decrement steps between pulses.
kitaqfc/lib/input_repeat.c:40
void nes_pad_repeat_step(void)
{
unsigned char bit_index;
unsigned char mask;
unsigned char counter;
nes_pad1_repeat = 0;
bit_index = 0;
mask = 1;
while (mask != 0)
{
if ((nes_pad1_cur & mask) == 0)
{
nes_pad1_repeat_counter[bit_index] = nes_pad_repeat_delay;
}
else
{
if ((nes_pad1_pressed & mask) != 0)
{
nes_pad1_repeat = nes_pad1_repeat | mask;
nes_pad1_repeat_counter[bit_index] = nes_pad_repeat_delay;
}
else
{
counter = nes_pad1_repeat_counter[bit_index];
if (counter == 0)
{
nes_pad1_repeat = nes_pad1_repeat | mask;
nes_pad1_repeat_counter[bit_index] = nes_pad_repeat_interval;
}
else
{
nes_pad1_repeat_counter[bit_index] = counter - 1;
}
}
}
bit_index = bit_index + 1;
// Byte overflow terminates the scan after the eighth button; each button has its own countdown.
mask = mask + mask;
}
}nes_pad_trigger
以 mask 篩選控制器 1 最近一次的新按下遮罩,適合在選中按鈕由放開變為按下時執行一次動作。
語法
unsigned char nes_pad_trigger(unsigned char mask);參數
mask依 NES 原始位元順序指定要保留的按鈕,需要時以
|組合。0 表示不選任何按鈕。這是位元篩選遮罩,不是控制器連接埠編號。
回傳值
回傳快取遮罩中符合條件的位元,保留原本的位置。結果可能不是 1;0 表示沒有符合的按鈕。讀取不會消耗事件。
使用條件與限制
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
第一次讀取前,將四個 nes_pad1_* 狀態位元組初始化為 0。之後每個輸入週期讀取一次。pressed = current & ~previous,released = previous & ~current,兩者表示最近一次讀取發生的變化。重複狀態需另行呼叫 nes_pad_repeat_step() 更新。
使用範例
if (nes_pad_trigger(0x02)!=0) {
first_trigger=nes_pad_trigger(0x02); // Returns 2, not Boolean 1.
first_held=nes_pad_held(0x02); first_repeat=nes_pad_repeat(0x02);
if (first_trigger!=2 || first_held!=2 || first_repeat!=2) failures++;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範輪詢→更新連發→查詢狀態的順序,並說明NES查詢函式回傳對應位元,而非布林值1。使用nes_pad_repeat_config(3, 1),按住B達40次更新後放開。FIRST HELD、FIRST TRIGGER、FIRST REPEAT為2,HELD TICKS為40,PULSE COUNT為19,RELEASE BITS為2。初次按下的脈衝之後經過4次更新產生首次連發,隨後每2次更新產生一次。FAILED CHECKS應為0。改變按住的時間會改變脈衝計數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/input_repeat.h:22
Return the requested newly-pressed bits, not a normalized Boolean.
kitaqfc/lib/input_repeat.c:85
unsigned char nes_pad_trigger(unsigned char mask)
{
return (unsigned char)(nes_pad1_pressed & mask);
}metasprite.h — 由多個精靈組成的圖像
既有 metasprite.c 中的 C 函式,也有 nes_game.h 中展開為 __metasprite_draw 的巨集。兩者讀取相同的附結束標記資料流,並寫入相同的四位元組 OAM 項目。範例分別編譯這兩種形式。
C 版組合精靈函式需要 nes_oam_shadow[256]。runtime.c 將它定義在 0x0200,另為 VRAM 佇列保留 0x0300–0x03BF,並提供 __nes_nmi。每個實作檔只應引入一次,且應與程式其他部分協調中斷處理。
nes_metasprite_draw
既有 metasprite.c 中的 C 函式,也有 nes_game.h 中展開為 __metasprite_draw 的巨集。兩者讀取相同的附結束標記資料流,並寫入相同的四位元組 OAM 項目。範例分別編譯這兩種形式。
將含有終止標記的精靈部件資料串流展開至第02頁影子緩衝區的連續項目。每個部件會將位元組大小的X/Y偏移加到基準位置,並使用各自的圖塊及屬性。傳回下一個OAM編號。
語法
unsigned char nes_metasprite_draw(unsigned char oam_index, unsigned char base_x, unsigned char base_y, unsigned char* metasprite);
// Macro from nes_game.h:
#define nes_metasprite_draw(i,x,y,data) __metasprite_draw((i),(x),(y),(data))參數
oam_index / i精靈項目編號,範圍0–63,不是位元組偏移。實作使用8位元游標將其乘以4;超出範圍的值會以64為週期循環,可能覆寫其他項目。不會檢查項目是否已配置。
base_x / x以像素為單位的橫向位置,使用無號位元組表示,並非圖塊座標。
base_y / y直接寫入 OAM 的 Y 位元組。若要將頂端放在第 1 條掃描線或更下方,應傳入頂端座標減一;239..255 位於 240 行可見區域之外。
metasprite / data指向可讀四位元組記錄的指標,格式為
dx, dy, tile, attr。下一個dx位置的0xFF表示結束,其後無須其他位元組。偏移以256為週期相加:0xFE表示−2,dy的0xFF可表示−1,但dx的0xFF保留作終止標記,不能表示−1。指標必須在目前映射的記憶體中有效。
回傳值
下一個OAM項目編號,即(oam_index + 已寫入部件數) modulo 64。傳回的是游標,而不是繪製的部件數。空資料串流會傳回oam_index modulo 64。
使用條件與限制
請明確選擇標頭檔組合:nes_game.h 和整合標頭檔 fc.h 會定義巨集。要使用 C 函式,請引入 runtime.h 或 metasprite.h 並連結對應的實作檔,不要引入同名巨集,或先用 #undef 取消巨集定義。無參數 DMA 巨集不能接收 C 函式的 page 參數。
C 版組合精靈函式需要 nes_oam_shadow[256]。runtime.c 將它定義在 0x0200,另為 VRAM 佇列保留 0x0300–0x03BF,並提供 __nes_nmi。每個實作檔只應引入一次,且應與程式其他部分協調中斷處理。
這些操作會修改CPU RAM中的0x0200–0x02FF,不會立即改變硬體OAM。請準備好完整頁面後再呼叫__oam_dma。它們不會維護精靈函式庫的配置旗標、座標陣列或使用數量。應避免中斷處理常式修改或傳送尚未準備完成的頁面。
不會檢查部件數、畫面裁切或容量。必須加入終止標記,並將部件數限制在64−oam_index以內。座標以256為週期循環;寫完項目63後會回到項目0。空資料串流不會修改任何項目。此格式不同於精靈函式庫metasprite_draw使用的、另外指定數量的MetaSpritePart陣列。
使用範例
demo_next=nes_metasprite_draw(4,144,31,demo_parts); // C function: returns 6.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
C-RUNTIME 示範多個 C 函式的配合。PAIR 列在 (144,32) 和 (152,32) 顯示兩個 8×8 箭頭,第二個水平翻轉。y=64 的另一對被隱藏,因此 HIDE RANGE 應為空白。兩次繪製依序使用槽位 4–5 和 6–7,顯示 NEXT 08。將第 02 頁複製到第 04 頁後,只把槽位 8 從箭頭圖塊 128 改為方塊圖塊 129。nes_oam_dma(4) 應在 PAGE 04 旁的 (144,96) 顯示綠色方塊,而第 02 頁仍保留圖塊 128。
箭頭採用紅色邊緣、綠色箭桿和藍色箭尖細節;方塊圖塊 129 為綠色。驗證會逐張比對 8,704 個像素的顏色、傳送後的全部 256 位元組 OAM 及顯示標籤。尚未在實體硬體上驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_c_helpers.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_c_helpers.nes --no-cache --no-disasm使用範例
fc_oam_next=nes_metasprite_draw(5,136,95,fc_oam_pair); // Returns 7 after two entries.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例以有標籤的各行區分操作。SET與MOVE在(144,16)、(144,32)顯示8×8向右箭頭;TILE在(144,48)顯示綠色方塊;ATTR在(144,64)顯示水平及垂直皆翻轉的箭頭。HIDE的(144,80)與CLEAR的(144,112)必須為空。META在(136,96)、(144,96)顯示一對箭頭,第二個水平翻轉。NEXT 07表示寫完項目5與6後的下一個位置。箭頭邊緣為紅色、箭桿為綠色,尖端細節為藍色。驗證會逐圖比較8,704個像素並檢查傳送後的OAM位元組;尚未進行實機測試。
ALIASES 程式使用 nes_game.h 中的巨集準備各列,再用 nes_oam_dma() 傳送第 02 頁。TRANSFER 列應在 (144,128) 顯示一個 8×8 箭頭。此例示範不必連結 runtime.c 或 metasprite.c 的巨集形式。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/metasprite.h:12
Optional declarations for the phase 10 NES metasprite helper. Metasprite data layout: [dx, dy, tile, attr] repeated, terminated by dx=0xFF Read four-byte records [dx,dy,tile,attr] until dx=0xFF, writing them to shadow OAM. Coordinates and destination offsets wrap as bytes. The caller must supply a terminator and enough unused slots; there is no capacity guard. Return the next slot index derived from the final wrapped byte offset.
kitaqfc/lib/metasprite.c:18
unsigned char nes_metasprite_draw(unsigned char oam_index, unsigned char base_x, unsigned char base_y, unsigned char* metasprite)
{
unsigned char dst;
unsigned char dx;
dst = oam_index + oam_index;
dst = dst + dst;
while (1)
{
dx = metasprite[0];
if (dx == 0xFF)
{
break;
}
// These are raw OAM Y bytes, not a corrected screen-top coordinate; no allocation bookkeeping is updated.
nes_oam_shadow[dst] = (unsigned char)(base_y + metasprite[1]);
nes_oam_shadow[(unsigned char)(dst + 1)] = metasprite[2];
nes_oam_shadow[(unsigned char)(dst + 2)] = metasprite[3];
nes_oam_shadow[(unsigned char)(dst + 3)] = (unsigned char)(base_x + dx);
dst = (unsigned char)(dst + 4);
metasprite = metasprite + 4;
}
return (unsigned char)(dst >> 2);
}nes_metasprite_hide_from
對一段連續的 OAM 暫存項目的 Y 位元組寫入 0xF8,將它們隱藏。圖塊、屬性和 X 座標保持不變。此 C 函式不傳送 OAM,也不釋放精靈函式庫中的配置。
語法
void nes_metasprite_hide_from(unsigned char oam_index, unsigned char sprite_count);參數
oam_index精靈項目編號,範圍0–63,不是位元組偏移。實作使用8位元游標將其乘以4;超出範圍的值會以64為週期循環,可能覆寫其他項目。不會檢查項目是否已配置。
sprite_count要隱藏的項目數,範圍為 0 到
64−oam_index。0 表示不做任何修改。數量過多會讓位元組游標回繞,可能連 OAM 開頭的項目也隱藏;函式不檢查範圍。
回傳值
無(void)。
使用條件與限制
C 版組合精靈函式需要 nes_oam_shadow[256]。runtime.c 將它定義在 0x0200,另為 VRAM 佇列保留 0x0300–0x03BF,並提供 __nes_nmi。每個實作檔只應引入一次,且應與程式其他部分協調中斷處理。
這些操作會修改CPU RAM中的0x0200–0x02FF,不會立即改變硬體OAM。請準備好完整頁面後再呼叫__oam_dma。它們不會維護精靈函式庫的配置旗標、座標陣列或使用數量。應避免中斷處理常式修改或傳送尚未準備完成的頁面。
使用範例
nes_metasprite_hide_from(6,2); // Hide slots 6 and 7; the pair at slots 4 and 5 remains.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
C-RUNTIME 示範多個 C 函式的配合。PAIR 列在 (144,32) 和 (152,32) 顯示兩個 8×8 箭頭,第二個水平翻轉。y=64 的另一對被隱藏,因此 HIDE RANGE 應為空白。兩次繪製依序使用槽位 4–5 和 6–7,顯示 NEXT 08。將第 02 頁複製到第 04 頁後,只把槽位 8 從箭頭圖塊 128 改為方塊圖塊 129。nes_oam_dma(4) 應在 PAGE 04 旁的 (144,96) 顯示綠色方塊,而第 02 頁仍保留圖塊 128。
箭頭採用紅色邊緣、綠色箭桿和藍色箭尖細節;方塊圖塊 129 為綠色。驗證會逐張比對 8,704 個像素的顏色、傳送後的全部 256 位元組 OAM 及顯示標籤。尚未在實體硬體上驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_c_helpers.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_c_helpers.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/metasprite.h:17
Hide consecutive shadow slots by setting Y to 0xF8. Keep the requested range within 64 slots to avoid wrapping and hiding earlier entries.
kitaqfc/lib/metasprite.c:49
void nes_metasprite_hide_from(unsigned char oam_index, unsigned char sprite_count)
{
unsigned char dst;
dst = oam_index + oam_index;
dst = dst + dst;
while (sprite_count != 0)
{
nes_oam_shadow[dst] = 0xF8;
dst = (unsigned char)(dst + 4);
sprite_count = sprite_count - 1;
}
}nametable_asset.h — 名稱表素材與放置
上傳 32 圖塊列、帶步幅的矩形、填滿操作及完整 960+64 位元組畫面,亦可編輯和上傳屬性影子資料。請依情況選用立即傳輸或延後消費佇列。
直接傳輸時,請將 PPUCTRL 遞增量設為一,並在關閉繪圖的設定階段,或足以完成上傳的 VBlank 期間使用。這些輔助函式不會關閉繪圖或等待。
請連結 runtime.c。佇列會複製資料,供之後的 NMI 或關閉繪圖時的安全提交使用。生產與消費操作須序列化。多列操作中若容量耗盡,先前成功加入的列仍留在佇列中。
nes_attr_apply_now
立即將影子緩衝區的全部 64 位元組上傳至名稱表的屬性表。
語法
void nes_attr_apply_now(unsigned short nt_base);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
回傳值
無傳回值。
使用條件與限制
共用的 64 位元組屬性影子緩衝區佔用 CPU RAM $03E0..$041F,請保留此範圍。一個屬性位元組涵蓋 4×4 圖塊;每個兩位元欄位為一個 2×2 圖塊象限選擇調色盤。
直接傳輸時,請將 PPUCTRL 遞增量設為一,並在關閉繪圖的設定階段,或足以完成上傳的 VBlank 期間使用。這些輔助函式不會關閉繪圖或等待。
使用範例
nes_attr_apply_now(0x2000);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:20
Upload all attribute shadow bytes immediately; the caller provides safe PPU timing.
kitaqfc/lib/nametable_asset.c:90
void nes_attr_apply_now(unsigned short nt_base)
{
nes_ppu_stream_write(nes_attr_base_from_nt(nt_base), nes_attr_shadow, 64);
}nes_attr_base_from_nt
將 $3C0 加到名稱表基底位址,取得屬性表位置。
語法
unsigned short nes_attr_base_from_nt(unsigned short nt_base);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
回傳值
不驗證輸入,直接傳回 nt_base+$3C0。
使用範例
result[1]=nes_attr_base_from_nt(0x2400);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:11
Locate the 64-byte attribute table at offset 0x03C0 from a nametable base.
kitaqfc/lib/nametable_asset.c:30
unsigned short nes_attr_base_from_nt(unsigned short nt_base)
{
return (unsigned short)(nt_base + 0x03C0);
}nes_attr_queue_all
將完整屬性影子緩衝區複製到佇列。
語法
unsigned char nes_attr_queue_all(unsigned short nt_base);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
回傳值
成功排入時傳回 1,已滿時傳回 0;一筆記錄使用 67 個佇列位元組。
使用條件與限制
共用的 64 位元組屬性影子緩衝區佔用 CPU RAM $03E0..$041F,請保留此範圍。一個屬性位元組涵蓋 4×4 圖塊;每個兩位元欄位為一個 2×2 圖塊象限選擇調色盤。
請連結 runtime.c。佇列會複製資料,供之後的 NMI 或關閉繪圖時的安全提交使用。生產與消費操作須序列化。多列操作中若容量耗盡,先前成功加入的列仍留在佇列中。
使用範例
result[5]=nes_attr_queue_all(0x2000);result[6]=nes_vram_queue_used;nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:22
Copy all shadow attribute bytes into the runtime queue and return its admission result.
kitaqfc/lib/nametable_asset.c:97
unsigned char nes_attr_queue_all(unsigned short nt_base)
{
return nes_vram_queue_try_write(nes_attr_base_from_nt(nt_base), nes_attr_shadow, 64);
}nes_attr_shadow_clear
以相同的打包值填滿影子緩衝區的全部 64 個位元組。
語法
void nes_attr_shadow_clear(unsigned char value);參數
value打包的屬性位元組;例如 0x55 讓所有象限選擇調色盤 1,0xAA 則選擇 2。
回傳值
無傳回值。
使用條件與限制
共用的 64 位元組屬性影子緩衝區佔用 CPU RAM $03E0..$041F,請保留此範圍。一個屬性位元組涵蓋 4×4 圖塊;每個兩位元欄位為一個 2×2 圖塊象限選擇調色盤。
使用範例
nes_attr_shadow_clear(0x55);result[2]=nes_attr_shadow[63];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:13
Fill all 64 shadow bytes with an already-packed attribute value.
kitaqfc/lib/nametable_asset.c:36
void nes_attr_shadow_clear(unsigned char value)
{
__memset(nes_attr_shadow, value, 64);
}nes_attr_shadow_copy
將完整屬性表複製到 RAM,作為編輯的起點。
語法
void nes_attr_shadow_copy(unsigned char* src64);參數
src64可讀取的 64 位元組打包屬性表,不是逐圖塊的調色盤 ID 陣列。
回傳值
無傳回值。
使用條件與限制
共用的 64 位元組屬性影子緩衝區佔用 CPU RAM $03E0..$041F,請保留此範圍。一個屬性位元組涵蓋 4×4 圖塊;每個兩位元欄位為一個 2×2 圖塊象限選擇調色盤。
使用範例
for(i=0;i<64;i++)table[i]=0x55;nes_attr_shadow_copy(table);result[3]=nes_attr_shadow[0];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:15
Copy an entire packed attribute table into shadow RAM without writing the PPU.
kitaqfc/lib/nametable_asset.c:42
void nes_attr_shadow_copy(unsigned char* src64)
{
__memcpy(nes_attr_shadow, src64, 64);
}nes_attr_shadow_set_quad
替換一個 2×2 圖塊象限的調色盤,保留同一位元組中的其他欄位。
語法
void nes_attr_shadow_set_quad(unsigned char tile_x, unsigned char tile_y, unsigned char pal_index);參數
tile_x左側圖塊欄,可見範圍為 0..31。
tile_y頂端圖塊列,可見範圍為 0..29。
pal_index調色盤索引的最低兩個位元。
回傳值
無傳回值。
使用條件與限制
共用的 64 位元組屬性影子緩衝區佔用 CPU RAM $03E0..$041F,請保留此範圍。一個屬性位元組涵蓋 4×4 圖塊;每個兩位元欄位為一個 2×2 圖塊象限選擇調色盤。
座標須小於 32。奇數座標選取其所在的 2×2 象限。可見列為 0..29。
使用範例
nes_attr_shadow_set_quad(4,8,2);result[4]=nes_attr_shadow[17];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:18
Replace only the chosen quadrant's palette bits, preserving its neighbors. Palette IDs are masked to two bits; tile coordinates must fit the shadow table.
kitaqfc/lib/nametable_asset.c:72
void nes_attr_shadow_set_quad(unsigned char tile_x, unsigned char tile_y, unsigned char pal_index)
{
unsigned char idx;
unsigned char shift;
unsigned char mask;
unsigned char value;
idx = nes_attr_index(tile_x, tile_y);
shift = nes_attr_shift(tile_x, tile_y);
pal_index = (unsigned char)(pal_index & 3);
value = nes_attr_shadow[idx];
mask = (unsigned char)(3 << shift);
value = (unsigned char)(value & (unsigned char)(~mask));
value = (unsigned char)(value | (unsigned char)(pal_index << shift));
nes_attr_shadow[idx] = value;
}nes_nametable_apply_now
上傳 960 個圖塊 ID,接著上傳 64 位元組屬性表。
語法
void nes_nametable_apply_now(unsigned short nt_base, unsigned char* nam960, unsigned char* attr64);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
nam960逐列儲存的 32×30 圖塊陣列。
attr6464 個打包屬性位元組,不必是共用影子緩衝區。
回傳值
無傳回值。
使用條件與限制
直接傳輸時,請將 PPUCTRL 遞增量設為一,並在關閉繪圖的設定階段,或足以完成上傳的 VBlank 期間使用。這些輔助函式不會關閉繪圖或等待。
1024 位元組的同步上傳通常應在關閉繪圖的設定階段執行。此輔助函式不會將傳輸分散至多個影格。
使用範例
nes_nametable_apply_now(0x2000,empty,table);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:41
Upload 960 tile bytes followed by 64 attribute bytes. This bulk operation does not disable rendering or wait for VBlank on its own.
kitaqfc/lib/nametable_asset.c:178
void nes_nametable_apply_now(unsigned short nt_base, unsigned char* nam960, unsigned char* attr64)
{
nes_ppu_stream_write(nt_base, nam960, 960);
nes_ppu_stream_write(nes_attr_base_from_nt(nt_base), attr64, 64);
}nes_nt_base_from_index
根據索引的最低兩個位元計算邏輯名稱表基底位址。
語法
unsigned short nes_nt_base_from_index(unsigned char index);參數
index索引;0..3 選擇各表格,更大的值只保留最低兩個位元。
回傳值
傳回 $2000 + (index & 3)*$400。
使用範例
result[0]=nes_nt_base_from_index(5);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:9
Mask the index to the four logical nametables and return its PPU base. Physical storage still depends on the cartridge's mirroring configuration.
kitaqfc/lib/nametable_asset.c:22
unsigned short nes_nt_base_from_index(unsigned char index)
{
index = (unsigned char)(index & 3);
return (unsigned short)(0x2000 + ((unsigned short)index << 10));
}nes_nt_queue_fill_rect
將矩形每列以同一圖塊 ID 填滿的操作排入佇列。
語法
unsigned char nes_nt_queue_fill_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char value);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
tile_x左側圖塊欄,可見範圍為 0..31。
tile_y頂端圖塊列,可見範圍為 0..29。
width寬度,以圖塊為單位。
height高度,以圖塊為單位。
value填入的圖塊 ID,0..255。
回傳值
全部列完成或高度為零時傳回 1,排入失敗時傳回 0。
使用條件與限制
請連結 runtime.c。佇列會複製資料,供之後的 NMI 或關閉繪圖時的安全提交使用。生產與消費操作須序列化。多列操作中若容量耗盡,先前成功加入的列仍留在佇列中。
座標與範圍須位於可見名稱表內,通常 pitch≥width。不進行裁切。佇列每列長度最多 127;一般名稱表矩形最多寬 32 個圖塊。
使用範例
result[10]=nes_nt_queue_fill_rect(0x2000,16,8,4,3,1);result[11]=nes_vram_queue_used;nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:38
Queue one fill record per row, stopping on failure while retaining previously queued rows. The runtime fill-length and rectangle bounds requirements apply.
kitaqfc/lib/nametable_asset.c:157
unsigned char nes_nt_queue_fill_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char value)
{
unsigned char row;
unsigned short ppu_addr;
row = 0;
while (row != height)
{
ppu_addr = (unsigned short)(nt_base + ((unsigned short)(tile_y + row) << 5) + tile_x);
if (nes_vram_queue_try_fill(ppu_addr, value, width) == 0)
{
return 0;
}
row = (unsigned char)(row + 1);
}
return 1;
}nes_nt_queue_rect
將矩形各列的來源資料複製到佇列。
語法
unsigned char nes_nt_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
tile_x左側圖塊欄,可見範圍為 0..31。
tile_y頂端圖塊列,可見範圍為 0..29。
width寬度,以圖塊為單位。
height高度,以圖塊為單位。
pitch來源各列起點之間的位元組步幅,可略過列尾填補資料。
src至少涵蓋 (height−1)*pitch+width 位元組的可讀取來源。
回傳值
全部列完成或高度為零時傳回 1,排入失敗時傳回 0。
使用條件與限制
請連結 runtime.c。佇列會複製資料,供之後的 NMI 或關閉繪圖時的安全提交使用。生產與消費操作須序列化。多列操作中若容量耗盡,先前成功加入的列仍留在佇列中。
座標與範圍須位於可見名稱表內,通常 pitch≥width。不進行裁切。佇列每列長度最多 127;一般名稱表矩形最多寬 32 個圖塊。
使用範例
result[8]=nes_nt_queue_rect(0x2000,10,8,2,3,4,patch);result[9]=nes_vram_queue_used;nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:35
Copy rows into the runtime queue until complete or full. Failure leaves earlier rows queued; it does not roll back a partially admitted rectangle. Widths must respect the queue literal-record limit. Pitch is source bytes per row. Each copied literal record costs width+3 queue bytes; check total admission needs when partial updates are unacceptable.
kitaqfc/lib/nametable_asset.c:137
unsigned char nes_nt_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src)
{
unsigned char row;
unsigned short ppu_addr;
row = 0;
while (row != height)
{
ppu_addr = (unsigned short)(nt_base + ((unsigned short)(tile_y + row) << 5) + tile_x);
if (nes_vram_queue_try_write(ppu_addr, src, width) == 0)
{
return 0;
}
src = src + pitch;
row = (unsigned char)(row + 1);
}
return 1;
}nes_nt_queue_row
將完整的一列 32 個圖塊複製到佇列。
語法
unsigned char nes_nt_queue_row(unsigned short nt_base, unsigned char row, unsigned char* src32);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
row列 0..29;不檢查邊界。
src3232 個可讀取的圖塊 ID。
回傳值
成功排入時傳回 1,已滿時傳回 0;使用 35 個佇列位元組。
使用條件與限制
請連結 runtime.c。佇列會複製資料,供之後的 NMI 或關閉繪圖時的安全提交使用。生產與消費操作須序列化。多列操作中若容量耗盡,先前成功加入的列仍留在佇列中。
使用範例
result[7]=nes_nt_queue_row(0x2000,4,row);nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:26
Copy one complete nametable row into the runtime queue.
kitaqfc/lib/nametable_asset.c:111
unsigned char nes_nt_queue_row(unsigned short nt_base, unsigned char row, unsigned char* src32)
{
unsigned short ppu_addr;
ppu_addr = (unsigned short)(nt_base + ((unsigned short)row << 5));
return nes_vram_queue_try_write(ppu_addr, src32, 32);
}nes_nt_stream_rect
依來源步幅讀取矩形的每一列,直接上傳至 PPU。
語法
void nes_nt_stream_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
tile_x左側圖塊欄,可見範圍為 0..31。
tile_y頂端圖塊列,可見範圍為 0..29。
width寬度,以圖塊為單位。
height高度,以圖塊為單位。
pitch來源各列起點之間的位元組步幅,可略過列尾填補資料。
src至少涵蓋 (height−1)*pitch+width 位元組的可讀取來源。
回傳值
無傳回值。
使用條件與限制
直接傳輸時,請將 PPUCTRL 遞增量設為一,並在關閉繪圖的設定階段,或足以完成上傳的 VBlank 期間使用。這些輔助函式不會關閉繪圖或等待。
座標與範圍須位於可見名稱表內,通常 pitch≥width。不進行裁切。佇列每列長度最多 127;一般名稱表矩形最多寬 32 個圖塊。
使用範例
// A pitch of four skips two source bytes at the end of each row.
nes_nt_stream_rect(0x2000,4,8,2,2,4,patch);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:29
Write each rectangle row immediately, advancing source by pitch rather than width. Caller-provided coordinates, storage and timing are not clipped or checked.
kitaqfc/lib/nametable_asset.c:120
void nes_nt_stream_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src)
{
unsigned char row;
unsigned short ppu_addr;
row = 0;
while (row != height)
{
ppu_addr = (unsigned short)(nt_base + ((unsigned short)(tile_y + row) << 5) + tile_x);
nes_ppu_stream_write(ppu_addr, src, width);
src = src + pitch;
row = (unsigned char)(row + 1);
}
}nes_nt_stream_row
將完整的一列 32 個圖塊直接複製至 PPU。
語法
void nes_nt_stream_row(unsigned short nt_base, unsigned char row, unsigned char* src32);參數
nt_base邏輯名稱表基底位址 $2000/$2400/$2800/$2C00;實體上是否獨立取決於鏡像設定。
row列 0..29;不檢查邊界。
src3232 個可讀取的圖塊 ID。
回傳值
無傳回值。
使用條件與限制
直接傳輸時,請將 PPUCTRL 遞增量設為一,並在關閉繪圖的設定階段,或足以完成上傳的 VBlank 期間使用。這些輔助函式不會關閉繪圖或等待。
使用範例
nes_nt_stream_row(0x2000,2,row);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
組合列、帶步幅矩形、填滿及整表上傳。兩條紅色 32×8 橫條下方有藍色 16×16 正方形,以及紅色 16×24/32×24 矩形。直接傳輸與佇列傳輸會繪製在不同位置。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/nametable_asset.h:24
Write one complete 32-tile row directly. The caller validates the row and PPU timing.
kitaqfc/lib/nametable_asset.c:103
void nes_nt_stream_row(unsigned short nt_base, unsigned char row, unsigned char* src32)
{
unsigned short ppu_addr;
ppu_addr = (unsigned short)(nt_base + ((unsigned short)row << 5));
nes_ppu_stream_write(ppu_addr, src32, 32);
}nes_game.h — 遊戲操作巨集
nes_game.h 為 VRAM 佇列、OAM 與組合精靈、控制器讀取、映射器中斷、分割捲動和 FDS 操作提供易讀的巨集名稱。每個巨集都會展開為編譯器內建函式,因此診斷資訊和 KUROSAKI 中繼資料仍能記錄底層硬體操作。佇列巨集使用內建佇列,OAM DMA 巨集不接收參數。
請明確選擇標頭檔組合:nes_game.h 和整合標頭檔 fc.h 會定義巨集。要使用 C 函式,請引入 runtime.h 或 metasprite.h 並連結對應的實作檔,不要引入同名巨集,或先用 #undef 取消巨集定義。無參數 DMA 巨集不能接收 C 函式的 page 參數。
nes_fds_farcall
nes_game.h 中的 FDS 跨庫呼叫便利巨集,展開為 __fds_overlay_farcall((bank), (func))。
語法
#define nes_fds_farcall(bank, func) __fds_overlay_farcall((bank), (func))參數
bank表示記憶體庫的運算式。呼叫前會求值一次,但實際載入的記憶體庫由 func 連結後的位置決定。這不是將位址派送到執行期任意選定記憶體庫的功能。請傳入相符的值,例如
__bankof(func)。func已宣告且不帶參數的函式名稱。範例傳入
u8 overlay_answer(void)。不接受數值位址、執行期函式指標或需要引數的函式。需要引數時,請使用一般的target(a, b)呼叫。
回傳值
目標函式的八位元結果。若載入失敗但可還原前一個記憶體庫,就不呼叫目標,改傳回載入錯誤位元組。請設計能區分錯誤與正常結果的傳回值慣例。
使用條件與限制
請搭配 --mapper=fds --fds-layout=fds32 使用。記憶體庫 0 是位於 $A000–$DFFF 的共用程式碼。啟動時記憶體庫 1 佔用 $6000–$9FFF;記憶體庫 2 以上則是載入同一個 16 KiB 視窗的覆疊。請用 #pragma fixed_bank 2 等指示詞配置覆疊程式碼或資料。
記憶體庫 1 會從載入位址為 $6000、大小為 16,384 位元組的獨立開機 PRG 檔還原。沒有清單時,預設檔案 ID 為:記憶體庫 1 使用 0、共用程式碼使用 1、CHR 使用 2。自訂清單須將開機 PRG 分成位於 $6000 與 $A000 的兩個 16,384 位元組檔案。記憶體庫 2 以上的檔案 ID 為 --fds-overlay-start-id(預設 32)+ 記憶體庫編號 − 2。
呼叫不同記憶體庫時,會保存先前的記憶體庫並在返回前還原。巢狀呼叫也遵循相同規則。傳輸進行一部分後失敗時,仍會嘗試還原。若還原本身失敗,執行會停在共用程式碼中,不會返回已被覆寫的程式碼。目標位於共用記憶體庫或同一記憶體庫時,會避免不必要的傳輸。
BIOS 呼叫是同步的;載入期間此 API 不會維持遊戲主迴圈每影格持續前進。請從共用記憶體庫中的一般控制程式呼叫,不可從中斷處理常式呼叫。顯示/音訊連續性與真正 BIOS 的共同運作,須另行驗證。
這些擷取使用自行撰寫的 LoadFiles 呼叫慣例測試程式,檢查編譯後 CPU 程式碼、記憶體傳輸及每個顯示像素。不驗證真正的 BIOS、磁碟傳輸時序、CRC 或實機開機。KUROSAKI 的 FDS 控制器模型為部分實作;未使用此測試程式的一般執行無法證明相同的傳輸結果。
下方第一個編譯器命令會建置可下載的範例。Python 檢查工具會將五個教學範例分別以啟用及停用最佳化建置,再於 KUROSAKI 檢查。它會從 scripts/fds_abi_fixture.py 建立暫時測試程式並於完成後移除,因此這些檢查不需要外部 BIOS。此測試程式不是一般遊戲用 BIOS。
使用範例
#pragma fixed_bank 0
#include "fc_fds_scene.h"
u8 choose_overlay(void){fds_result[2]++;return 2;}
#pragma fixed_bank 2
u8 overlay_answer(void){fds_result[1]++;fds_result[3]=__fds_current_bank();return 42;}
#pragma fixed_bank 0
void main(void) {
__irq_disable();fds_result[1]=0;fds_result[2]=0;
fds_result[0]=nes_fds_farcall(choose_overlay(),overlay_answer);
fds_result[4]=__fds_current_bank();fds_result[15]=165;
fds_call_screen();while(1){m_wait();}
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用自行撰寫的 LoadFiles ABI 測試程式時,RETURN VALUE 為 042;CALLBACK COUNT 與 BANK EXPR COUNT 皆為 001;BANK IN CALLBACK 為 002;BANK AFTER RETURN 為 001。函式與記憶體庫運算式各執行一次,呼叫記憶體庫 2 後還原了記憶體庫 1。這不是實際磁碟傳輸測試的擷取畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\fds_call_alias.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fds_call_alias.fds --mapper=fds --fds-layout=fds32 --fds-no-license-bypass --fds-overlay-trim --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm
python .\kitaq-docs\tools\check_fds_load_examples.py實作與原始碼
kitaqfc/lib/nes_game.h:41
nes_fds_load_bank
nes_game.h 中的 __fds_load_bank() 巨集寫法,可透過遊戲便利標頭明確載入邏輯記憶體庫。
語法
#define nes_fds_load_bank(bank) __fds_load_bank((bank))參數
bank要載入的邏輯記憶體庫編號,範圍為 1~254。記憶體庫 0 是共用程式碼,不是可載入視窗;255 保留用來表示駐留狀態未知。記憶體庫 2 以上計算出的檔案 ID 也須落在 0~254。
回傳值
成功時為零。記憶體庫為 0 或 255、檔案 ID 溢位,或記憶體庫 1 沒有還原檔案時,傳回 255。BIOS 傳輸失敗時傳回其錯誤位元組。傳輸前的引數錯誤會保留駐留紀錄;BIOS 傳輸失敗則將其標記為 255(未知)。
使用條件與限制
請搭配 --mapper=fds --fds-layout=fds32 使用。記憶體庫 0 是位於 $A000–$DFFF 的共用程式碼。啟動時記憶體庫 1 佔用 $6000–$9FFF;記憶體庫 2 以上則是載入同一個 16 KiB 視窗的覆疊。請用 #pragma fixed_bank 2 等指示詞配置覆疊程式碼或資料。
展開為 __fds_load_bank((bank)),不會重複求值 bank。引數限制、駐留檢查及錯誤行為皆與內建函式相同。
記憶體庫 1 會從載入位址為 $6000、大小為 16,384 位元組的獨立開機 PRG 檔還原。沒有清單時,預設檔案 ID 為:記憶體庫 1 使用 0、共用程式碼使用 1、CHR 使用 2。自訂清單須將開機 PRG 分成位於 $6000 與 $A000 的兩個 16,384 位元組檔案。記憶體庫 2 以上的檔案 ID 為 --fds-overlay-start-id(預設 32)+ 記憶體庫編號 − 2。
預設的駐留檢查發現已記錄相同記憶體庫時,會不讀取磁碟而直接傳回零。--fds-no-overlay-guard 可停用 __fds_load_bank() 的此項略過機制。成功載入後會記錄要求的記憶體庫;該紀錄不代表已驗證記憶體內容。
若從 $6000–$9FFF 視窗內的程式碼直接載入另一個記憶體庫,可能覆寫正在執行的函式或返回位址。此範例以 #pragma fixed_bank 0 放置呼叫端與顯示程式碼。若要呼叫另一個記憶體庫中的函式並返回,請使用 __fds_overlay_farcall() 或一般具型別的函式呼叫。
BIOS 呼叫是同步的;載入期間此 API 不會維持遊戲主迴圈每影格持續前進。請從共用記憶體庫中的一般控制程式呼叫,不可從中斷處理常式呼叫。顯示/音訊連續性與真正 BIOS 的共同運作,須另行驗證。
這些擷取使用自行撰寫的 LoadFiles 呼叫慣例測試程式,檢查編譯後 CPU 程式碼、記憶體傳輸及每個顯示像素。不驗證真正的 BIOS、磁碟傳輸時序、CRC 或實機開機。KUROSAKI 的 FDS 控制器模型為部分實作;未使用此測試程式的一般執行無法證明相同的傳輸結果。
下方第一個編譯器命令會建置可下載的範例。Python 檢查工具會將五個教學範例分別以啟用及停用最佳化建置,再於 KUROSAKI 檢查。它會從 scripts/fds_abi_fixture.py 建立暫時測試程式並於完成後移除,因此這些檢查不需要外部 BIOS。此測試程式不是一般遊戲用 BIOS。
使用範例
#pragma fixed_bank 0
#include "fc_fds_scene.h"
#pragma fixed_bank 2
__prg_rom u8 bank_payload[4]={11,22,33,44};
#pragma fixed_bank 0
void main(void) {
__irq_disable();
fds_result[0]=__fds_load_bank(2);
fds_result[1]=__fds_current_bank();
fds_result[2]=__fds_require_bank(2);
fds_result[3]=bank_payload[0];fds_result[4]=bank_payload[3];
fds_result[5]=nes_fds_load_bank(1);
fds_result[6]=__fds_current_bank();
fds_result[7]=__fds_require_bank(1);
fds_result[8]=__fds_load_bank(0);
fds_result[9]=__fds_load_bank(255);
fds_result[15]=165;
m_init();m_text(2,2,"FDS DATA WINDOW");m_wait();
m_text(2,5,"LOAD BANK 2 STATUS");fds_number(25,5,fds_result[0]);m_wait();
m_text(2,7,"FIRST / LAST BYTE");fds_number(21,7,fds_result[3]);fds_number(25,7,fds_result[4]);m_wait();
m_text(2,9,"REQUIRE SAME BANK");fds_number(25,9,fds_result[2]);m_wait();
m_text(2,11,"RESTORE BANK 1");fds_number(25,11,fds_result[5]);m_wait();
m_text(2,13,"RESIDENT BANK");fds_number(25,13,fds_result[6]);m_wait();
m_text(2,16,"INVALID BANKS 0 / 255");m_wait();
fds_number(2,18,fds_result[8]);fds_number(8,18,fds_result[9]);m_wait();
while(1){m_wait();}
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用自行撰寫的 LoadFiles ABI 測試程式時,LOAD BANK 2 STATUS、REQUIRE SAME BANK 與 RESTORE BANK 1 均為 000。FIRST / LAST BYTE 顯示傳輸的四位元組資料中的 011 與 044;還原後 RESIDENT BANK 為 001。無效記憶體庫 0 與 255 各傳回 255。要求相同記憶體庫不會額外載入;確認到的檔案請求依序為 32、0。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\fds_bank_load.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fds_bank_load.fds --mapper=fds --fds-layout=fds32 --fds-no-license-bypass --fds-overlay-trim --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm
python .\kitaq-docs\tools\check_fds_load_examples.py實作與原始碼
kitaqfc/lib/nes_game.h:40
nes_fds_wave_load
將陣列轉交 __fds_wave_load,以載入 64 位元組波形的巨集。
語法
#define nes_fds_wave_load(wave64) __fds_wave_load((wave64))參數
wave6464 個 FDS 波形位元組,各為 0..63 的 6 位元振幅。不檢查 NULL。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
以 --mapper=fds 建置 .fds 映像。此範例不進行磁碟 I/O,只操作聲音。錄音使用 KUROSAKI 的 RAM 直接啟動與音訊模型。測試使用的空韌體未實作 BIOS 常式,也不隨附散布。一般磁碟啟動與實機需要適當的啟動環境。
使用範例
// Mapper 20 sound lesson: original 64-step triangle and two sustained pitches.
#include "fc_sound_example.h"
#include "fds_sound.h"
#include "nes_game.h"
__location(0x4087) u8 mod_control;
__location(0x4085) u8 mod_counter;
u8 triangle[64]; u8 modulation[32];
void main(void) {
u8 i;
sound_begin("FDS WAVE AND VOLUME");
for(i=0;i<32;i++) { triangle[i]=(u8)(i*2); triangle[63-i]=(u8)(i*2); modulation[i]=0; }
__fds_sound_enable();
// Halt/reset modulation before writing the 32 values (each writes two slots).
mod_control=0x80; mod_counter=0;
__fds_mod_load(modulation);
__fds_wave_load(triangle);
sound_result[0]=*((u8*)0x4040); sound_result[1]=*((u8*)0x405F);
__fds_freq_set(1031);
__fds_volume_set(24);
sound_wait(60);
__fds_volume_set(0); sound_wait(30);
// This macro forwards the same 64-byte load. Use raw envelope registers.
nes_fds_wave_load(triangle);
__fds_env_set(0x98,0x80,0);
__fds_freq_set(1545);
sound_wait(60);
__fds_volume_set(0); sound_wait(30);
sound_end();
}預期結果
原創 64 階三角波先以約 440 Hz 播放,暫停後以約 660 Hz 播放,再停止。第二個音使用 nes_fds_wave_load 與原始包絡設定。這驗證音訊模型與直接啟動,不是 BIOS 驅動的磁碟開機。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_fds.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-fds.fds --mapper=fds --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:39
#define nes_fds_wave_load(wave64) __fds_wave_load((wave64))nes_mapper_irq_ack
nes_game.h 中供處理常式使用的確認巨集。展開為 __mapper_irq_ack(),同時清除並停用請求。
語法
#define nes_mapper_irq_ack() __mapper_irq_ack()回傳值
無傳回值。
使用條件與限制
內建函式宣告位於 intrinsics.h。使用 nes_mapper_irq_* 巨集時請包含 nes_game.h,並在建置時以 --mapper 選擇電路板。
僅限 MMC3。須提供 __nes_irq 處理常式、符合條件的 PPU A12 轉換,並啟用映射器 IRQ 與 CPU __irq_enable()。範例以背景圖樣 $0000、精靈圖樣 $1000 啟用繪製。本教學未驗證實機上對精確掃描線的同步。
MMC3 的確認與停用操作都寫入 $E000,會清除目前請求並停用後續請求。若要準備下一次中斷,請在適當時機再次呼叫 __mapper_irq_enable()。兩者都不變更 CPU 中斷遮罩或 NMI 啟用狀態。
編譯器會為自訂中斷處理常式產生 RTI,但常式須保存自己修改的 A/X/Y 暫存器及共用暫存區。範例保存 A/X/Y,僅使用位元組遞增與不帶引數的確認操作。若加入 C 呼叫,也須檢查它們使用的共用儲存空間。
使用範例
void __nes_irq(void) {
__asm {
PHA
TXA
PHA
TYA
PHA
}
irq_count++;
if (irq_phase == 1) { nes_mapper_irq_ack(); }
else { __mapper_irq_ack(); }
__asm {
PLA
TAY
PLA
TAX
PLA
}
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
MMC3 範例顯示 CHR 標記 19/20、21/22、23/24。CIRAM 讀取在垂直鏡射時為 A B A B,水平鏡射時為 A A B B。IRQ 次數為 01→02→03→03:前三次明確啟用各允許一次中斷,停用後次數不變。每階段等待六個影格。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\mapper_controls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\mapper_controls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\mapper_banks.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:36
nes_mapper_irq_disable
透過 nes_game.h 停用 MMC3 IRQ 並清除待處理請求。展開為 __mapper_irq_disable()。
語法
#define nes_mapper_irq_disable() __mapper_irq_disable()回傳值
無傳回值。
使用條件與限制
內建函式宣告位於 intrinsics.h。使用 nes_mapper_irq_* 巨集時請包含 nes_game.h,並在建置時以 --mapper 選擇電路板。
僅限 MMC3。須提供 __nes_irq 處理常式、符合條件的 PPU A12 轉換,並啟用映射器 IRQ 與 CPU __irq_enable()。範例以背景圖樣 $0000、精靈圖樣 $1000 啟用繪製。本教學未驗證實機上對精確掃描線的同步。
MMC3 的確認與停用操作都寫入 $E000,會清除目前請求並停用後續請求。若要準備下一次中斷,請在適當時機再次呼叫 __mapper_irq_enable()。兩者都不變更 CPU 中斷遮罩或 NMI 啟用狀態。
編譯器會為自訂中斷處理常式產生 RTI,但常式須保存自己修改的 A/X/Y 暫存器及共用暫存區。範例保存 A/X/Y,僅使用位元組遞增與不帶引數的確認操作。若加入 C 呼叫,也須檢查它們使用的共用儲存空間。
使用範例
nes_mapper_irq_disable();
for (i=0;i<6;i++) { m_wait(); }
mapper_result[18]=irq_count;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
MMC3 範例顯示 CHR 標記 19/20、21/22、23/24。CIRAM 讀取在垂直鏡射時為 A B A B,水平鏡射時為 A A B B。IRQ 次數為 01→02→03→03:前三次明確啟用各允許一次中斷,停用後次數不變。每階段等待六個影格。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\mapper_controls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\mapper_controls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\mapper_banks.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:35
nes_mapper_irq_enable
透過 nes_game.h 啟用 MMC3 IRQ。展開為 __mapper_irq_enable(),不變更 CPU 中斷遮罩。
語法
#define nes_mapper_irq_enable() __mapper_irq_enable()回傳值
無傳回值。
使用條件與限制
內建函式宣告位於 intrinsics.h。使用 nes_mapper_irq_* 巨集時請包含 nes_game.h,並在建置時以 --mapper 選擇電路板。
僅限 MMC3。須提供 __nes_irq 處理常式、符合條件的 PPU A12 轉換,並啟用映射器 IRQ 與 CPU __irq_enable()。範例以背景圖樣 $0000、精靈圖樣 $1000 啟用繪製。本教學未驗證實機上對精確掃描線的同步。
MMC3 的確認與停用操作都寫入 $E000,會清除目前請求並停用後續請求。若要準備下一次中斷,請在適當時機再次呼叫 __mapper_irq_enable()。兩者都不變更 CPU 中斷遮罩或 NMI 啟用狀態。
編譯器會為自訂中斷處理常式產生 RTI,但常式須保存自己修改的 A/X/Y 暫存器及共用暫存區。範例保存 A/X/Y,僅使用位元組遞增與不帶引數的確認操作。若加入 C 呼叫,也須檢查它們使用的共用儲存空間。
使用範例
nes_mapper_irq_set(15); nes_mapper_irq_enable();
for (i=0;i<6;i++) { m_wait(); }
mapper_result[16]=irq_count;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
MMC3 範例顯示 CHR 標記 19/20、21/22、23/24。CIRAM 讀取在垂直鏡射時為 A B A B,水平鏡射時為 A A B B。IRQ 次數為 01→02→03→03:前三次明確啟用各允許一次中斷,停用後次數不變。每階段等待六個影格。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\mapper_controls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\mapper_controls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\mapper_banks.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:34
nes_mapper_irq_set
nes_game.h 的 MMC3 鎖存設定巨集。將引數傳給 __mapper_irq_set 一次,並要求重新載入。
語法
#define nes_mapper_irq_set(scanline) __mapper_irq_set((scanline))參數
scanline八位元計數器鎖存值,範圍為 0~255,不是絕對螢幕 Y 座標。重新載入時機與符合條件的 PPU A12 轉換決定觸發時刻。零是有效值,不代表「停用中斷」。
回傳值
無傳回值。
使用條件與限制
內建函式宣告位於 intrinsics.h。使用 nes_mapper_irq_* 巨集時請包含 nes_game.h,並在建置時以 --mapper 選擇電路板。
僅限 MMC3。須提供 __nes_irq 處理常式、符合條件的 PPU A12 轉換,並啟用映射器 IRQ 與 CPU __irq_enable()。範例以背景圖樣 $0000、精靈圖樣 $1000 啟用繪製。本教學未驗證實機上對精確掃描線的同步。
MMC3 的確認與停用操作都寫入 $E000,會清除目前請求並停用後續請求。若要準備下一次中斷,請在適當時機再次呼叫 __mapper_irq_enable()。兩者都不變更 CPU 中斷遮罩或 NMI 啟用狀態。
編譯器會為自訂中斷處理常式產生 RTI,但常式須保存自己修改的 A/X/Y 暫存器及共用暫存區。範例保存 A/X/Y,僅使用位元組遞增與不帶引數的確認操作。若加入 C 呼叫,也須檢查它們使用的共用儲存空間。
使用範例
nes_mapper_irq_set(15); nes_mapper_irq_enable();
for (i=0;i<6;i++) { m_wait(); }
mapper_result[16]=irq_count;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
MMC3 範例顯示 CHR 標記 19/20、21/22、23/24。CIRAM 讀取在垂直鏡射時為 A B A B,水平鏡射時為 A A B B。IRQ 次數為 01→02→03→03:前三次明確啟用各允許一次中斷,停用後次數不變。每階段等待六個影格。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\mapper_controls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\mapper_controls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\mapper_banks.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:33
nes_oam_clear
這是 nes_game.h 中的巨集,會展開為語法欄所示的內建函式。引入此標頭檔即可使用,不必為此操作加入 C 實作檔。
將第02頁影子緩衝區中全部64個精靈的Y設為0xF0,使其隱藏。圖塊編號、屬性及X座標保持不變。
語法
#define nes_oam_clear() __oam_clear()回傳值
無(void)。
使用條件與限制
這些操作會修改CPU RAM中的0x0200–0x02FF,不會立即改變硬體OAM。請準備好完整頁面後再呼叫__oam_dma。它們不會維護精靈函式庫的配置旗標、座標陣列或使用數量。應避免中斷處理常式修改或傳送尚未準備完成的頁面。
使用範例
nes_sprite_set(63,144,111,128,0); // Seed the CLEAR row with a visible entry.
nes_oam_clear(); // Set every Y byte to 240; tile, attributes and X are retained.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例以有標籤的各行區分操作。SET與MOVE在(144,16)、(144,32)顯示8×8向右箭頭;TILE在(144,48)顯示綠色方塊;ATTR在(144,64)顯示水平及垂直皆翻轉的箭頭。HIDE的(144,80)與CLEAR的(144,112)必須為空。META在(136,96)、(144,96)顯示一對箭頭,第二個水平翻轉。NEXT 07表示寫完項目5與6後的下一個位置。箭頭邊緣為紅色、箭桿為綠色,尖端細節為藍色。驗證會逐圖比較8,704個像素並檢查傳送後的OAM位元組;尚未進行實機測試。
ALIASES 程式使用 nes_game.h 中的巨集準備各列,再用 nes_oam_dma() 傳送第 02 頁。TRANSFER 列應在 (144,128) 顯示一個 8×8 箭頭。此例示範不必連結 runtime.c 或 metasprite.c 的巨集形式。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:21
#define nes_oam_clear() __oam_clear()nes_oam_dma
此名稱有兩種形式。無參數巨集 nes_oam_dma() 透過 __oam_dma() 傳送第 02 頁;C 函式 nes_oam_dma(page) 則傳送指定的 256 位元組 CPU 記憶體頁。兩者都會將 OAMADDR 歸零並傳送整頁,且不修改來源資料。
語法
#define nes_oam_dma() __oam_dma()
// C function declared in runtime.h:
void nes_oam_dma(unsigned char page);參數
page (C)來源CPU位址的高位元組:傳送
0x0400–0x04FF時應傳入4,而不是0x0400。請提供完整的256位元組可讀頁面,並保持所需記憶體庫已映射。避免使用含I/O暫存器的頁面,因為讀取可能產生副作用。函式不會檢查來源位址。
回傳值
無(void)。
使用條件與限制
請明確選擇標頭檔組合:nes_game.h 和整合標頭檔 fc.h 會定義巨集。要使用 C 函式,請引入 runtime.h 或 metasprite.h 並連結對應的實作檔,不要引入同名巨集,或先用 #undef 取消巨集定義。無參數 DMA 巨集不能接收 C 函式的 page 參數。
C 版組合精靈函式需要 nes_oam_shadow[256]。runtime.c 將它定義在 0x0200,另為 VRAM 佇列保留 0x0300–0x03BF,並提供 __nes_nmi。每個實作檔只應引入一次,且應與程式其他部分協調中斷處理。
請在 VBlank 期間或關閉繪製後呼叫 DMA。兩種形式都不會等待 VBlank。應先備妥整個來源頁面再傳送,避免中斷在準備途中修改該頁面。
使用範例
m_wait();nes_oam_dma(); // Expand to the page-02 compiler intrinsic.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例以有標籤的各行區分操作。SET與MOVE在(144,16)、(144,32)顯示8×8向右箭頭;TILE在(144,48)顯示綠色方塊;ATTR在(144,64)顯示水平及垂直皆翻轉的箭頭。HIDE的(144,80)與CLEAR的(144,112)必須為空。META在(136,96)、(144,96)顯示一對箭頭,第二個水平翻轉。NEXT 07表示寫完項目5與6後的下一個位置。箭頭邊緣為紅色、箭桿為綠色,尖端細節為藍色。驗證會逐圖比較8,704個像素並檢查傳送後的OAM位元組;尚未進行實機測試。
ALIASES 程式使用 nes_game.h 中的巨集準備各列,再用 nes_oam_dma() 傳送第 02 頁。TRANSFER 列應在 (144,128) 顯示一個 8×8 箭頭。此例示範不必連結 runtime.c 或 metasprite.c 的巨集形式。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasm使用範例
m_wait();nes_oam_dma(4); // C function: source address high byte, 0x0400 -> 4.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
C-RUNTIME 示範多個 C 函式的配合。PAIR 列在 (144,32) 和 (152,32) 顯示兩個 8×8 箭頭,第二個水平翻轉。y=64 的另一對被隱藏,因此 HIDE RANGE 應為空白。兩次繪製依序使用槽位 4–5 和 6–7,顯示 NEXT 08。將第 02 頁複製到第 04 頁後,只把槽位 8 從箭頭圖塊 128 改為方塊圖塊 129。nes_oam_dma(4) 應在 PAGE 04 旁的 (144,96) 顯示綠色方塊,而第 02 頁仍保留圖塊 128。
箭頭採用紅色邊緣、綠色箭桿和藍色箭尖細節;方塊圖塊 129 為綠色。驗證會逐張比對 8,704 個像素的顏色、傳送後的全部 256 位元組 OAM 及顯示標籤。尚未在實體硬體上驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_c_helpers.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_c_helpers.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:23
kitaqfc/lib/runtime.c:245
void nes_oam_dma(unsigned char page)
{
OAMADDR = 0;
OAMDMA = page;
}nes_pad1
展開為 __pad_read1_safe() 的函式型巨集。讀取控制器 1 並回傳 NES 原始遮罩,不是查詢快取狀態的 input_current() 的別名。
語法
#define nes_pad1() __pad_read1_safe()回傳值
NES 原始位元順序的 8 位元按住遮罩。每個設為 1 的位元代表一個按下按鈕,0 表示沒有按鈕。不是正規化的布林值。
使用條件與限制
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
此呼叫重新讀取硬體狀態,不更新 input_* 或 nes_pad1_* 的快取,也不產生按下、放開或重複事件。需要偵測變化時,請保存讀取結果,與自行保存的前次遮罩比較。
safe 版本成對讀取全部按鈕,直到兩次遮罩相同。每次讀取都會對 $4016 發出選通信號,將兩個控制器的序列讀取位置重設為開頭。重試次數沒有上限。此一致性檢查不代表已驗證所有 DMC 與周邊裝置組合。
使用範例
alias1=nes_pad1(); // Macro for __pad_read1_safe(), using NES raw bits.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式比較兩個控制器埠、一般讀取與一致性檢查讀取、遮罩篩選及簡寫巨集。在控制器1上同時按A與右,在控制器2上同時按B與左。RAW P1、SAFE P1、ALIAS P1為129;P2的三個數值為66。BUTTONS P1為1,DIRS P1為128:篩選方向位元時保留其高位位置。FAILED CHECKS應為0。擷取到的數值會保留在畫面上。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\input_raw.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_raw.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/nes_game.h:30
nes_pad2
展開為 __pad_read2_safe() 的函式型巨集。讀取控制器 2 並回傳 NES 原始遮罩,不是查詢快取狀態的 input_current() 的別名。
語法
#define nes_pad2() __pad_read2_safe()回傳值
NES 原始位元順序的 8 位元按住遮罩。每個設為 1 的位元代表一個按下按鈕,0 表示沒有按鈕。不是正規化的布林值。
使用條件與限制
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
此呼叫重新讀取硬體狀態,不更新 input_* 或 nes_pad1_* 的快取,也不產生按下、放開或重複事件。需要偵測變化時,請保存讀取結果,與自行保存的前次遮罩比較。
safe 版本成對讀取全部按鈕,直到兩次遮罩相同。每次讀取都會對 $4016 發出選通信號,將兩個控制器的序列讀取位置重設為開頭。重試次數沒有上限。此一致性檢查不代表已驗證所有 DMC 與周邊裝置組合。
使用範例
alias2=nes_pad2(); // Macro for __pad_read2_safe(), using NES raw bits.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式比較兩個控制器埠、一般讀取與一致性檢查讀取、遮罩篩選及簡寫巨集。在控制器1上同時按A與右,在控制器2上同時按B與左。RAW P1、SAFE P1、ALIAS P1為129;P2的三個數值為66。BUTTONS P1為1,DIRS P1為128:篩選方向位元時保留其高位位置。FAILED CHECKS應為0。擷取到的數值會保留在畫面上。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\input_raw.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_raw.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/nes_game.h:31
nes_split_scroll_sprite0
nes_game.h 的畫面分割巨集。將 X 與 Y 各傳給 __split_scroll_sprite0 一次,執行相同等待與捲動寫入。
語法
#define nes_split_scroll_sprite0(x,y) __split_scroll_sprite0((x),(y))參數
x水平捲動值 0..255,不是物件螢幕 X 座標。範例使用 32,將同一背景的下半部左移 32 像素。
y暫時垂直捲動設定 0..255,通常可見範圍為 0..239。此函式寫入 $2005,不會在繪製中立即改變目前垂直位置。水平分割範例傳入零。
回傳值
無傳回值。
使用條件與限制
啟用兩圖層,讓 OAM 精靈 0 的不透明像素與背景不透明像素重疊。置於背景後方的優先旗標仍允許命中。最左八像素須開啟對應圖層顯示;X=255 的重疊無法觸發命中。
輪詢 PPUSTATUS($2002)位元 6,先等它清除,再等它設為 1。呼叫時若已命中,會等待下一影格的新命中。讀取不會清除此旗標;PPU 在預繪製階段清除它。
沒有逾時或失敗回傳。精靈 0 隱藏、背景透明、繪製停用或其他無重疊設定,都會使呼叫持續等待。呼叫前須確保命中。不要求啟用 CPU IRQ,也不會啟用 NMI。範例為了另外的影格等待而啟用 NMI。
讀取 $2002 也會影響共用 PPU 位址/捲動寫入鎖存器及 VBlank 旗標。勿將此呼叫插在 $2005/$2006 的兩次寫入之間。請從主程式使用,不要從 NMI/IRQ 處理常式使用。
命中後讀取 $2002,再依 X、Y 順序寫入 $2005。細部 X 立即改變,粗略 X 於下一次水平重載生效。Y 通常在下次預繪製重載生效,除非先被其他捲動寫入取代。這不是立即任意重設 X/Y 光柵位置的操作。
輪詢與指令執行會延遲寫入。KUROSAKI 以掃描線繪製,因此擷取不能證明實機逐點精確邊界。範例將變更放在 Y=96..103 白帶內,讓邊界的不確定性遠離藍、紅長條。
共用標頭 fc_sprite0_scene.h 準備原創藍/紅長條與白色水平帶。精靈 0 位於螢幕 (16,96),藏在背景後方;顯示 Y 為 OAM Y+1,因此原始 OAM Y 是 95。每影格在 VBlank 將頂部捲動還原為零,再等待命中。
使用範例
void main(void) {
s0_prepare();
while (1) {
s0_frame();
nes_split_scroll_sprite0(32,0);
s0_completed++;
}
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
白帶上方,藍色為 X=64..95,紅色為 X=160..191。下方自 Y=104 起,藍色移至 X=32..63,紅色移至 X=128..159,僅下方區域左移 32 像素。水平帶位於 Y=96..103,長條結束於 Y=207。驗證檢查每影格完成一次,並比對所有像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite0_split_alias.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite0_split_alias.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\sprite0_scene.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:37
nes_sprite_hide
這是 nes_game.h 中的巨集,會展開為語法欄所示的內建函式。引入此標頭檔即可使用,不必為此操作加入 C 實作檔。
將一個影子精靈的Y設為0xF0以隱藏它。X、圖塊及屬性會保留以供重複使用。此函式不會釋放已配置的項目,也不會變更精靈函式庫的使用數量。
語法
#define nes_sprite_hide(i) __sprite_hide((i))參數
i精靈項目編號,範圍0–63,不是位元組偏移。實作使用8位元游標將其乘以4;超出範圍的值會以64為週期循環,可能覆寫其他項目。不會檢查項目是否已配置。
回傳值
無(void)。
使用條件與限制
這些操作會修改CPU RAM中的0x0200–0x02FF,不會立即改變硬體OAM。請準備好完整頁面後再呼叫__oam_dma。它們不會維護精靈函式庫的配置旗標、座標陣列或使用數量。應避免中斷處理常式修改或傳送尚未準備完成的頁面。
使用範例
nes_sprite_hide(4); // The HIDE row remains empty after DMA.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例以有標籤的各行區分操作。SET與MOVE在(144,16)、(144,32)顯示8×8向右箭頭;TILE在(144,48)顯示綠色方塊;ATTR在(144,64)顯示水平及垂直皆翻轉的箭頭。HIDE的(144,80)與CLEAR的(144,112)必須為空。META在(136,96)、(144,96)顯示一對箭頭,第二個水平翻轉。NEXT 07表示寫完項目5與6後的下一個位置。箭頭邊緣為紅色、箭桿為綠色,尖端細節為藍色。驗證會逐圖比較8,704個像素並檢查傳送後的OAM位元組;尚未進行實機測試。
ALIASES 程式使用 nes_game.h 中的巨集準備各列,再用 nes_oam_dma() 傳送第 02 頁。TRANSFER 列應在 (144,128) 顯示一個 8×8 箭頭。此例示範不必連結 runtime.c 或 metasprite.c 的巨集形式。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:26
#define nes_sprite_hide(i) __sprite_hide((i))nes_sprite_move
這是 nes_game.h 中的巨集,會展開為語法欄所示的內建函式。引入此標頭檔即可使用,不必為此操作加入 C 實作檔。
只修改一個影子精靈的X與Y位元組,保留圖塊編號及屬性,因此可在不變更調色盤或翻轉狀態的情況下移動同一圖形。
語法
#define nes_sprite_move(i,x,y) __sprite_move((i),(x),(y))參數
i精靈項目編號,範圍0–63,不是位元組偏移。實作使用8位元游標將其乘以4;超出範圍的值會以64為週期循環,可能覆寫其他項目。不會檢查項目是否已配置。
x以像素為單位的橫向位置,使用無號位元組表示,並非圖塊座標。
y直接寫入 OAM 的 Y 位元組。若要將頂端放在第 1 條掃描線或更下方,應傳入頂端座標減一;239..255 位於 240 行可見區域之外。
回傳值
無(void)。
使用條件與限制
這些操作會修改CPU RAM中的0x0200–0x02FF,不會立即改變硬體OAM。請準備好完整頁面後再呼叫__oam_dma。它們不會維護精靈函式庫的配置旗標、座標陣列或使用數量。應避免中斷處理常式修改或傳送尚未準備完成的頁面。
使用範例
nes_sprite_move(1,144,31); // Move to (144,32), retaining tile 128 and attributes 0.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例以有標籤的各行區分操作。SET與MOVE在(144,16)、(144,32)顯示8×8向右箭頭;TILE在(144,48)顯示綠色方塊;ATTR在(144,64)顯示水平及垂直皆翻轉的箭頭。HIDE的(144,80)與CLEAR的(144,112)必須為空。META在(136,96)、(144,96)顯示一對箭頭,第二個水平翻轉。NEXT 07表示寫完項目5與6後的下一個位置。箭頭邊緣為紅色、箭桿為綠色,尖端細節為藍色。驗證會逐圖比較8,704個像素並檢查傳送後的OAM位元組;尚未進行實機測試。
ALIASES 程式使用 nes_game.h 中的巨集準備各列,再用 nes_oam_dma() 傳送第 02 頁。TRANSFER 列應在 (144,128) 顯示一個 8×8 箭頭。此例示範不必連結 runtime.c 或 metasprite.c 的巨集形式。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:25
#define nes_sprite_move(i,x,y) __sprite_move((i),(x),(y))nes_sprite_set
這是 nes_game.h 中的巨集,會展開為語法欄所示的內建函式。引入此標頭檔即可使用,不必為此操作加入 C 實作檔。
將一個精靈的全部四個欄位寫入第02頁影子緩衝區。參數順序為編號、X、Y、圖塊、屬性,實際儲存順序為Y、圖塊、屬性、X。
語法
#define nes_sprite_set(i,x,y,t,a) __sprite_set((i),(x),(y),(t),(a))參數
i精靈項目編號,範圍0–63,不是位元組偏移。實作使用8位元游標將其乘以4;超出範圍的值會以64為週期循環,可能覆寫其他項目。不會檢查項目是否已配置。
x以像素為單位的橫向位置,使用無號位元組表示,並非圖塊座標。
y直接寫入 OAM 的 Y 位元組。若要將頂端放在第 1 條掃描線或更下方,應傳入頂端座標減一;239..255 位於 240 行可見區域之外。
t8 位元圖塊編號。須先載入圖形。8×16 精靈仍遵循硬體規則,函式不會自動調整成成對圖塊編號。
a完整屬性位元組:位元0–1選擇精靈調色盤0–3;位元5使不透明精靈像素位於不透明背景像素之後;位元6與7分別控制水平及垂直翻轉。位元2–4應為0。可用位元OR組合旗標;傳入的位元組會取代全部原有屬性。
回傳值
無(void)。
使用條件與限制
這些操作會修改CPU RAM中的0x0200–0x02FF,不會立即改變硬體OAM。請準備好完整頁面後再呼叫__oam_dma。它們不會維護精靈函式庫的配置旗標、座標陣列或使用數量。應避免中斷處理常式修改或傳送尚未準備完成的頁面。
使用範例
nes_sprite_set(0,144,15,128,0); // An 8x8 arrow at visible position (144,16).這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例以有標籤的各行區分操作。SET與MOVE在(144,16)、(144,32)顯示8×8向右箭頭;TILE在(144,48)顯示綠色方塊;ATTR在(144,64)顯示水平及垂直皆翻轉的箭頭。HIDE的(144,80)與CLEAR的(144,112)必須為空。META在(136,96)、(144,96)顯示一對箭頭,第二個水平翻轉。NEXT 07表示寫完項目5與6後的下一個位置。箭頭邊緣為紅色、箭桿為綠色,尖端細節為藍色。驗證會逐圖比較8,704個像素並檢查傳送後的OAM位元組;尚未進行實機測試。
ALIASES 程式使用 nes_game.h 中的巨集準備各列,再用 nes_oam_dma() 傳送第 02 頁。TRANSFER 列應在 (144,128) 顯示一個 8×8 箭頭。此例示範不必連結 runtime.c 或 metasprite.c 的巨集形式。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:24
#define nes_sprite_set(i,x,y,t,a) __sprite_set((i),(x),(y),(t),(a))nes_vram_clear_queue
這是 nes_game.h 中的巨集,會展開為語法欄所示的內建函式。引入此標頭檔即可使用,不必為此操作加入 C 實作檔。
捨棄內建佇列的全部待處理記錄,並將長度和就緒旗標設為0。不寫入VRAM,也不清除溢位旗標;清除旗標需要另外呼叫__vramq_clear_overflow。
語法
#define nes_vram_clear_queue() __vramq_clear()回傳值
無(void)。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
這些巨集操作編譯器的內建命令佇列,lib/vram.c 也使用同一佇列。它們不會選用 C 執行階段的 nes_vram_queue_* 緩衝區。用 __vramq_len() 查詢待處理命令的編碼位元組數,用 __vramq_overflow() 檢查容量不足,再用 __vramq_clear_overflow() 清除失敗旗標。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
nes_vram_clear_queue();
if (__vramq_len()!=0 || __vramq_overflow()!=1) failures++;
// Clearing queued work deliberately leaves the overflow latch set.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整範例使用 nes_game.h 中的巨集完成單一位元組入列、複製、填滿、提交及清空佇列,並使用 __vramq_* 查詢與執行內建函式檢查效果。畫面標題為 VRAM QUEUE MACROS。大量傳送在關閉繪製時執行;提交操作本身無法保證大量傳送在 VBlank 內完成。
完整程式示範佇列容量、保留的指標、兩種獨立重設,以及直接執行與NMI執行的差異。預期顯示CAPACITY 128、ENCODED BYTES 030、AFTER EXEC 000、OVERFLOW SEEN 001和FAILED CHECKS 000。6筆記錄占30位元組,卻執行512次位元組寫入。OVERFLOW SEEN保留先前刻意觸發拒絕時的值,不表示最終溢位旗標仍設定。
藍色複製區域從像素(0,16)開始,綠色填滿區域從(0,88)開始。每塊包含7個完整的256像素寬圖塊列,以及第8列的248像素,共255個圖塊。最後一個8×8格保持黑色。複製重複實心、左半填滿和三角形的8×8圖樣;因加入後修改了來源資料,首圖塊應為三角形。填滿在呼叫端變數改變後仍保持實心。測試同時檢查形狀和顏色。
在y=160處,x=16應為紅色實心正方形,x=224為紅色左半圖塊,x=240為紅色實心正方形。第一個驗證零長度複製和填滿不會改寫;中間驗證預設NMI執行;最後驗證單次寫入。已取消的(248,160)格必須保持黑色。長傳輸在關閉繪製和NMI時執行,只有最後的小寫入使用NMI。這是NROM模擬器證據,不是實機測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:19
#define nes_vram_clear_queue() __vramq_clear()nes_vram_commit
這是 nes_game.h 中的巨集,會展開為語法欄所示的內建函式。引入此標頭檔即可使用,不必為此操作加入 C 實作檔。
將佇列就緒旗標設為1,允許執行器處理。不複製傳輸資料、不執行PPU寫入,也不等待NMI。提交後應保持佇列和保留的來源資料穩定,直到執行完成。NMI開啟時,預設處理常式可能非同步執行佇列。
語法
#define nes_vram_commit() __vramq_commit()回傳值
無(void)。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
這些巨集操作編譯器的內建命令佇列,lib/vram.c 也使用同一佇列。它們不會選用 C 執行階段的 nes_vram_queue_* 緩衝區。用 __vramq_len() 查詢待處理命令的編碼位元組數,用 __vramq_overflow() 檢查容量不足,再用 __vramq_clear_overflow() 清除失敗旗標。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
nes_vram_commit(); // NMI is disabled here: this only marks the queue ready.
if (__vramq_len()!=30) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整範例使用 nes_game.h 中的巨集完成單一位元組入列、複製、填滿、提交及清空佇列,並使用 __vramq_* 查詢與執行內建函式檢查效果。畫面標題為 VRAM QUEUE MACROS。大量傳送在關閉繪製時執行;提交操作本身無法保證大量傳送在 VBlank 內完成。
完整程式示範佇列容量、保留的指標、兩種獨立重設,以及直接執行與NMI執行的差異。預期顯示CAPACITY 128、ENCODED BYTES 030、AFTER EXEC 000、OVERFLOW SEEN 001和FAILED CHECKS 000。6筆記錄占30位元組,卻執行512次位元組寫入。OVERFLOW SEEN保留先前刻意觸發拒絕時的值,不表示最終溢位旗標仍設定。
藍色複製區域從像素(0,16)開始,綠色填滿區域從(0,88)開始。每塊包含7個完整的256像素寬圖塊列,以及第8列的248像素,共255個圖塊。最後一個8×8格保持黑色。複製重複實心、左半填滿和三角形的8×8圖樣;因加入後修改了來源資料,首圖塊應為三角形。填滿在呼叫端變數改變後仍保持實心。測試同時檢查形狀和顏色。
在y=160處,x=16應為紅色實心正方形,x=224為紅色左半圖塊,x=240為紅色實心正方形。第一個驗證零長度複製和填滿不會改寫;中間驗證預設NMI執行;最後驗證單次寫入。已取消的(248,160)格必須保持黑色。長傳輸在關閉繪製和NMI時執行,只有最後的小寫入使用NMI。這是NROM模擬器證據,不是實機測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:18
#define nes_vram_commit() __vramq_commit()nes_vram_copy
這是 nes_game.h 中的巨集,會展開為語法欄所示的內建函式。引入此標頭檔即可使用,不必為此操作加入 C 實作檔。
加入一筆6位元組記錄,在執行時將src的len位元組複製到ppu_addr。佇列保留來源指標而非資料本身。即使複製255位元組,也只占6位元組命令緩衝區。來源資料依位址遞增順序讀取;目的連續寫入需選擇PPU增量1。
語法
#define nes_vram_copy(addr, src, len) __vramq_copy((addr), (src), (len))參數
addrPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。src指向可讀位元組的近指標,保留到執行時。整個執行期間必須保持資料有效且其記憶體或ROM記憶體庫可存取;不儲存記憶體庫編號或資料副本。非空傳輸需要有效來源,不可使用生命週期已結束的區域陣列。
len位元組數,範圍0至255。一筆記錄處理全部長度,不拆成127位元組的區塊。0仍占用複製或填滿記錄;執行時會設定PPU位址,但不向PPUDATA寫入位元組。256超出此參數範圍。
回傳值
無(void)。
使用條件與限制
加入函式不回傳成功值。完整記錄放不下時,將__vramq_overflow()設為1,保留原有記錄和長度。空間剛好足夠時可以加入。舊溢位旗標不會阻止放得下的新記錄,因此判斷新批次前應先處理或清除旗標。連續多次加入不構成交易。
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
這些巨集操作編譯器的內建命令佇列,lib/vram.c 也使用同一佇列。它們不會選用 C 執行階段的 nes_vram_queue_* 緩衝區。用 __vramq_len() 查詢待處理命令的編碼位元組數,用 __vramq_overflow() 檢查容量不足,再用 __vramq_clear_overflow() 清除失敗旗標。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
nes_vram_copy(0x2040,source_bytes,255);
source_bytes[0]=3; // The executor must see this change through its retained pointer.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整範例使用 nes_game.h 中的巨集完成單一位元組入列、複製、填滿、提交及清空佇列,並使用 __vramq_* 查詢與執行內建函式檢查效果。畫面標題為 VRAM QUEUE MACROS。大量傳送在關閉繪製時執行;提交操作本身無法保證大量傳送在 VBlank 內完成。
完整程式示範佇列容量、保留的指標、兩種獨立重設,以及直接執行與NMI執行的差異。預期顯示CAPACITY 128、ENCODED BYTES 030、AFTER EXEC 000、OVERFLOW SEEN 001和FAILED CHECKS 000。6筆記錄占30位元組,卻執行512次位元組寫入。OVERFLOW SEEN保留先前刻意觸發拒絕時的值,不表示最終溢位旗標仍設定。
藍色複製區域從像素(0,16)開始,綠色填滿區域從(0,88)開始。每塊包含7個完整的256像素寬圖塊列,以及第8列的248像素,共255個圖塊。最後一個8×8格保持黑色。複製重複實心、左半填滿和三角形的8×8圖樣;因加入後修改了來源資料,首圖塊應為三角形。填滿在呼叫端變數改變後仍保持實心。測試同時檢查形狀和顏色。
在y=160處,x=16應為紅色實心正方形,x=224為紅色左半圖塊,x=240為紅色實心正方形。第一個驗證零長度複製和填滿不會改寫;中間驗證預設NMI執行;最後驗證單次寫入。已取消的(248,160)格必須保持黑色。長傳輸在關閉繪製和NMI時執行,只有最後的小寫入使用NMI。這是NROM模擬器證據,不是實機測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:16
#define nes_vram_copy(addr, src, len) __vramq_copy((addr), (src), (len))nes_vram_fill
這是 nes_game.h 中的巨集,會展開為語法欄所示的內建函式。引入此標頭檔即可使用,不必為此操作加入 C 實作檔。
加入一筆5位元組記錄,將單位元組value向PPU重複寫入len次。值儲存在記錄中,之後修改呼叫端變數不會改變已加入的填充值。重複的是單位元組,不是多位元組圖塊圖樣。
語法
#define nes_vram_fill(addr, value, len) __vramq_fill((addr), (value), (len))參數
addrPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。value重複寫入0至255的單一位元組。顯示意義取決於目標是圖塊索引、像素位元平面還是其他位元組結構。
len位元組數,範圍0至255。一筆記錄處理全部長度,不拆成127位元組的區塊。0仍占用複製或填滿記錄;執行時會設定PPU位址,但不向PPUDATA寫入位元組。256超出此參數範圍。
回傳值
無(void)。
使用條件與限制
加入函式不回傳成功值。完整記錄放不下時,將__vramq_overflow()設為1,保留原有記錄和長度。空間剛好足夠時可以加入。舊溢位旗標不會阻止放得下的新記錄,因此判斷新批次前應先處理或清除旗標。連續多次加入不構成交易。
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
這些巨集操作編譯器的內建命令佇列,lib/vram.c 也使用同一佇列。它們不會選用 C 執行階段的 nes_vram_queue_* 緩衝區。用 __vramq_len() 查詢待處理命令的編碼位元組數,用 __vramq_overflow() 檢查容量不足,再用 __vramq_clear_overflow() 清除失敗旗標。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
nes_vram_fill(0x2160,fill_value,255); // Seven complete rows and 31 tiles in the eighth.
fill_value=3; // The queued value stays 1, so the green block remains solid.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整範例使用 nes_game.h 中的巨集完成單一位元組入列、複製、填滿、提交及清空佇列,並使用 __vramq_* 查詢與執行內建函式檢查效果。畫面標題為 VRAM QUEUE MACROS。大量傳送在關閉繪製時執行;提交操作本身無法保證大量傳送在 VBlank 內完成。
完整程式示範佇列容量、保留的指標、兩種獨立重設,以及直接執行與NMI執行的差異。預期顯示CAPACITY 128、ENCODED BYTES 030、AFTER EXEC 000、OVERFLOW SEEN 001和FAILED CHECKS 000。6筆記錄占30位元組,卻執行512次位元組寫入。OVERFLOW SEEN保留先前刻意觸發拒絕時的值,不表示最終溢位旗標仍設定。
藍色複製區域從像素(0,16)開始,綠色填滿區域從(0,88)開始。每塊包含7個完整的256像素寬圖塊列,以及第8列的248像素,共255個圖塊。最後一個8×8格保持黑色。複製重複實心、左半填滿和三角形的8×8圖樣;因加入後修改了來源資料,首圖塊應為三角形。填滿在呼叫端變數改變後仍保持實心。測試同時檢查形狀和顏色。
在y=160處,x=16應為紅色實心正方形,x=224為紅色左半圖塊,x=240為紅色實心正方形。第一個驗證零長度複製和填滿不會改寫;中間驗證預設NMI執行;最後驗證單次寫入。已取消的(248,160)格必須保持黑色。長傳輸在關閉繪製和NMI時執行,只有最後的小寫入使用NMI。這是NROM模擬器證據,不是實機測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:17
#define nes_vram_fill(addr, value, len) __vramq_fill((addr), (value), (len))nes_vram_put
這是 nes_game.h 中的巨集,會展開為語法欄所示的內建函式。引入此標頭檔即可使用,不必為此操作加入 C 實作檔。
將一個PPU位址和單位元組值加入為4位元組記錄。值立即複製進佇列,執行時才寫入PPU。可用來更新名稱表中的一個圖塊,也可指定其他可寫的PPU位元組。
語法
#define nes_vram_put(addr, value) __vramq_put((addr), (value))參數
addrPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。value重複寫入0至255的單一位元組。顯示意義取決於目標是圖塊索引、像素位元平面還是其他位元組結構。
回傳值
無(void)。
使用條件與限制
加入函式不回傳成功值。完整記錄放不下時,將__vramq_overflow()設為1,保留原有記錄和長度。空間剛好足夠時可以加入。舊溢位旗標不會阻止放得下的新記錄,因此判斷新批次前應先處理或清除旗標。連續多次加入不構成交易。
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
這些巨集操作編譯器的內建命令佇列,lib/vram.c 也使用同一佇列。它們不會選用 C 執行階段的 nes_vram_queue_* 緩衝區。用 __vramq_len() 查詢待處理命令的編碼位元組數,用 __vramq_overflow() 檢查容量不足,再用 __vramq_clear_overflow() 清除失敗旗標。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
nes_vram_put(0x2282,1); // Red 8x8 sentinel at pixel (16,160).這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整範例使用 nes_game.h 中的巨集完成單一位元組入列、複製、填滿、提交及清空佇列,並使用 __vramq_* 查詢與執行內建函式檢查效果。畫面標題為 VRAM QUEUE MACROS。大量傳送在關閉繪製時執行;提交操作本身無法保證大量傳送在 VBlank 內完成。
完整程式示範佇列容量、保留的指標、兩種獨立重設,以及直接執行與NMI執行的差異。預期顯示CAPACITY 128、ENCODED BYTES 030、AFTER EXEC 000、OVERFLOW SEEN 001和FAILED CHECKS 000。6筆記錄占30位元組,卻執行512次位元組寫入。OVERFLOW SEEN保留先前刻意觸發拒絕時的值,不表示最終溢位旗標仍設定。
藍色複製區域從像素(0,16)開始,綠色填滿區域從(0,88)開始。每塊包含7個完整的256像素寬圖塊列,以及第8列的248像素,共255個圖塊。最後一個8×8格保持黑色。複製重複實心、左半填滿和三角形的8×8圖樣;因加入後修改了來源資料,首圖塊應為三角形。填滿在呼叫端變數改變後仍保持實心。測試同時檢查形狀和顏色。
在y=160處,x=16應為紅色實心正方形,x=224為紅色左半圖塊,x=240為紅色實心正方形。第一個驗證零長度複製和填滿不會改寫;中間驗證預設NMI執行;最後驗證單次寫入。已取消的(248,160)格必須保持黑色。長傳輸在關閉繪製和NMI時執行,只有最後的小寫入使用NMI。這是NROM模擬器證據,不是實機測試。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/nes_game.h:15
#define nes_vram_put(addr, value) __vramq_put((addr), (value))oam_fair.h — 保留優先順序的精靈輪替
將 64 項軟體池中的有效項目附加到 OAM 暫存緩衝區。每次呼叫都會先將掃描起點加 13,再對 64 取餘數。重複呼叫可輪換 OAM 優先順序、分散精靈閃爍,但不會提高硬體精靈數量上限。
由呼叫端定義 X、Y、active、shadow 陣列及 used 游標,並在固定 PRG 記憶體庫中僅引入一次 oam_fair_impl.h。在 8×8 精靈模式下從主迴圈呼叫。座標對 256 取餘數,不做裁切。此常式不傳送 OAM,請對 shadow 緩衝區所在頁執行 DMA。硬體仍只支援 64 個 OAM 精靈,且每條掃描線最多 8 個。
OAM_FairDraw
將 64 項軟體池中的有效項目附加到 OAM 暫存緩衝區。每次呼叫都會先將掃描起點加 13,再對 64 取餘數。重複呼叫可輪換 OAM 優先順序、分散精靈閃爍,但不會提高硬體精靈數量上限。
語法
void OAM_FairDraw(void);回傳值
沒有 C 回傳值。oam_fair_drawn 儲存此次附加的項目數,oam_fair_used 儲存更新後的位元組游標,oam_fair_phase 儲存此次掃描的起始索引。即使沒有繪製任何項目,phase 仍會推進,此時 oam_fair_drawn 為零。
使用條件與限制
函式沒有參數,請透過共享變數設定。oam_fair_x[64] 和 oam_fair_y[64] 儲存 8×8 精靈的像素中心座標;寫入 OAM 的原始 X 為中心 X−4,原始 Y 為中心 Y−5。oam_fair_active[64] 中非零的項目會被選取,所有輸出項目共用 oam_fair_tile 和 oam_fair_attr 提供的圖塊及屬性位元組。
將 oam_fair_used 設為 oam_fair_shadow[256] 中下一個空閒位元組位移,並保持四位元組對齊。oam_fair_limit 限制此次呼叫可附加的項目數。最多掃描 64 個池項目,在位元組位移 252 處停止寫入,保留槽位 63 不用。游標之前的項目保持不變;末尾未使用的項目須另行隱藏。
由呼叫端定義 X、Y、active、shadow 陣列及 used 游標,並在固定 PRG 記憶體庫中僅引入一次 oam_fair_impl.h。在 8×8 精靈模式下從主迴圈呼叫。座標對 256 取餘數,不做裁切。此常式不傳送 OAM,請對 shadow 緩衝區所在頁執行 DMA。硬體仍只支援 64 個 OAM 精靈,且每條掃描線最多 8 個。
使用範例
oam_fair_used=4; // Byte cursor: reserve the already prepared slot 0.
OAM_FairDraw(); // Phase becomes 13; append pool entries 13, 14 and 15.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
FAIR-POOL 保留槽位 0 中位於 (144,32) 的綠色 8×8 方塊,並附加中心位於 (148,68)、(164,68)、(180,68) 的三個箭頭。它們在畫面上的左上角應分別為 (144,64)、(160,64)、(176,64)。從 phase=0、used=4 開始呼叫,應顯示 PHASE 13、DRAWN 03、BYTES 16。此靜態圖驗證位置及既有項目的保留;另行執行的 64 次呼叫狀態測試驗證每個池項目都恰好成為一次起點。
箭頭採用紅色邊緣、綠色箭桿和藍色箭尖細節;方塊圖塊 129 為綠色。驗證會逐張比對 8,704 個像素的顏色、傳送後的全部 256 位元組 OAM 及顯示標籤。尚未在實體硬體上驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_fair.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_fair.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/oam_fair.h:24
Append active pool entries using the configured common tile/attributes. The emitter stops at byte cursor 252, leaving slot 63 unused to avoid cursor wrap. Hide unused trailing OAM entries separately before DMA.
kitaqfc/lib/oam_fair_impl.h:12
void OAM_FairDraw(void) {
__asm {
LDA oam_fair_phase
CLC
ADC #13
AND #63
STA oam_fair_phase
TAX
LDY oam_fair_used
LDA #0
STA oam_fair_drawn
STA oam_fair_scanned
// Visit each pool entry at most once, preserving already-written OAM entries
// and sharing the configured tile/attribute values across emitted sprites.
kq_fair_loop:
LDA oam_fair_active,X
BEQ kq_fair_next
LDA oam_fair_drawn
CMP oam_fair_limit
BCS kq_fair_done
// Reserve the final four-byte slot so advancing this byte cursor cannot wrap to zero.
CPY #252
BCS kq_fair_done
// Convert the 8x8 center to raw OAM coordinates; Y also needs the hardware minus-one bias.
LDA oam_fair_y,X
SEC
SBC #5
STA oam_fair_shadow,Y
LDA oam_fair_tile
STA oam_fair_shadow+1,Y
LDA oam_fair_attr
STA oam_fair_shadow+2,Y
LDA oam_fair_x,X
SEC
SBC #4
STA oam_fair_shadow+3,Y
INY
INY
INY
INY
INC oam_fair_drawn
// Advance cyclically and stop after returning to this frame's starting entry.
kq_fair_next:
TXA
CLC
ADC #1
AND #63
TAX
CPX oam_fair_phase
BNE kq_fair_loop
// Publish the updated byte cursor for later OAM writers and the VBlank DMA path.
kq_fair_done:
STY oam_fair_used
}
}pad.h — NES 控制器輸入
pad.h 與 pad.c 依 NES 位元順序保存控制器 1 的狀態。讀取時計算前次、按住、新按下與放開遮罩,但不產生重複觸發。需要可設定的獨立按鈕重複時,也要連結 input_repeat.c。控制器 2 使用連接埠 2 的內建函式讀取,前次狀態由遊戲保存。
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
第一次讀取前,將四個 nes_pad1_* 狀態位元組初始化為 0。之後每個輸入週期讀取一次。pressed = current & ~previous,released = previous & ~current,兩者表示最近一次讀取發生的變化。重複狀態需另行呼叫 nes_pad_repeat_step() 更新。
nes_pad_poll
對 $4016 發出選通信號,從控制器 1 的 D0 序列讀取八位元,更新 nes_pad1_prev、nes_pad1_cur、nes_pad1_pressed 與 nes_pad1_released。只讀取一次,不執行 safe 內建函式的比對重試。末尾會讀取 $4017,但不保存控制器 2 的狀態。
語法
void nes_pad_poll(void);回傳值
無(void)。
使用條件與限制
NES 原始格式為 A=0x01、B=0x02、SELECT=0x04、START=0x08、UP=0x10、DOWN=0x20、LEFT=0x40、RIGHT=0x80。位元為 1 表示按下。nes_pad_* 與原始 __pad_* 結果應使用這些值,不要與 input.h 的共用 BTN_* 遮罩混用。
第一次讀取前,將四個 nes_pad1_* 狀態位元組初始化為 0。之後每個輸入週期讀取一次。pressed = current & ~previous,released = previous & ~current,兩者表示最近一次讀取發生的變化。重複狀態需另行呼叫 nes_pad_repeat_step() 更新。
使用範例
nes_pad_poll(); // Read controller 1 and update its held/pressed/released snapshots.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範輪詢→更新連發→查詢狀態的順序,並說明NES查詢函式回傳對應位元,而非布林值1。使用nes_pad_repeat_config(3, 1),按住B達40次更新後放開。FIRST HELD、FIRST TRIGGER、FIRST REPEAT為2,HELD TICKS為40,PULSE COUNT為19,RELEASE BITS為2。初次按下的脈衝之後經過4次更新產生首次連發,隨後每2次更新產生一次。FAILED CHECKS應為0。改變按住的時間會改變脈衝計數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cache實作與原始碼
kitaqfc/lib/pad.h:16
Latch controller input with a 1-to-0 strobe and shift eight controller-1 bits into held/pressed/released masks. This direct path does not perform repeated reads for DMC interference; the final JOY2 read does not populate player-2 state.
kitaqfc/lib/pad.c:21
void nes_pad_poll(void)
{
unsigned char state;
unsigned char mask;
unsigned char sample;
nes_pad1_prev = nes_pad1_cur;
JOY1 = 1;
JOY1 = 0;
state = 0;
mask = 1;
while (mask != 0)
{
sample = JOY1;
if ((sample & 1) != 0)
{
state = state | mask;
}
mask = mask + mask;
}
nes_pad1_cur = state;
nes_pad1_pressed = (unsigned char)(state & (unsigned char)(state ^ nes_pad1_prev));
nes_pad1_released = (unsigned char)(nes_pad1_prev & (unsigned char)(state ^ nes_pad1_prev));
sample = JOY2;
sample = sample;
}palette.h — NES 調色盤
透過 32 位元組 CPU 影子緩衝區,以及立即或佇列上傳,管理背景與精靈色彩。PPU 調色盤位址包含指向相同位置的別名。
nes_palette_apply_now
將 32 個色彩複製至影子緩衝區,再直接上傳至 PPU。
語法
void nes_palette_apply_now(unsigned char* src32);參數
src32可讀取的 32 位元組調色盤,先放 16 個背景色,再放 16 個精靈色;請使用 0–63 的色碼。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
影子緩衝區保留 CPU 位址 0x03C0–0x03DF。PPU 位址 0x3F10/14/18/1C 與 0x3F00/04/08/0C 指向相同位置,因此原始的 32 個影子位元組不一定能對應到 32 個獨立的 PPU 讀回值。 請在安全的 VBlank 時段或關閉繪圖時,使用 PPU 遞增值 1。此輔助函式不會等待、遮罩中斷或還原捲動。
使用範例
nes_palette_apply_now(colors);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 (16,32)、(80,32)、(144,32) 顯示紅、藍、綠的 32×32 背景矩形,並在 (16,96)、(80,96)、(144,96) 以相同色序顯示 8×8 精靈正方形。分開的背景與精靈調色盤示範直接上傳及佇列上傳。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/palette.h:11
Replace shadow palette data and upload all 32 bytes immediately. The caller provides a safe PPU access period; this helper does not wait for VBlank.
kitaqfc/lib/palette.c:28
void nes_palette_apply_now(unsigned char* src32)
{
nes_palette_copy(src32);
nes_ppu_stream_write(0x3F00, nes_palette_shadow, 32);
}nes_palette_apply_shadow_now
將影子緩衝區目前的 32 個色彩直接上傳至 PPU。
語法
void nes_palette_apply_shadow_now(void);回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
影子緩衝區保留 CPU 位址 0x03C0–0x03DF。PPU 位址 0x3F10/14/18/1C 與 0x3F00/04/08/0C 指向相同位置,因此原始的 32 個影子位元組不一定能對應到 32 個獨立的 PPU 讀回值。 請在安全的 VBlank 時段或關閉繪圖時,使用 PPU 遞增值 1。此輔助函式不會等待、遮罩中斷或還原捲動。
使用範例
nes_palette_apply_shadow_now();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 (16,32)、(80,32)、(144,32) 顯示紅、藍、綠的 32×32 背景矩形,並在 (16,96)、(80,96)、(144,96) 以相同色序顯示 8×8 精靈正方形。分開的背景與精靈調色盤示範直接上傳及佇列上傳。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/palette.h:13
Upload the current palette shadow directly, with timing controlled by the caller.
kitaqfc/lib/palette.c:35
void nes_palette_apply_shadow_now(void)
{
nes_ppu_stream_write(0x3F00, nes_palette_shadow, 32);
}nes_palette_copy
將 32 個調色盤位元組複製至 CPU 端影子緩衝區,不傳送至 PPU。
語法
void nes_palette_copy(unsigned char* src32);參數
src32可讀取的 32 位元組調色盤,先放 16 個背景色,再放 16 個精靈色;請使用 0–63 的色碼。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
影子緩衝區保留 CPU 位址 0x03C0–0x03DF。PPU 位址 0x3F10/14/18/1C 與 0x3F00/04/08/0C 指向相同位置,因此原始的 32 個影子位元組不一定能對應到 32 個獨立的 PPU 讀回值。
使用範例
nes_palette_copy(colors);result[0]=nes_palette_shadow[5];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 (16,32)、(80,32)、(144,32) 顯示紅、藍、綠的 32×32 背景矩形,並在 (16,96)、(80,96)、(144,96) 以相同色序顯示 8×8 精靈正方形。分開的背景與精靈調色盤示範直接上傳及佇列上傳。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/palette.h:8
Copy exactly 32 palette bytes to the fixed shadow buffer without writing the PPU.
kitaqfc/lib/palette.c:19
void nes_palette_copy(unsigned char* src32)
{
__memcpy(nes_palette_shadow, src32, 32);
}nes_palette_queue_all
替換影子緩衝區的全部 32 個色彩,並複製到執行階段 VRAM 佇列。
語法
unsigned char nes_palette_queue_all(unsigned char* src32);參數
src32可讀取的 32 位元組調色盤,先放 16 個背景色,再放 16 個精靈色;請使用 0–63 的色碼。
回傳值
成功排入佇列為 1,容量不足為 0。即使失敗,影子緩衝區仍保留新值。成功不代表 PPU 已完成更新。
使用條件與限制
影子緩衝區保留 CPU 位址 0x03C0–0x03DF。PPU 位址 0x3F10/14/18/1C 與 0x3F00/04/08/0C 指向相同位置,因此原始的 32 個影子位元組不一定能對應到 32 個獨立的 PPU 讀回值。 佇列會複製數值,因此成功排入後即可修改來源。請避免佇列生產端與 NMI 消費端之間的競態條件。
使用範例
nes_vram_queue_clear();result[1]=nes_palette_queue_all(colors);result[2]=nes_vram_queue_used;nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 (16,32)、(80,32)、(144,32) 顯示紅、藍、綠的 32×32 背景矩形,並在 (16,96)、(80,96)、(144,96) 以相同色序顯示 8×8 精靈正方形。分開的背景與精靈調色盤示範直接上傳及佇列上傳。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/palette.h:18
Update the shadow and copy all colors into the runtime queue. A queue failure leaves the new shadow contents in place. Return one if the runtime queue accepted the copied payload, zero if it was full. Admission does not mean the NMI consumer has already updated the PPU.
kitaqfc/lib/palette.c:42
unsigned char nes_palette_queue_all(unsigned char* src32)
{
nes_palette_copy(src32);
return nes_vram_queue_try_write(0x3F00, nes_palette_shadow, 32);
}nes_palette_queue_bg4
更新影子緩衝區中一組背景調色盤的四個色彩,並複製至 VRAM 佇列。
語法
unsigned char nes_palette_queue_bg4(unsigned char pal_index, unsigned char* src4);參數
pal_index調色盤索引 0–3;函式不會驗證索引。
src4所選調色盤的四個位元組;請使用 0–63 的色碼。
回傳值
成功排入佇列為 1,容量不足為 0。即使失敗,影子緩衝區仍保留新值。成功不代表 PPU 已完成更新。
使用條件與限制
影子緩衝區保留 CPU 位址 0x03C0–0x03DF。PPU 位址 0x3F10/14/18/1C 與 0x3F00/04/08/0C 指向相同位置,因此原始的 32 個影子位元組不一定能對應到 32 個獨立的 PPU 讀回值。 佇列會複製數值,因此成功排入後即可修改來源。請避免佇列生產端與 NMI 消費端之間的競態條件。
使用範例
result[3]=nes_palette_queue_bg4(3,four);nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 (16,32)、(80,32)、(144,32) 顯示紅、藍、綠的 32×32 背景矩形,並在 (16,96)、(80,96)、(144,96) 以相同色序顯示 8×8 精靈正方形。分開的背景與精靈調色盤示範直接上傳及佇列上傳。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/palette.h:21
Update and queue four background palette bytes. pal_index must be 0..3; there is no range check before writing the shadow.
kitaqfc/lib/palette.c:50
unsigned char nes_palette_queue_bg4(unsigned char pal_index, unsigned char* src4)
{
unsigned char dst;
dst = pal_index + pal_index;
dst = dst + dst;
__memcpy(nes_palette_shadow + dst, src4, 4);
return nes_vram_queue_try_write((unsigned short)(0x3F00 + dst), nes_palette_shadow + dst, 4);
}nes_palette_queue_sprite4
更新影子緩衝區中一組精靈調色盤的四個色彩,並複製至 VRAM 佇列。
語法
unsigned char nes_palette_queue_sprite4(unsigned char pal_index, unsigned char* src4);參數
pal_index調色盤索引 0–3;函式不會驗證索引。
src4所選調色盤的四個位元組;請使用 0–63 的色碼。
回傳值
成功排入佇列為 1,容量不足為 0。即使失敗,影子緩衝區仍保留新值。成功不代表 PPU 已完成更新。
使用條件與限制
影子緩衝區保留 CPU 位址 0x03C0–0x03DF。PPU 位址 0x3F10/14/18/1C 與 0x3F00/04/08/0C 指向相同位置,因此原始的 32 個影子位元組不一定能對應到 32 個獨立的 PPU 讀回值。 佇列會複製數值,因此成功排入後即可修改來源。請避免佇列生產端與 NMI 消費端之間的競態條件。
使用範例
result[4]=nes_palette_queue_sprite4(2,four);nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 (16,32)、(80,32)、(144,32) 顯示紅、藍、綠的 32×32 背景矩形,並在 (16,96)、(80,96)、(144,96) 以相同色序顯示 8×8 精靈正方形。分開的背景與精靈調色盤示範直接上傳及佇列上傳。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/palette.h:24
Update and queue four sprite palette bytes at the 0x3F10 region. The caller supplies pal_index 0..3; NES palette mirroring still applies.
kitaqfc/lib/palette.c:61
unsigned char nes_palette_queue_sprite4(unsigned char pal_index, unsigned char* src4)
{
unsigned char dst;
dst = pal_index + pal_index;
dst = dst + dst;
__memcpy(nes_palette_shadow + (unsigned char)(0x10 + dst), src4, 4);
return nes_vram_queue_try_write((unsigned short)(0x3F10 + dst), nes_palette_shadow + (unsigned char)(0x10 + dst), 4);
}使用 Q5.3 資料型別自訂移動
除了 world/body 函式,physics2d.h 也定義了自訂小數位移所需的型別與常數。此範例依 Q5.3 資料慣例實作 game_step,與 world/body 積分是不同的做法。
KQ2DPosition 儲存整數像素位置(0..255),KQ2DFraction 儲存餘數(0..7),KQ2DSpeed 儲存每 tick 的位移大小(以 1/8 像素為單位,0..255),KQ2DDirection 儲存方向。四種型別都是 u8。方向另外儲存,不以速度的正負號表示。
使用 KQ2D_SUBPIXEL_BITS=3、ONE=8、MASK=7,將 position*8+fraction 合併為 16 位元中間值。方向 NONE=0 表示不移動,NEGATIVE=1 表示減法,POSITIVE=2 表示加法。遊戲必須自行處理邊界,使減法結果非負,且最終整數位置維持在 0..255。
KQ2D_DRAG_BRAKE=1、STUN=2、COAST=3、THRUST=4 是供遊戲定義煞車、暈眩、慣性滑行與推進行為的識別值。僅指定其中一個值不會套用加速度或阻力。請在更新常式中定義各效果及持續時間。
範例:累積半像素位移
上方紅色 16×16 像素方盒從 X=24 開始;下方方盒顯示 16 tick 後的 X=32。速度 4 代表每 tick 移動 4/8=0.5 像素,因此 16 tick 共移動八像素。不同的 Y 位置用來分開兩個狀態,方便比較。後續數值檢查向回移動八 tick,得到 X=28、小數部分為 0。
void game_step() {
u16 total;
total=(u16)position*KQ2D_SUBPIXEL_ONE+fraction;
if(direction==KQ2D_DIR_POSITIVE) total=total+speed;
else if(direction==KQ2D_DIR_NEGATIVE) total=total-speed;
position=(KQ2DPosition)(total>>KQ2D_SUBPIXEL_BITS);
fraction=(KQ2DFraction)(total&KQ2D_SUBPIXEL_MASK);
}
// Initial state: position=24; fraction=0; speed=4;
// direction=KQ2D_DIR_POSITIVE; call game_step() 16 times.
建置
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_subpixel.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\physics_subpixel.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmphysics2d
提供盒體積分、AABB 接觸處理,以及可選用的表面反應求解器。物體使用中心與半長表示;active=0 會排除該欄位,inv_mass_q8<=0 則視為靜態物體。KQRect 使用左上角座標與寬度/高度。盒體配對接觸不使用物體的 restitution 欄位;表面反應則使用 KQSurface2D 係數。
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
kq2d_world_init
將陣列連接至 2D 世界,設定重力為 (0,32)、接觸迭代 4 次,以及每軸速度上限 512。
語法
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);參數
world指向持有物體陣列與模擬設定的世界。
bodies呼叫端持有的物體陣列起始位置,包含 body_count 個元素。
body_count陣列欄位數量,範圍為 0..255,包含未啟用的項目。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq2d_world_init(&world,bodies,2);
result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:36
Retain the caller-owned body array without initializing its elements. Set gravity to (0,32), four contact iterations and a per-axis speed limit of 512. A null world is ignored; the array must outlive subsequent world operations.
kitaqfc/lib/physics2d.c:351
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count)
{
if (world == 0) return;
world->bodies = bodies;
world->body_count = body_count;
world->gravity_x = 0;
world->gravity_y = 32;
world->solver_iterations = 4;
world->max_speed = 512;
}kq2d_step
先積分作用中的動態物體,再處理陣列中已啟用項目之間的接觸。
語法
void kq2d_step(KQWorld2D* world);參數
world指向持有物體陣列與模擬設定的世界。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
接觸沿穿入較淺的軸處理,深度相同時選 Y 軸。位置修正使用反質量,但兩個動態物體在該軸的速度會設為兩者的簡單平均;碰到靜態物體時,該速度分量歸零。此求解器不使用 restitution_q8。這是離散碰撞處理,可能漏掉快速穿越。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
world 或陣列為 NULL 時忽略。即使 solver_iterations 為零,仍會執行一次接觸處理。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq2d_step(&world);
result[22]=bodies[0].x; result[23]=bodies[0].y;
result[24]=bodies[0].vx; result[25]=bodies[0].vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:41
Advance active dynamic bodies, then visit each active unordered pair for the configured contact passes (zero means one). Static bodies still participate as obstacles. The world borrows its array and uses non-reentrant helper scratch. This is discrete integration; fast bodies can pass through thin obstacles.
kitaqfc/lib/physics2d.c:581
void kq2d_step(KQWorld2D* world)
{
if (world == 0) return;
if (world->bodies == 0) return;
KQBody2D* bodies = world->bodies;
u8 count = world->body_count;
// Integrate dynamic bodies.
u8 i;
for (i = 0; i < count; i++)
{
KQBody2D* b = &bodies[(u8)i];
if (b->active == 0) continue;
if (b->inv_mass_q8 <= 0) continue;
kq2d_asm_value = b->vx;
kq2d_asm_operand = world->gravity_x;
kq2d__add_value();
kq2d_asm_limit = world->max_speed;
kq2d__clamp_value();
b->vx = kq2d_asm_value;
kq2d_asm_value = b->vy;
kq2d_asm_operand = world->gravity_y;
kq2d__add_value();
kq2d_asm_limit = world->max_speed;
kq2d__clamp_value();
b->vy = kq2d_asm_value;
kq2d_asm_value = b->x;
kq2d_asm_operand = b->vx;
kq2d__add_value();
b->x = kq2d_asm_value;
kq2d_asm_value = b->y;
kq2d_asm_operand = b->vy;
kq2d__add_value();
b->y = kq2d_asm_value;
}
// Solve contacts with a small fixed iteration count.
u8 iterations = world->solver_iterations;
if (iterations == 0) iterations = 1;
u8 it;
for (it = 0; it < iterations; it++)
{
for (i = 0; i < count; i++)
{
KQBody2D* a = &bodies[(u8)i];
if (a->active == 0) continue;
u8 j;
for (j = (u8)(i + 1); j < count; j++)
{
KQBody2D* b = &bodies[(u8)j];
if (b->active == 0) continue;
kq2d__resolve_pair(a, b);
}
}
}
}kq2d_integrate_body
對一個動態物體套用世界重力與每軸速度上限,再將速度加至位置。
語法
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);參數
world指向持有物體陣列與模擬設定的世界。
body指向要修改的物體。本操作未使用的欄位會保持不變。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
忽略 NULL、未啟用物體及反質量小於或等於零的物體。速度上限請提供非負值。
此呼叫不處理與其他物體的接觸。world 為 NULL 時也會忽略。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq2d_integrate_body(&world,&temp);
result[18]=temp.x; result[19]=temp.y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:45
For one active dynamic body, add gravity, clamp each velocity axis and then add velocity to position. Null inputs are ignored; no contacts are solved. Use a nonnegative speed limit and keep additions in signed 16-bit range.
kitaqfc/lib/physics2d.c:451
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body)
{
if (world == 0) return;
if (body == 0) return;
if (body->active == 0) return;
if (body->inv_mass_q8 <= 0) return;
kq2d_asm_value = body->vx;
kq2d_asm_operand = world->gravity_x;
kq2d__add_value();
kq2d_asm_limit = world->max_speed;
kq2d__clamp_value();
body->vx = kq2d_asm_value;
kq2d_asm_value = body->vy;
kq2d_asm_operand = world->gravity_y;
kq2d__add_value();
kq2d_asm_limit = world->max_speed;
kq2d__clamp_value();
body->vy = kq2d_asm_value;
kq2d_asm_value = body->x;
kq2d_asm_operand = body->vx;
kq2d__add_value();
body->x = kq2d_asm_value;
kq2d_asm_value = body->y;
kq2d_asm_operand = body->vy;
kq2d__add_value();
body->y = kq2d_asm_value;
}kq2d_overlap_aabb
檢查兩個以中心表示的盒體是否在 X、Y 兩軸皆嚴格重疊。
語法
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);參數
a有效的物體指標。此查詢忽略啟用狀態、質量與旗標。
b有效的物體指標。此查詢忽略啟用狀態、質量與旗標。
回傳值
內部重疊時傳回 1,僅相觸或分離時傳回 0。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
result[20]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);
bodies[1].x=40; result[21]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:49
Test strict overlap of two centered boxes; touching edges return false. Both pointers must be valid. Active/mass flags are ignored, and coordinate differences and extent sums must fit the signed 16-bit calculations.
kitaqfc/lib/physics2d.c:366
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b)
{
s16 dx = (s16)(b->x - a->x);
s16 dy = (s16)(b->y - a->y);
s16 adx = kq2d__abs_s16(dx);
s16 ady = kq2d__abs_s16(dy);
s16 sx = (s16)(a->half_x + b->half_x);
s16 sy = (s16)(a->half_y + b->half_y);
if (adx >= sx) return 0;
if (ady >= sy) return 0;
return 1;
}kq2d_body_init
以指定半長初始化以中心表示的盒體,將速度設為零、反質量設為 256,並啟用物體。
語法
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
x中心或點的 X 座標;範例以像素為單位。
y中心或點的 Y 座標;範例中正方向朝下。
half_xX 軸半長;盒體的完整寬度為此值的兩倍。
half_yY 軸半長;盒體的完整高度為此值的兩倍。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
將 restitution_q8 設為零。body 為 NULL 時忽略呼叫。請提供正的半長。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq2d_body_init(&temp,10,20,8,8);
result[3]=temp.inv_mass_q8; result[4]=temp.active;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:52
Initialize an active unit-inverse-mass body at the supplied center and half extents, with zero velocity and reserved restitution set to zero. Null is ignored.
kitaqfc/lib/physics2d.c:384
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y)
{
if (body == 0) return;
body->x = x;
body->y = y;
body->vx = 0;
body->vy = 0;
body->half_x = half_x;
body->half_y = half_y;
body->inv_mass_q8 = 256;
body->restitution_q8 = 0;
body->active = 1;
}kq2d_body_set_pos
只取代物體中心,保留速度、尺寸與啟用狀態。
語法
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
x中心或點的 X 座標;範例以像素為單位。
y中心或點的 Y 座標;範例中正方向朝下。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
忽略 NULL。指標有效時,未啟用及靜態物體也會被修改。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq2d_body_set_pos(&temp,-12,20);
result[5]=temp.x; result[6]=temp.y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:54
Replace the center without altering velocity, extents or activity. Null is ignored.
kitaqfc/lib/physics2d.c:399
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y)
{
if (body == 0) return;
body->x = x;
body->y = y;
}kq2d_body_set_velocity
直接設定速度,不限制其範圍,也不更新位置。
語法
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
vx每個模擬刻度的 X 位移,單位與位置相同。
vy每個模擬刻度的 Y 位移,單位與位置相同。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
忽略 NULL。指標有效時,未啟用及靜態物體也會被修改。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq2d_body_set_velocity(&temp,40,-30);
result[7]=temp.vx; result[8]=temp.vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:56
Replace velocity without clamping or checking activity/mass. Null is ignored.
kitaqfc/lib/physics2d.c:407
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy)
{
if (body == 0) return;
body->vx = vx;
body->vy = vy;
}kq2d_body_apply_gravity
對作用中的動態物體加上重力,並將每軸速度限制在 +/-max_speed,不更新位置。
語法
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
gravity_x本次呼叫加至 X 速度的加速度。
gravity_y本次呼叫加至 Y 速度的加速度。
max_speed速度上限。各項說明會指出此限制是作用於每個軸,還是整個向量。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
忽略 NULL、未啟用物體及反質量小於或等於零的物體。速度上限請提供非負值。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq2d_body_apply_gravity(&temp,5,-10,32);
result[9]=temp.vx; result[10]=temp.vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:60
Add gravity and clamp each velocity axis separately for an active dynamic body. Null, inactive and static bodies are ignored. Supply a nonnegative limit and avoid overflow in the additions before clamping; position is unchanged.
kitaqfc/lib/physics2d.c:417
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed)
{
if (body == 0) return;
if (body->active == 0) return;
if (body->inv_mass_q8 <= 0) return;
kq2d_asm_value = body->vx;
kq2d_asm_operand = gravity_x;
kq2d__add_value();
kq2d_asm_limit = max_speed;
kq2d__clamp_value();
body->vx = kq2d_asm_value;
kq2d_asm_value = body->vy;
kq2d_asm_operand = gravity_y;
kq2d__add_value();
kq2d_asm_limit = max_speed;
kq2d__clamp_value();
body->vy = kq2d_asm_value;
}kq2d_body_apply_friction
將兩個速度分量乘上帶正負號位元組係數再除以 256,不檢查位置或啟用狀態。
語法
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
friction_q8此函式使用的速度倍率。它會轉成 s8,因此 128..255 會成為負係數。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
0..127 對應倍率 0..127/256。128..255 轉成 s8 後成為負數,會反轉速度方向。若要在 0..255 範圍使用非負阻尼,請對各速度分量使用 kq2d_scale_q8。乘積向零截斷。忽略 NULL。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq2d_body_apply_friction(&temp,64);
result[11]=temp.vx; result[12]=temp.vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:64
Scale both velocities by a signed eight-bit coefficient divided by 256. Despite the unsigned parameter, values 128..255 become negative coefficients; this is not a full-range unsigned Q8 damping helper. Null is ignored.
kitaqfc/lib/physics2d.c:441
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8)
{
if (body == 0) return;
body->vx = kq2d_scale_q8(body->vx, (s16)(s8)friction_q8);
body->vy = kq2d_scale_q8(body->vy, (s16)(s8)friction_q8);
}kq2d_rect_intersect
檢查以左上角位置與尺寸表示的兩個矩形,其內部是否重疊。
語法
u8 kq2d_rect_intersect(KQRect a, KQRect b);參數
aKQRect 值,包含左上角座標及正的寬度與高度。
bKQRect 值,包含左上角座標及正的寬度與高度。
回傳值
內部重疊時傳回 1,僅相觸或分離時傳回 0。
使用條件與限制
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
不會明確拒絕非正尺寸。請勿將物體中心與半長直接複製到 KQRect。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
result[14]=kq2d_rect_intersect(r1,r2);
r2.x=16; result[15]=kq2d_rect_intersect(r1,r2);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:67
Delegate strict rectangle overlap to the fixed-point utility; edge-only contact is false. Coordinate-plus-size sums must remain representable as s16.
kitaqfc/lib/physics2d.c:485
u8 kq2d_rect_intersect(KQRect a, KQRect b)
{
return kq_rect_intersect(a, b);
}kq2d_point_in_rect
檢查點是否位於矩形內;包含左邊與上邊,不包含右邊與下邊。
語法
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);參數
x中心或點的 X 座標;範例以像素為單位。
y中心或點的 Y 座標;範例中正方向朝下。
rKQRect 值,包含左上角位置 x/y 與寬度/高度 w/h。
回傳值
位於內部時傳回 1,外部時傳回 0。
使用條件與限制
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
result[16]=kq2d_point_in_rect(0,0,r1);
result[17]=kq2d_point_in_rect(16,0,r1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是初始狀態,右側是一個節拍後。中心為 (24,24)、速度為 (4,16) 的紅色 16×16 方塊移至 (28,36),落在藍色地板上,Y 速度歸零。兩面板原點位於螢幕 (8,48) 與 (88,48)。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢及帶正負號縮放。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:70
Delegate the half-open point test: include left/top and exclude right/bottom. Coordinate-plus-size sums must remain representable as s16.
kitaqfc/lib/physics2d.c:492
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r)
{
return kq_point_in_rect(x, y, r);
}kq2d_scale_q8
乘上帶正負號的係數再除以 256,不分正負皆向零截斷。
語法
s16 kq2d_scale_q8(s16 value, s16 coefficient);參數
value要縮放的帶正負號 16 位元值。
coefficient範圍為 -256..256 的帶正負號係數,256 代表 1.0。
回傳值
傳回向零截斷的帶正負號 16 位元結果。
使用條件與限制
係數只能使用 -256..256;+/-256 代表 +/-1 倍。value=-32768 且 coefficient=-256 時,數學結果為 32768,無法以 s16 表示。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
result[0]=kq2d_scale_q8(-257,128);
result[1]=kq2d_scale_q8(300,-256);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
紅色物體保持原位。綠色速度線由左側的 (8,16) 變成右側的 (2,−8),呈現撞上藍色表面後的反彈及切向摩擦。面板原點位於螢幕 (8,48) 與 (88,48),物體中心的局部座標為 (24,40)。入射速率為 16,交越時間範例傳回 192/256。另一個限速呼叫會將 (300,400) 降為 (147,196)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_surface.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_surface.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:86
Truncates toward zero, including negative values; coefficient is -256..256.
kitaqfc/lib/physics2d.c:8
s16 kq2d_scale_q8(s16 value,s16 coefficient) {
u16 magnitude;u16 product;u8 factor;u8 negative;
__asm {
LDA value
ORA value+1
BEQ kqfc_scale_zero
LDA coefficient
BNE kqfc_scale_fraction
LDA coefficient+1
BEQ kqfc_scale_zero
BMI kqfc_scale_negate_value
LDA value
LDX value+1
RTS
kqfc_scale_negate_value:
SEC
LDA #0
SBC value
STA product
LDA #0
SBC value+1
TAX
LDA product
RTS
kqfc_scale_zero:
LDA #0
LDX #0
RTS
kqfc_scale_fraction:
LDA value+1
EOR coefficient+1
AND #128
STA negative
LDA value
STA magnitude
LDA value+1
STA magnitude+1
BPL kqfc_scale_value_positive
SEC
LDA #0
SBC magnitude
STA magnitude
LDA #0
SBC magnitude+1
STA magnitude+1
kqfc_scale_value_positive:
LDA coefficient
STA factor
LDA coefficient+1
BPL kqfc_scale_factor_positive
SEC
LDA #0
SBC factor
STA factor
kqfc_scale_factor_positive:
LDA #0
STA product
STA product+1
// Process coefficient bit 0; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_0
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_0:
ROR product+1
ROR product
// Process coefficient bit 1; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_1
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_1:
ROR product+1
ROR product
// Process coefficient bit 2; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_2
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_2:
ROR product+1
ROR product
// Process coefficient bit 3; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_3
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_3:
ROR product+1
ROR product
// Process coefficient bit 4; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_4
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_4:
ROR product+1
ROR product
// Process coefficient bit 5; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_5
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_5:
ROR product+1
ROR product
// Process coefficient bit 6; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_6
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_6:
ROR product+1
ROR product
// Process coefficient bit 7; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_7
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_7:
ROR product+1
ROR product
LDA negative
BEQ kqfc_scale_positive
SEC
LDA #0
SBC product
STA product
LDA #0
SBC product+1
TAX
LDA product
RTS
kqfc_scale_positive:
LDA product
LDX product+1
RTS
}
}kq2d_body_limit_speed
保守估計向量長度,並以相同比例縮放兩軸,限制合成速率。
語法
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
max_speed速度上限。各項說明會指出此限制是作用於每個軸,還是整個向量。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
速度分量的絕對值與正的 max_speed 都應不超過 16383。上限小於或等於零時,速度歸零。忽略 NULL,但不會因啟用狀態或質量而略過修改。整數量化可能使結果低於上限,極小的縮放係數也可能使結果成為零。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq2d_body_limit_speed(&body,250);
result[2]=body.vx; result[3]=body.vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
紅色物體保持原位。綠色速度線由左側的 (8,16) 變成右側的 (2,−8),呈現撞上藍色表面後的反彈及切向摩擦。面板原點位於螢幕 (8,48) 與 (88,48),物體中心的局部座標為 (24,40)。入射速率為 16,交越時間範例傳回 192/256。另一個限速呼叫會將 (300,400) 降為 (147,196)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_surface.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_surface.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:90
Conservative circular bound, with a shared Q8 scale for both components. Quantizes toward zero; very small limits relative to input may yield zero. Components and positive max_speed must be <= 16383 in magnitude.
kitaqfc/lib/physics2d.c:214
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed)
{
u16 x;
u16 y;
u16 swap;
u16 ratio;
u16 length;
if (body == 0) return;
if (max_speed <= 0) { body->vx = 0; body->vy = 0; return; }
x = (u16)body->vx;
y = (u16)body->vy;
if (body->vx < 0) x = (u16)(0 - body->vx);
if (body->vy < 0) y = (u16)(0 - body->vy);
if (x + y <= (u16)max_speed) return;
if (x < y) { swap = x; x = y; y = swap; }
// major + minor/2 bounds hypot from above for 0 <= minor <= major.
if (x + (y >> 1) + 1 <= (u16)max_speed) return;
// Round the minor/major ratio upward for the 65-entry upper-bound table.
// The extra unit covers truncation when converting the estimate back to speed.
ratio = (kq2d__fraction_q8(y, x) + 4) >> 2;
if (ratio > 64) ratio = 64;
length = x + (u16)kq2d_scale_q8((s16)x, (s16)kq2d_hypot_extra[(u8)ratio]) + 1;
if (length <= (u16)max_speed) return;
ratio = kq2d__fraction_q8((u16)max_speed, length);
body->vx = kq2d_scale_q8(body->vx, (s16)ratio);
body->vy = kq2d_scale_q8(body->vy, (s16)ratio);
}kq2d_body_resolve_surface
以相對於移動表面的速度,套用法線方向反彈、最低反彈速率與切向摩擦。
語法
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
surface指向包含法線、速度、反彈與摩擦設定的 KQSurface2D。
回傳值
傳回正的法線方向入射速率;輸入為 NULL 或彼此分離時傳回 0。
使用條件與限制
使用長度為 256 的 Q8 單位法線。相對速度分量須在 +/-8191 內,threshold/kick 須非負,係數須在 0..255。僅在入射速率嚴格大於門檻時套用恢復係數,kick 作為最低反彈速率。輸入為 NULL 或彼此分離時,不改變速度。接觸偵測與穿入修正須另外處理;不檢查啟用狀態或質量。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
result[6]=kq2d_body_resolve_surface(&body,&surface);
result[7]=body.vx; result[8]=body.vy; result[9]=body.y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
紅色物體保持原位。綠色速度線由左側的 (8,16) 變成右側的 (2,−8),呈現撞上藍色表面後的反彈及切向摩擦。面板原點位於螢幕 (8,48) 與 (88,48),物體中心的局部座標為 (24,40)。入射速率為 16,交越時間範例傳回 192/256。另一個限速呼叫會將 (300,400) 降為 (147,196)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_surface.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_surface.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:93
Kinematic surface response; returns incoming normal speed, or zero if separating. Caller resolves penetration separately. Relative components must fit +/-8191.
kitaqfc/lib/physics2d.c:268
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface)
{
s16 vx;
s16 vy;
s16 speed;
s16 tangent;
s16 bounce = 0;
s16 impulse;
s16 friction;
if (body == 0 || surface == 0) return 0;
vx = (s16)(body->vx - surface->vx);
vy = (s16)(body->vy - surface->vy);
speed = (s16)(kq2d_scale_q8(vx,surface->nx_q8) + kq2d_scale_q8(vy,surface->ny_q8));
if (speed >= 0) return 0;
speed = (s16)(0 - speed);
if (speed > surface->bounce_threshold) bounce = kq2d_scale_q8(speed,(s16)surface->restitution_q8);
if (bounce < surface->kick) bounce = surface->kick;
impulse = (s16)(speed + bounce);
// A resting contact is a tangent constraint, not a tiny rounded bounce.
if (bounce == 0) {
tangent = (s16)(kq2d__rest_component(vy,surface->nx_q8) - kq2d__rest_component(vx,surface->ny_q8));
friction = kq2d_scale_q8(impulse,(s16)surface->friction_q8);
if (tangent > friction) tangent = (s16)(tangent - friction);
else if (tangent < (s16)(0 - friction)) tangent = (s16)(tangent + friction);
else tangent = 0;
body->vx = (s16)(surface->vx - kq2d__rest_component(tangent,surface->ny_q8));
body->vy = (s16)(surface->vy + kq2d__rest_component(tangent,surface->nx_q8));
return speed;
}
body->vx = (s16)(body->vx + kq2d_scale_q8(impulse,surface->nx_q8));
body->vy = (s16)(body->vy + kq2d_scale_q8(impulse,surface->ny_q8));
if (surface->friction_q8 != 0) {
tangent = (s16)(kq2d_scale_q8(vy,surface->nx_q8) - kq2d_scale_q8(vx,surface->ny_q8));
friction = kq2d_scale_q8(impulse,(s16)surface->friction_q8);
if (tangent > friction) tangent = friction;
if (tangent < (s16)(0 - friction)) tangent = (s16)(0 - friction);
body->vx = (s16)(body->vx + kq2d_scale_q8(tangent,surface->ny_q8));
body->vy = (s16)(body->vy - kq2d_scale_q8(tangent,surface->nx_q8));
}
return speed;
}kq2d_surface_toi_q8
假設線性運動,以起始與結束的帶正負號間距估計刻度內的穿越時間。
語法
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);參數
start_gap刻度開始時的帶正負號間距;正值表示位於表面外側。
end_gap刻度結束時的帶正負號間距;負值表示已越過表面。
回傳值
傳回 0..256 的 Q8 時間;192 代表該刻度的 75%。
使用條件與限制
間距須在 +/-8191 內。起始間距小於或等於零時傳回 0;結束間距大於或等於零時傳回 256。初始重疊與時間零共用回傳值,沒有穿越與恰好在終點接觸也共用回傳值。不改變位置。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
result[4]=kq2d_surface_toi_q8(6,-2);
result[5]=kq2d_surface_toi_q8(6,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
紅色物體保持原位。綠色速度線由左側的 (8,16) 變成右側的 (2,−8),呈現撞上藍色表面後的反彈及切向摩擦。面板原點位於螢幕 (8,48) 與 (88,48),物體中心的局部座標為 (24,40)。入射速率為 16,交越時間範例傳回 192/256。另一個限速呼叫會將 (300,400) 降為 (147,196)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_surface.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_surface.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics2d.h:96
Linear crossing time in Q8 (0..256); positive separation is outside. Returns 0 for initial overlap, 256 for no crossing. Gaps must fit +/-8191.
kitaqfc/lib/physics2d.c:245
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap)
{
if (start_gap <= 0) return 0;
if (end_gap >= 0) return 256;
return kq2d__fraction_q8((u16)start_gap, (u16)(start_gap - end_gap));
}physics3d
用於不旋轉的 3D 盒體,以中心及各軸半長表示。質量/反質量決定接觸權重,restitution_q8 控制反彈,ax/ay/az 提供持續加速度。繪製須另外處理。範例繪出同一物體的正視圖與俯視圖,呈現深度方向移動及牆面反彈。
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
last_impact_speed 記錄沿接觸軸的最大接近速度。積分時會清除作用中動態物體的此值;靜態及未啟用物體則保留。break_speed 與 KQ3D_BODY_BROKEN 都不會自動觸發破壞。遊戲自行決定何時破壞物體,並修改 flags/active。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
kq3d_world_init
將物體陣列連接至 3D 世界,設定重力 (0,24,0)、4 次處理及每軸速度上限 512。
語法
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count);參數
world指向持有物體陣列與模擬設定的世界。
bodies呼叫端持有的物體陣列起始位置,包含 body_count 個元素。
body_count陣列欄位數量,範圍為 0..255,包含未啟用的項目。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq3d_world_init(&world,bodies,2);
result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為 X/Y 正視圖,右側為 X/Z 俯視圖。綠色外框標示初始位置 (24,24,16),紅色方塊表示一個節拍後的 (36,24,24),藍色區域是靜態障礙物。X 速度由 16 變為 −14,Z 速度保持 8。衝擊值為 16,但即使 break_speed=1,旗標仍為零。面板原點位於螢幕 (8,48) 與 (88,48)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics3d.h:47
Borrow the body array without initializing it. Set gravity (0,24,0), four contact passes and a per-axis speed limit of 512. Null world is ignored; the caller retains ownership and must keep the array alive.
kitaqfc/lib/physics3d.c:125
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count)
{
if (world == 0) return;
world->bodies = bodies;
world->body_count = body_count;
world->gravity_x = 0;
world->gravity_y = 24;
world->gravity_z = 0;
world->solver_iterations = 4;
world->max_speed = 512;
}kq3d_body_init
初始化 3D 中心、半長與質量;將速度、加速度、衝擊與旗標歸零,並啟用物體。
語法
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
x中心或點的 X 座標;範例以像素為單位。
y中心或點的 Y 座標;範例中正方向朝下。
z中心的 Z 座標,在範例俯視圖中以垂直方向呈現。
half_xX 軸半長;盒體的完整寬度為此值的兩倍。
half_yY 軸半長;盒體的完整高度為此值的兩倍。
half_zZ 軸半長;完整深度為此值的兩倍。
mass_q8質量值,256 代表 1.0;小於或等於零時建立靜態物體。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
恢復係數為 224,break_speed 為零。質量遵循 kq3d_body_set_mass 的規則。忽略 NULL;呼叫端須提供有效半長。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq3d_body_init(&temp,10,20,30,8,8,8,256);
result[3]=temp.inv_mass_q8; result[4]=temp.restitution_q8; result[5]=temp.active;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為 X/Y 正視圖,右側為 X/Z 俯視圖。綠色外框標示初始位置 (24,24,16),紅色方塊表示一個節拍後的 (36,24,24),藍色區域是靜態障礙物。X 速度由 16 變為 −14,Z 速度保持 8。衝擊值為 16,但即使 break_speed=1,旗標仍為零。面板原點位於螢幕 (8,48) 與 (88,48)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics3d.h:51
Initialize an active centered box with zero velocity/acceleration, restitution 224, cleared impact/flags and mass set through the weight helper. The caller supplies valid half extents. Null body is ignored.
kitaqfc/lib/physics3d.c:161
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8)
{
if (body == 0) return;
body->x = x;
body->y = y;
body->z = z;
body->vx = 0;
body->vy = 0;
body->vz = 0;
body->ax = 0;
body->ay = 0;
body->az = 0;
body->half_x = half_x;
body->half_y = half_y;
body->half_z = half_z;
body->restitution_q8 = 224;
body->break_speed = 0;
body->last_impact_speed = 0;
body->active = 1;
body->flags = 0;
kq3d_body_set_mass(body, mass_q8);
}kq3d_body_set_mass
儲存指定質量,並計算用於修正與反彈的反質量權重。
語法
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
mass_q8質量值,256 代表 1.0;小於或等於零時建立靜態物體。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
質量小於或等於零時,反質量為零,代表靜態物體。正質量使用整數式 32767/max(mass,64),最小值為 1。儲存的質量保留請求值,因此此權重不是精確的 Q8 倒數。質量 256 得到反質量 127。速度與啟用狀態不變;忽略 NULL。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq3d_body_set_mass(&temp,32); result[6]=temp.mass_q8; result[7]=temp.inv_mass_q8;
kq3d_body_set_mass(&temp,0); result[8]=temp.inv_mass_q8;
kq3d_body_set_mass(&temp,256);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為 X/Y 正視圖,右側為 X/Z 俯視圖。綠色外框標示初始位置 (24,24,16),紅色方塊表示一個節拍後的 (36,24,24),藍色區域是靜態障礙物。X 速度由 16 變為 −14,Z 速度保持 8。衝擊值為 16,但即使 break_speed=1,旗標仍為零。面板原點位於螢幕 (8,48) 與 (88,48)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics3d.h:56
Store the requested mass; nonpositive mass makes the body static. For positive mass compute inverse weight as max(1,32767/max(mass,64)). The stored mass retains the original input; this is a relative solver weight, not an exact Q8 reciprocal. Null body is ignored.
kitaqfc/lib/physics3d.c:142
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8)
{
if (body == 0) return;
body->mass_q8 = mass_q8;
if (mass_q8 <= 0)
{
body->inv_mass_q8 = 0;
return;
}
if (mass_q8 < 64) mass_q8 = 64;
body->inv_mass_q8 = (s16)(32767 / mass_q8);
if (body->inv_mass_q8 <= 0) body->inv_mass_q8 = 1;
}kq3d_step
積分作用中的動態物體,並處理世界內已啟用項目之間的接觸修正、反彈與衝擊記錄。
語法
void kq3d_step(KQWorld3D* world);參數
world指向持有物體陣列與模擬設定的世界。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
接觸使用穿入最淺的軸,相同時依 X、Y、Z 的順序選擇。只有彼此接近的運動才會產生反彈,計算使用反質量,以及限制在 0..256 的平均恢復係數。不處理高速穿透、旋轉、角動量或摩擦。
last_impact_speed 記錄沿接觸軸的最大接近速度。積分時會清除作用中動態物體的此值;靜態及未啟用物體則保留。break_speed 與 KQ3D_BODY_BROKEN 都不會自動觸發破壞。遊戲自行決定何時破壞物體,並修改 flags/active。
world 或陣列為 NULL 時忽略。即使 solver_iterations 為零,仍會執行一次接觸處理。
中間運算 impact*(256+restitution) 與 correction*inverse-mass 的乘積也是 s16。乘積須不超過 32767;例如 restitution 為 256 時,impact 應不超過 63。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq3d_step(&world);
result[16]=bodies[0].x; result[17]=bodies[0].y; result[18]=bodies[0].z;
result[19]=bodies[0].vx; result[20]=bodies[0].vz;
result[21]=bodies[0].last_impact_speed; result[22]=bodies[0].flags;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為 X/Y 正視圖,右側為 X/Z 俯視圖。綠色外框標示初始位置 (24,24,16),紅色方塊表示一個節拍後的 (36,24,24),藍色區域是靜態障礙物。X 速度由 16 變為 −14,Z 速度保持 8。衝擊值為 16,但即使 break_speed=1,旗標仍為零。面板原點位於螢幕 (8,48) 與 (88,48)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics3d.h:62
Integrate active dynamic bodies and reset their impact values, then solve each active unordered pair for the configured passes (zero means one). Static bodies retain previous impact maxima until the game clears them. Acceleration persists; flags and break thresholds remain game-owned. This discrete solver uses non-reentrant helper scratch and can miss fast crossings.
kitaqfc/lib/physics3d.c:323
void kq3d_step(KQWorld3D* world)
{
if (world == 0) return;
if (world->bodies == 0) return;
KQBody3D* bodies = world->bodies;
u8 count = world->body_count;
u8 i;
for (i = 0; i < count; i++)
{
KQBody3D* b = &bodies[(u8)i];
if (b->active == 0) continue;
if (b->inv_mass_q8 <= 0) continue;
b->last_impact_speed = 0;
kq3d_asm_value = b->vx;
kq3d_asm_operand = world->gravity_x;
kq3d__add_value();
kq3d_asm_operand = b->ax;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
b->vx = kq3d_asm_value;
kq3d_asm_value = b->vy;
kq3d_asm_operand = world->gravity_y;
kq3d__add_value();
kq3d_asm_operand = b->ay;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
b->vy = kq3d_asm_value;
kq3d_asm_value = b->vz;
kq3d_asm_operand = world->gravity_z;
kq3d__add_value();
kq3d_asm_operand = b->az;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
b->vz = kq3d_asm_value;
kq3d_asm_value = b->x;
kq3d_asm_operand = b->vx;
kq3d__add_value();
b->x = kq3d_asm_value;
kq3d_asm_value = b->y;
kq3d_asm_operand = b->vy;
kq3d__add_value();
b->y = kq3d_asm_value;
kq3d_asm_value = b->z;
kq3d_asm_operand = b->vz;
kq3d__add_value();
b->z = kq3d_asm_value;
}
u8 iterations = world->solver_iterations;
if (iterations == 0) iterations = 1;
u8 it;
for (it = 0; it < iterations; it++)
{
for (i = 0; i < count; i++)
{
KQBody3D* a = &bodies[(u8)i];
if (a->active == 0) continue;
u8 j;
for (j = (u8)(i + 1); j < count; j++)
{
KQBody3D* b = &bodies[(u8)j];
if (b->active == 0) continue;
kq3d__resolve_pair(a, b);
}
}
}
}kq3d_integrate_body
清除一個作用中動態物體的衝擊值,加上世界重力與物體加速度,限制各軸速度,再推進位置。
語法
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body);參數
world指向持有物體陣列與模擬設定的世界。
body指向要修改的物體。本操作未使用的欄位會保持不變。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
last_impact_speed 記錄沿接觸軸的最大接近速度。積分時會清除作用中動態物體的此值;靜態及未啟用物體則保留。break_speed 與 KQ3D_BODY_BROKEN 都不會自動觸發破壞。遊戲自行決定何時破壞物體,並修改 flags/active。
ax/ay/az 會保留,並在下一次積分時再次套用。此函式本身不處理接觸。不修改 NULL、未啟用或靜態物體。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
kq3d_integrate_body(&world,&temp);
result[9]=temp.x; result[10]=temp.y; result[11]=temp.z; result[12]=temp.last_impact_speed;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為 X/Y 正視圖,右側為 X/Z 俯視圖。綠色外框標示初始位置 (24,24,16),紅色方塊表示一個節拍後的 (36,24,24),藍色區域是靜態障礙物。X 速度由 16 變為 −14,Z 速度保持 8。衝擊值為 16,但即使 break_speed=1,旗標仍為零。面板原點位於螢幕 (8,48) 與 (88,48)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics3d.h:67
Reset impact for one active dynamic body, add gravity and persistent body acceleration, clamp velocity per axis and advance position. Static/inactive bodies retain impact state. Null inputs are ignored; no contacts are solved. Use a nonnegative speed limit and avoid overflow before clamping.
kitaqfc/lib/physics3d.c:267
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body)
{
if (world == 0) return;
if (body == 0) return;
if (body->active == 0) return;
if (body->inv_mass_q8 <= 0) return;
body->last_impact_speed = 0;
kq3d_asm_value = body->vx;
kq3d_asm_operand = world->gravity_x;
kq3d__add_value();
kq3d_asm_operand = body->ax;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
body->vx = kq3d_asm_value;
kq3d_asm_value = body->vy;
kq3d_asm_operand = world->gravity_y;
kq3d__add_value();
kq3d_asm_operand = body->ay;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
body->vy = kq3d_asm_value;
kq3d_asm_value = body->vz;
kq3d_asm_operand = world->gravity_z;
kq3d__add_value();
kq3d_asm_operand = body->az;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
body->vz = kq3d_asm_value;
kq3d_asm_value = body->x;
kq3d_asm_operand = body->vx;
kq3d__add_value();
body->x = kq3d_asm_value;
kq3d_asm_value = body->y;
kq3d_asm_operand = body->vy;
kq3d__add_value();
body->y = kq3d_asm_value;
kq3d_asm_value = body->z;
kq3d_asm_operand = body->vz;
kq3d__add_value();
body->z = kq3d_asm_value;
}kq3d_overlap_aabb
檢查兩個以中心表示的盒體是否在三個軸皆嚴格重疊。
語法
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b);參數
a有效的物體指標。此查詢忽略啟用狀態、質量與旗標。
b有效的物體指標。此查詢忽略啟用狀態、質量與旗標。
回傳值
內部重疊時傳回 1,僅相觸或分離時傳回 0。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
result[14]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);
bodies[1].z=32; result[15]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為 X/Y 正視圖,右側為 X/Z 俯視圖。綠色外框標示初始位置 (24,24,16),紅色方塊表示一個節拍後的 (36,24,24),藍色區域是靜態障礙物。X 速度由 16 變為 −14,Z 速度保持 8。衝擊值為 16,但即使 break_speed=1,旗標仍為零。面板原點位於螢幕 (8,48) 與 (88,48)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics3d.h:71
Test strict overlap on all three axes; face-only contact returns false. Valid pointers are required and flags are ignored. Center differences and extent sums must fit the signed 16-bit magnitude calculations.
kitaqfc/lib/physics3d.c:188
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b)
{
s16 dx = kq3d__abs_s16((s16)(b->x - a->x));
s16 dy = kq3d__abs_s16((s16)(b->y - a->y));
s16 dz = kq3d__abs_s16((s16)(b->z - a->z));
s16 sx = (s16)(a->half_x + b->half_x);
s16 sy = (s16)(a->half_y + b->half_y);
s16 sz = (s16)(a->half_z + b->half_z);
if (dx >= sx) return 0;
if (dy >= sy) return 0;
if (dz >= sz) return 0;
return 1;
}kq3d_dot_q8_8
將三個帶正負號乘積各除以 256,分別向零截斷後再相加。
語法
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az);參數
x要乘上對應係數的帶正負號 16 位元分量,可代表位置或速度。
y要乘上對應係數的帶正負號 16 位元分量,可代表位置或速度。
z要乘上對應係數的帶正負號 16 位元分量,可代表位置或速度。
ax此軸的帶正負號位元組係數(-128..127),以 1/256 為比例套用。
ay此軸的帶正負號位元組係數(-128..127),以 1/256 為比例套用。
az此軸的帶正負號位元組係數(-128..127),以 1/256 為比例套用。
回傳值
以 s16 傳回三個量化項目的總和。
使用條件與限制
先將每一項向零截斷,可能與總和只位移一次的結果不同。係數無法儲存 1.0=256。最後的總和不做飽和處理。
除了包含標頭,也必須編譯實作檔。2D 使用 fixed.c 與 physics2d.c;3D 另需加入 physics3d.c。範例使用 MMC3、CHR RAM,以及 PRG RAM $6800–$6FFF 的繪圖儲存空間。此繪圖緩衝區並非物理函式庫本身的必要條件。
使用範例
result[13]=kq3d_dot_q8_8(256,128,0,64,-64,127);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為 X/Y 正視圖,右側為 X/Z 俯視圖。綠色外框標示初始位置 (24,24,16),紅色方塊表示一個節拍後的 (36,24,24),藍色區域是靜態障礙物。X 速度由 16 變為 −14,Z 速度保持 8。衝擊值為 16,但即使 break_speed=1,旗標仍為零。面板原點位於螢幕 (8,48) 與 (88,48)。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasm實作與原始碼
kitaqfc/lib/physics3d.h:75
Sum three signed products, dividing each by 256 (toward zero) before addition. Coefficients are signed bytes scaled by 1/256; the 16-bit sum is not saturated.
kitaqfc/lib/physics3d.c:407
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az)
{
return (s16)(kq2d_scale_q8(x,(s16)ax) + kq2d_scale_q8(y,(s16)ay) + kq2d_scale_q8(z,(s16)az));
}ppu.h — PPU 顯示宣告
僅引入或編譯一次 ppu.c,不要同時使用 runtime.c。呼叫其高、低位址位元組函式前,請用 __ppu_read_status() 重設共用鎖存器。ppu.h 沒有宣告這些函式;其中四個畫面、調色盤及名稱表函式的宣告在此散布套件中沒有實作。這裡展示的函式由 ppu.c 提供,僅包含 ppu.h 無法使用。
nes_ppu_clear_nt
此散布套件沒有實作 nes_ppu_clear_nt(nt_base, tile, attr)。可執行範例分兩步清空名稱表 0:__nametable_rect_nt(0,0,0,32,30,0) 寫入 960 個圖塊格子,__vram_fill(0x23C0,0,64) 清空 64 個打包屬性位元組。兩步都在關閉繪製、位址增量為 1 時進行。邏輯名稱表可能因卡匣鏡像而共用儲存空間。
語法
void nes_ppu_clear_nt(unsigned short nt_base, unsigned char tile, unsigned char attr);參數
nt_base / tile / attr原型將
nt_base宣告為無號 16 位元,tile和attr宣告為無號八位元。沒有函式本體實作這些參數的位址選擇、填滿或驗證。替代方案明確選擇邏輯名稱表 0,並分別提供圖塊和打包屬性值。
回傳值
宣告的回傳型別為 void。沒有可連結的實作,因此此名稱沒有可執行的返回行為。
使用條件與限制
範例展示的是已經實作的替代方案,不是成功呼叫這些宣告。驗證包含每個缺失名稱觸發未解析符號的預期建置結果,以及對替代方案的獨立模擬器檢查。若要呼叫宣告中的名稱,請自行提供相符實作;僅包含另一個標頭檔不會加入函式本體。
使用範例
nes_ppu_clear_nt(0x2000,0,0); // All 960 tiles and 64 packed attribute bytes.
// Nametable reads are buffered: discard one read, then inspect all 1024 bytes.
__ppu_addr(0x2000);discarded_read=sample_ppudata;
for(i=0;i<1024;i++)if(sample_ppudata!=0)failures=1;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
可執行替代方案先關閉繪製,設定調色盤並清空圖塊和屬性,再繪製此測試影像。藍色實心圖塊、左半直條與三角形的重複圖案從 (0,16) 開始,綠色實心區域從 (0,96) 開始。每塊區域為 256×64 像素,但只傳輸 255 個圖塊位元組,因此最後的 8×8 格子 (248,72) 和 (248,152) 保持黑色。y=208 處的紅色圖形分別是 x=16 的 8×8 正方形、x=224 的左半 4×8 直條、x=240 的八行三角形。FAILED CHECKS 為 0。獨立狀態測試還確認兩個控制暫存器、32 位元組調色盤傳輸,以及名稱表全部 1,024 位元組的清空。直接呼叫四個宣告時,預期結果是連結失敗。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_implemented.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_implemented.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/ppu.h:14
Fill 960 tiles and 64 packed attributes; preserve PPUCTRL. Accept exactly $2000/$2400/$2800/$2C00; invalid bases are ignored.
kitaqfc/lib/ppu.c:60
void nes_ppu_clear_nt(unsigned short nt_base, unsigned char tile, unsigned char attr)
{
unsigned char table;
unsigned char saved_ctrl;
if (nt_base != 0x2000 && nt_base != 0x2400 && nt_base != 0x2800 && nt_base != 0x2C00) return;
table = (unsigned char)((nt_base - 0x2000) >> 10);
saved_ctrl=__ppu_ctrl_get();
__ppu_ctrl_set((u8)(saved_ctrl & 0xFB));
__nametable_rect_nt(table,0,0,32,30,tile);
__vram_fill((u16)(nt_base+0x3C0),attr,64);
__ppu_ctrl_set(saved_ctrl);
}nes_ppu_fill
用 hi 和 lo 設定位址,再將 value 向 PPUDATA 寫入 count 次。此 ppu.c 函式使用八位元計數立即填滿,呼叫端須先重設鎖存器。不會依行或矩形邊界裁切。
語法
void nes_ppu_fill(unsigned char hi, unsigned char lo, unsigned char value, unsigned char count);參數
hi / lohi和lo是 PPU 位址的高、低位元組,例如0x23, 0x42表示0x2342。它們是位址位元組,不是圖塊座標。適用正常的 PPU 位址遮罩與鏡像規則。value重複寫入0至255的單一位元組。顯示意義取決於目標是圖塊索引、像素位元平面還是其他位元組結構。
count無號八位元的位元組數,範圍為
0..255。0 只設定位址,不寫入資料。即使為 0,函式也不會重設共用鎖存器,請在呼叫前準備好鎖存器。
回傳值
無(void)。
使用條件與限制
僅引入或編譯一次 ppu.c,不要同時使用 runtime.c。呼叫其高、低位址位元組函式前,請用 __ppu_read_status() 重設共用鎖存器。ppu.h 沒有宣告這些函式;其中四個畫面、調色盤及名稱表函式的宣告在此散布套件中沒有實作。這裡展示的函式由 ppu.c 提供,僅包含 ppu.h 無法使用。
直接存取 PPU 時,必須關閉繪製,或確保整個操作位於安全的 VBlank 時間內。這些函式不等待、不排入佇列、不阻擋 NMI,也不還原捲動。呼叫期間應防止中斷改變共用鎖存器或位址。PPUCTRL 第 2 位元決定每個資料位元組使目的位址增加 1 還是 32。鏡像和位址繞回由 PPU 處理;CHR-ROM 不可寫入。存取結束後、開始繪製前,請設定所需的捲動狀態。
使用範例
__ppu_read_status();nes_ppu_fill(0x21,0x80,1,255);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
獨立的高、低位址範例用於學習明確準備鎖存器和八位元傳輸計數。藍色與綠色區域各使用 255 位元組,因此最後一個 8×8 格子 (248,72) 和 (248,152) 保持黑色。紅色位址設定及零長度標記的位置和形狀與執行階段範例相同。FAILED CHECKS 為 0;此程式不測試執行階段等待函式。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_address_pair.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_address_pair.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/ppu.c:27
Set the address and issue count identical PPUDATA writes without waiting for VBlank.
kitaqfc/lib/ppu.c:27
void nes_ppu_fill(unsigned char hi, unsigned char lo, unsigned char value, unsigned char count)
{
unsigned char i;
nes_ppu_seek_bytes(hi, lo);
for (i = 0; i != count; ++i)
kq_ppu_data_register = value;
}nes_ppu_load_palette
nes_ppu_load_palette(pal32) 只有宣告,沒有對應的調色盤傳輸實作。可執行範例在關閉繪製、位址增量為 1 時,使用 __palette_bg_load 傳輸 16 個背景位元組,使用 __palette_sp_load 傳輸 16 個精靈位元組。硬體調色盤位址別名仍然有效,寫入精靈調色盤也可能改變背景色彩項目。
語法
void nes_ppu_load_palette(unsigned char* pal32);參數
pal32pal32宣告為無號位元組指標,名稱並不代表已經實作了 32 位元組傳輸。使用可執行替代方案時,為每個調色盤內建函式提供 16 個可讀位元組,並在返回前保持來源記憶體庫映射。
回傳值
宣告的回傳型別為 void。沒有可連結的實作,因此此名稱沒有可執行的返回行為。
使用條件與限制
範例展示的是已經實作的替代方案,不是成功呼叫這些宣告。驗證包含每個缺失名稱觸發未解析符號的預期建置結果,以及對替代方案的獨立模擬器檢查。若要呼叫宣告中的名稱,請自行提供相符實作;僅包含另一個標頭檔不會加入函式本體。
使用範例
nes_ppu_load_palette(stream_palette); // Sixteen BG bytes followed by sixteen sprite bytes.
// Palette reads are immediate; both halves use the same original sample palette.
__ppu_addr(0x3F00);
for(i=0;i<32;i++)if(sample_ppudata!=stream_palette[(u8)(i&15)])failures=1;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
可執行替代方案先關閉繪製,設定調色盤並清空圖塊和屬性,再繪製此測試影像。藍色實心圖塊、左半直條與三角形的重複圖案從 (0,16) 開始,綠色實心區域從 (0,96) 開始。每塊區域為 256×64 像素,但只傳輸 255 個圖塊位元組,因此最後的 8×8 格子 (248,72) 和 (248,152) 保持黑色。y=208 處的紅色圖形分別是 x=16 的 8×8 正方形、x=224 的左半 4×8 直條、x=240 的八行三角形。FAILED CHECKS 為 0。獨立狀態測試還確認兩個控制暫存器、32 位元組調色盤傳輸,以及名稱表全部 1,024 位元組的清空。直接呼叫四個宣告時,預期結果是連結失敗。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_implemented.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_implemented.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/ppu.h:11
Copy 32 bytes into $3F00..$3F1F with increment one; preserve PPUCTRL. Null is ignored. Hardware palette mirrors apply; source bank must stay mapped.
kitaqfc/lib/ppu.c:48
void nes_ppu_load_palette(unsigned char* pal32)
{
u8 saved_ctrl;
if (pal32 == 0) return;
saved_ctrl=__ppu_ctrl_get();
__ppu_ctrl_set((u8)(saved_ctrl & 0xFB));
__palette_bg_load(pal32);
__palette_sp_load(pal32 + 16);
__ppu_ctrl_set(saved_ctrl);
}nes_ppu_screen_off
nes_ppu_screen_off 在 ppu.h 中有宣告,但此散布套件沒有函式本體,直接呼叫無法連結。可執行範例使用 __ppu_off() 停止繪製,將 PPUMASK 及其軟體儲存值設為零。它不會停用 NMI;範例為批次準備畫面而另外向 PPUCTRL 寫入零。
語法
void nes_ppu_screen_off(void);回傳值
宣告的回傳型別為 void。沒有可連結的實作,因此此名稱沒有可執行的返回行為。
使用條件與限制
範例展示的是已經實作的替代方案,不是成功呼叫這些宣告。驗證包含每個缺失名稱觸發未解析符號的預期建置結果,以及對替代方案的獨立模擬器檢查。若要呼叫宣告中的名稱,請自行提供相符實作;僅包含另一個標頭檔不會加入函式本體。
使用範例
nes_ppu_screen_off();__ppu_ctrl_set(0); // Disable NMI during this bulk preparation.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
可執行替代方案先關閉繪製,設定調色盤並清空圖塊和屬性,再繪製此測試影像。藍色實心圖塊、左半直條與三角形的重複圖案從 (0,16) 開始,綠色實心區域從 (0,96) 開始。每塊區域為 256×64 像素,但只傳輸 255 個圖塊位元組,因此最後的 8×8 格子 (248,72) 和 (248,152) 保持黑色。y=208 處的紅色圖形分別是 x=16 的 8×8 正方形、x=224 的左半 4×8 直條、x=240 的八行三角形。FAILED CHECKS 為 0。獨立狀態測試還確認兩個控制暫存器、32 位元組調色盤傳輸,以及名稱表全部 1,024 位元組的清空。直接呼叫四個宣告時,預期結果是連結失敗。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_implemented.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_implemented.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/ppu.h:6
Link ppu.c. Bulk palette/nametable transfers require rendering to be disabled. Disable background and sprite rendering, preserving other PPUMASK bits.
kitaqfc/lib/ppu.c:36
void nes_ppu_screen_off(void) { __ppu_mask_set((u8)(__ppu_mask_get() & 0xE7)); }nes_ppu_screen_on
nes_ppu_screen_on(ctrl, mask) 只是沒有實作的宣告,呼叫此名稱無法啟用畫面。可執行範例先設定捲動,再呼叫 __ppu_ctrl_set(0x80) 和 __ppu_mask_set(0x0A)。這會啟用 NMI 與背景繪製,包括最左側八個像素,但不啟用精靈繪製。請依遊戲需要選擇暫存器值。
語法
void nes_ppu_screen_on(unsigned char ctrl, unsigned char mask);參數
ctrl / mask宣告中的
ctrl和mask為無號八位元型別,沒有函式本體定義其執行行為。可執行替代方案透過兩個內建函式寫入所需的 PPUCTRL 和 PPUMASK 值。
回傳值
宣告的回傳型別為 void。沒有可連結的實作,因此此名稱沒有可執行的返回行為。
使用條件與限制
範例展示的是已經實作的替代方案,不是成功呼叫這些宣告。驗證包含每個缺失名稱觸發未解析符號的預期建置結果,以及對替代方案的獨立模擬器檢查。若要呼叫宣告中的名稱,請自行提供相符實作;僅包含另一個標頭檔不會加入函式本體。
使用範例
nes_ppu_screen_on(0x80,0x0A);
// NMI and background rendering are now enabled, with left-edge background visible.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
可執行替代方案先關閉繪製,設定調色盤並清空圖塊和屬性,再繪製此測試影像。藍色實心圖塊、左半直條與三角形的重複圖案從 (0,16) 開始,綠色實心區域從 (0,96) 開始。每塊區域為 256×64 像素,但只傳輸 255 個圖塊位元組,因此最後的 8×8 格子 (248,72) 和 (248,152) 保持黑色。y=208 處的紅色圖形分別是 x=16 的 8×8 正方形、x=224 的左半 4×8 直條、x=240 的八行三角形。FAILED CHECKS 為 0。獨立狀態測試還確認兩個控制暫存器、32 位元組調色盤傳輸,以及名稱表全部 1,024 位元組的清空。直接呼叫四個宣告時,預期結果是連結失敗。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_implemented.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_implemented.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/ppu.h:8
Set scroll to (0,0), then apply the requested PPUCTRL and PPUMASK values.
kitaqfc/lib/ppu.c:39
void nes_ppu_screen_on(unsigned char ctrl, unsigned char mask)
{
__ppu_read_status();
__scroll_set(0,0);
__ppu_ctrl_set(ctrl);
__ppu_mask_set(mask);
}nes_ppu_seek_bytes
先讀取 PPUSTATUS 重設共用的 PPU 位址鎖存器,再以獨立的 hi 與 lo 位元組設定位址。遊戲已將位址分成兩個位元組儲存時,適合使用此形式。
語法
void nes_ppu_seek_bytes(unsigned char hi, unsigned char lo);參數
hi / lohi和lo是 PPU 位址的高、低位元組,例如0x23, 0x42表示0x2342。它們是位址位元組,不是圖塊座標。適用正常的 PPU 位址遮罩與鏡像規則。
回傳值
無(void)。
使用條件與限制
僅引入或編譯一次 ppu.c,不要同時使用 runtime.c。呼叫其高、低位址位元組函式前,請用 __ppu_read_status() 重設共用鎖存器。ppu.h 沒有宣告這些函式;其中四個畫面、調色盤及名稱表函式的宣告在此散布套件中沒有實作。這裡展示的函式由 ppu.c 提供,僅包含 ppu.h 無法使用。
直接存取 PPU 時,必須關閉繪製,或確保整個操作位於安全的 VBlank 時間內。這些函式不等待、不排入佇列、不阻擋 NMI,也不還原捲動。呼叫期間應防止中斷改變共用鎖存器或位址。PPUCTRL 第 2 位元決定每個資料位元組使目的位址增加 1 還是 32。鏡像和位址繞回由 PPU 處理;CHR-ROM 不可寫入。存取結束後、開始繪製前,請設定所需的捲動狀態。
使用範例
nes_ppu_seek_bytes(0x23,0x42);
PPUDATA=1; // Red 8x8 marker at pixel (16,208).這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
獨立的高、低位址範例用於學習明確準備鎖存器和八位元傳輸計數。藍色與綠色區域各使用 255 位元組,因此最後一個 8×8 格子 (248,72) 和 (248,152) 保持黑色。紅色位址設定及零長度標記的位置和形狀與執行階段範例相同。FAILED CHECKS 為 0;此程式不測試執行階段等待函式。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_address_pair.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_address_pair.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/ppu.c:8
Reset the shared scroll/address latch before writing the address byte pair.
kitaqfc/lib/ppu.c:8
void nes_ppu_seek_bytes(unsigned char hi, unsigned char lo)
{
__ppu_read_status();
kq_ppu_addr_register = hi;
kq_ppu_addr_register = lo;
}nes_ppu_write_bytes
用 hi 和 lo 設定位址後,將來源中連續的 count 位元組直接寫入 PPUDATA。此 ppu.c 函式接受八位元計數,位址鎖存器由呼叫端重設。不使用佇列,返回前完成傳輸。
語法
void nes_ppu_write_bytes(unsigned char hi, unsigned char lo, const unsigned char* src, unsigned char count);參數
hi / lohi和lo是 PPU 位址的高、低位元組,例如0x23, 0x42表示0x2342。它們是位址位元組,不是圖塊座標。適用正常的 PPU 位址遮罩與鏡像規則。srcCPU 指標,必須能讀取至少指定數量的位元組。同步傳輸返回前,請保持來源映射與內容穩定。函式不會切換記憶體庫、在佇列中保留指標或檢查來源長度;計數為 0 時不會解參考指標。
count無號八位元的位元組數,範圍為
0..255。0 只設定位址,不寫入資料。即使為 0,函式也不會重設共用鎖存器,請在呼叫前準備好鎖存器。
回傳值
無(void)。
使用條件與限制
僅引入或編譯一次 ppu.c,不要同時使用 runtime.c。呼叫其高、低位址位元組函式前,請用 __ppu_read_status() 重設共用鎖存器。ppu.h 沒有宣告這些函式;其中四個畫面、調色盤及名稱表函式的宣告在此散布套件中沒有實作。這裡展示的函式由 ppu.c 提供,僅包含 ppu.h 無法使用。
直接存取 PPU 時,必須關閉繪製,或確保整個操作位於安全的 VBlank 時間內。這些函式不等待、不排入佇列、不阻擋 NMI,也不還原捲動。呼叫期間應防止中斷改變共用鎖存器或位址。PPUCTRL 第 2 位元決定每個資料位元組使目的位址增加 1 還是 32。鏡像和位址繞回由 PPU 處理;CHR-ROM 不可寫入。存取結束後、開始繪製前,請設定所需的捲動狀態。
使用範例
__ppu_read_status();nes_ppu_write_bytes(0x20,0x40,source_bytes,255);
source_bytes[0]=3; // The completed transfer retains tile 1.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
獨立的高、低位址範例用於學習明確準備鎖存器和八位元傳輸計數。藍色與綠色區域各使用 255 位元組,因此最後一個 8×8 格子 (248,72) 和 (248,152) 保持黑色。紅色位址設定及零長度標記的位置和形狀與執行階段範例相同。FAILED CHECKS 為 0;此程式不測試執行階段等待函式。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_address_pair.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_address_pair.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/ppu.c:18
Set the address and write count bytes directly through PPUDATA. The current PPUCTRL increment mode determines how the destination advances. count is 0..255; zero still changes PPU address/latch state. No bank switch or payload copy is performed.
kitaqfc/lib/ppu.c:18
void nes_ppu_write_bytes(unsigned char hi, unsigned char lo, const unsigned char* src, unsigned char count)
{
unsigned char i;
nes_ppu_seek_bytes(hi, lo);
for (i = 0; i != count; ++i)
kq_ppu_data_register = src[i];
}runtime.h — NMI、OAM 與 PPU 傳輸用 C 輔助函式
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
這是 runtime.c 在 CPU 位址 0x0300–0x03BF 使用的獨立 192 位元組佇列。資料記錄占 3+len 位元組,填滿記錄占四位元組。nes_vram_queue_used 表示編碼後的記錄位元組數,不是待執行的 PPU 寫入次數或剩餘 VRAM。__vramq_* 內建佇列使用不同格式,這些函式不會清空、查詢或執行它。
請把建立批次和執行批次分成兩個階段;這裡沒有鎖定或雙緩衝。要確保準備過程穩定,應在附加記錄時停用 NMI,接著在關閉繪製時執行,或準備好能在 VBlank 內完成的批次後再啟用 NMI。runtime.c 會從 __nes_nmi 自動執行非空佇列,不需要提交呼叫。執行過程不設時間預算、不拆分工作,也不還原捲動狀態。佇列放得下並不表示 VBlank 時間足夠。
nes_ppu_seek
設定後續 PPUDATA 存取使用的 PPU 位址。runtime.c 的 nes_ppu_seek(ppu_addr) 先讀取 PPUSTATUS,重設共用寫入鎖存器,再寫入位址高、低位元組。ppu.c 另行提供 nes_ppu_seek(hi, lo),不會重設鎖存器。兩者同名但參數與行為不同,請選擇一種實作,不要同時連結。
語法
void nes_ppu_seek(unsigned short ppu_addr);參數
ppu_addrPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。
回傳值
無(void)。
使用條件與限制
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
直接存取 PPU 時,必須關閉繪製,或確保整個操作位於安全的 VBlank 時間內。這些函式不等待、不排入佇列、不阻擋 NMI,也不還原捲動。呼叫期間應防止中斷改變共用鎖存器或位址。PPUCTRL 第 2 位元決定每個資料位元組使目的位址增加 1 還是 32。鏡像和位址繞回由 PPU 處理;CHR-ROM 不可寫入。存取結束後、開始繪製前,請設定所需的捲動狀態。
使用範例
PPUADDR=0x21; // Deliberately leave the shared address latch half-written.
nes_ppu_seek(0x2342); // This runtime function resets the latch itself.
PPUDATA=1; // Red 8x8 marker at pixel (16,208).這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
執行階段範例用於學習直接傳輸和兩種等待方式。(0,16) 顯示藍色實心圖塊、左半直條與三角形的重複圖案;(0,96) 顯示綠色實心區域。每塊區域為 256×64 像素,來自 256 個圖塊位元組。修改來源後,第一個藍色圖塊仍為實心。y=208 的 x=16、224、240 處分別用紅色 8×8 正方形、左半 4×8 直條和八行三角形表示位址設定、零長度寫入和零長度填滿。兩項等待指示均為 1,FAILED CHECKS 為 0。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/runtime.h:28
Reset the PPU address latch with a status read, then write the high/low address bytes.
kitaqfc/lib/runtime.c:207
void nes_ppu_seek(unsigned short ppu_addr)
{
unsigned char latch;
latch = PPUSTATUS;
PPUADDR = (unsigned char)(ppu_addr >> 8);
PPUADDR = (unsigned char)ppu_addr;
latch = latch;
}nes_ppu_stream_fill
設定 ppu_addr 後,將同一個位元組值 value 向 PPUDATA 寫入 len 次。這是返回前完成的直接填滿操作,不會解讀圖塊尺寸、屬性或矩形邊界。
語法
void nes_ppu_stream_fill(unsigned short ppu_addr, unsigned char value, unsigned short len);參數
ppu_addrPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。value重複寫入0至255的單一位元組。顯示意義取決於目標是圖塊索引、像素位元平面還是其他位元組結構。
len位元組數,範圍為
0..65535,使用無號 16 位元值。即使為 0,也會設定 PPU 位址並重設鎖存器,但不寫入 PPUDATA。沒有目的地容量檢查或分段傳輸;較大的計數可能繞回 PPU 位址空間。
回傳值
無(void)。
使用條件與限制
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
直接存取 PPU 時,必須關閉繪製,或確保整個操作位於安全的 VBlank 時間內。這些函式不等待、不排入佇列、不阻擋 NMI,也不還原捲動。呼叫期間應防止中斷改變共用鎖存器或位址。PPUCTRL 第 2 位元決定每個資料位元組使目的位址增加 1 還是 32。鏡像和位址繞回由 PPU 處理;CHR-ROM 不可寫入。存取結束後、開始繪製前,請設定所需的捲動狀態。
使用範例
nes_ppu_stream_fill(0x2180,1,256); // Eight complete rows of solid green tiles.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
執行階段範例用於學習直接傳輸和兩種等待方式。(0,16) 顯示藍色實心圖塊、左半直條與三角形的重複圖案;(0,96) 顯示綠色實心區域。每塊區域為 256×64 像素,來自 256 個圖塊位元組。修改來源後,第一個藍色圖塊仍為實心。y=208 的 x=16、224、240 處分別用紅色 8×8 正方形、左半 4×8 直條和八行三角形表示位址設定、零長度寫入和零長度填滿。兩項等待指示均為 1,FAILED CHECKS 為 0。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/runtime.h:34
Write value repeatedly through PPUDATA, using the current PPU address increment mode. This routine does not wait for VBlank or disable rendering.
kitaqfc/lib/runtime.c:232
void nes_ppu_stream_fill(unsigned short ppu_addr, unsigned char value, unsigned short len)
{
nes_ppu_seek(ppu_addr);
while (len != 0)
{
PPUDATA = value;
len = len - 1;
}
}nes_ppu_stream_write
從 ppu_addr 開始,將來源中連續的 len 位元組直接寫入 PPUDATA。函式先設定一次位址,每次寫入後推進內部來源指標。返回前傳輸已經完成,之後修改來源不會改變 VRAM;呼叫端的指標變數也不會改變。
語法
void nes_ppu_stream_write(unsigned short ppu_addr, unsigned char* src, unsigned short len);參數
ppu_addrPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。srcCPU 指標,必須能讀取至少指定數量的位元組。同步傳輸返回前,請保持來源映射與內容穩定。函式不會切換記憶體庫、在佇列中保留指標或檢查來源長度;計數為 0 時不會解參考指標。
len位元組數,範圍為
0..65535,使用無號 16 位元值。即使為 0,也會設定 PPU 位址並重設鎖存器,但不寫入 PPUDATA。沒有目的地容量檢查或分段傳輸;較大的計數可能繞回 PPU 位址空間。
回傳值
無(void)。
使用條件與限制
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
直接存取 PPU 時,必須關閉繪製,或確保整個操作位於安全的 VBlank 時間內。這些函式不等待、不排入佇列、不阻擋 NMI,也不還原捲動。呼叫期間應防止中斷改變共用鎖存器或位址。PPUCTRL 第 2 位元決定每個資料位元組使目的位址增加 1 還是 32。鏡像和位址繞回由 PPU 處理;CHR-ROM 不可寫入。存取結束後、開始繪製前,請設定所需的捲動狀態。
使用範例
// Rendering/NMI are off; PPUCTRL increment is 1. Transfer 256 bytes now.
nes_ppu_stream_write(0x2040,source_bytes,256);
source_bytes[0]=3; // VRAM already holds tile 1 at the first blue cell.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
執行階段範例用於學習直接傳輸和兩種等待方式。(0,16) 顯示藍色實心圖塊、左半直條與三角形的重複圖案;(0,96) 顯示綠色實心區域。每塊區域為 256×64 像素,來自 256 個圖塊位元組。修改來源後,第一個藍色圖塊仍為實心。y=208 的 x=16、224、240 處分別用紅色 8×8 正方形、左半 4×8 直條和八行三角形表示位址設定、零長度寫入和零長度填滿。兩項等待指示均為 1,FAILED CHECKS 為 0。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/runtime.h:31
Write len source bytes directly through PPUDATA. Call only during an appropriate PPU access period; the address increment mode comes from the current PPUCTRL.
kitaqfc/lib/runtime.c:219
void nes_ppu_stream_write(unsigned short ppu_addr, unsigned char* src, unsigned short len)
{
nes_ppu_seek(ppu_addr);
while (len != 0)
{
PPUDATA = *src;
src = src + 1;
len = len - 1;
}
}nes_vblank_wait
輪詢 PPUSTATUS 的第 7 位,先消耗已設立的通知,再等待新的 VBlank 通知。NMI 停用時也能運作,但不會執行佇列或更新執行階段 NMI 計數器。每次讀取狀態都會清除 VBlank 旗標,並重設捲動與位址共用的寫入鎖存器。狀態讀取可能影響 NMI 時序,請將此輪詢方式與 NMI 驅動的排程分開使用。它沒有逾時,也不傳輸資料或還原捲動。
語法
void nes_vblank_wait(void);回傳值
無(void)。
使用條件與限制
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
使用範例
// With NMI disabled, poll a new PPU VBlank flag. No queued work is flushed.
nes_vblank_wait();blank_seen=1;
if((PPUSTATUS&0x80)!=0)failures++; // The wait's status read cleared the flag.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
執行階段範例用於學習直接傳輸和兩種等待方式。(0,16) 顯示藍色實心圖塊、左半直條與三角形的重複圖案;(0,96) 顯示綠色實心區域。每塊區域為 256×64 像素,來自 256 個圖塊位元組。修改來源後,第一個藍色圖塊仍為實心。y=208 的 x=16、224、240 處分別用紅色 8×8 正方形、左半 4×8 直條和八行三角形表示位址設定、零長度寫入和零長度填滿。兩項等待指示均為 1,FAILED CHECKS 為 0。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/runtime.h:26
Wait for the current VBlank to end, then for the next one to begin. Each PPUSTATUS read has hardware side effects, including clearing the VBlank flag.
kitaqfc/lib/runtime.c:196
void nes_vblank_wait(void)
{
while ((PPUSTATUS & 0x80) != 0)
{
}
while ((PPUSTATUS & 0x80) == 0)
{
}
}nes_vram_queue_clear
捨棄 C 執行階段佇列中的所有待處理記錄,將 nes_vram_queue_used 和 nes_vram_queue_overflow 都歸零。不寫入 PPU,也不清除緩衝區內原有的資料位元組。編譯器的內建佇列不受影響。
語法
void nes_vram_queue_clear(void);回傳值
無(void)。
使用條件與限制
這是 runtime.c 在 CPU 位址 0x0300–0x03BF 使用的獨立 192 位元組佇列。資料記錄占 3+len 位元組,填滿記錄占四位元組。nes_vram_queue_used 表示編碼後的記錄位元組數,不是待執行的 PPU 寫入次數或剩餘 VRAM。__vramq_* 內建佇列使用不同格式,這些函式不會清空、查詢或執行它。
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
請把建立批次和執行批次分成兩個階段;這裡沒有鎖定或雙緩衝。要確保準備過程穩定,應在附加記錄時停用 NMI,接著在關閉繪製時執行,或準備好能在 VBlank 內完成的批次後再啟用 NMI。runtime.c 會從 __nes_nmi 自動執行非空佇列,不需要提交呼叫。執行過程不設時間預算、不拆分工作,也不還原捲動狀態。佇列放得下並不表示 VBlank 時間足夠。
使用範例
nes_vram_queue_clear(); // Discard all records AND clear the overflow latch.
if(nes_vram_queue_used!=0 || nes_vram_queue_overflow!=0)failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例先填滿全部 192 個佇列位元組,並刻意讓下一筆記錄被拒絕。清空該批次後,確認長度 128 被拒絕,再用五筆記錄占用 145 位元組,安排 255 次 PPU 寫入。應顯示 CAPACITY 192、ENCODED BYTES 145、AFTER FLUSH 000、REJECTED LENGTH 001、OVERFLOW SEEN 001、FAILED CHECKS 000。拒絕相關數字保存的是程式先前步驟中觀察到的結果,不代表最終的旗標狀態。
藍色複製圖塊從 (0,16) 開始,綠色填滿圖塊從 (0,64) 開始。每區共 127 個圖塊:三整列,加上第四列的 31 個,最後一個 8×8 儲存格保持黑色。藍色序列重複實心、半寬、三角圖塊;即使來源資料改變,第一個仍為實心。在 y=112,x=16 的紅色方塊在零長度記錄後仍保留,x=224 的紅色半寬圖塊驗證 NMI 自動執行,被取消的 x=248 儲存格保持黑色。驗證比對 18,432 個像素,並確認畫面繪製期間沒有 VRAM 寫入。尚未在實體硬體上驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_queue.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_queue.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/runtime.h:40
Discard pending VRAM commands and clear the overflow latch; no PPU writes occur.
kitaqfc/lib/runtime.c:31
void nes_vram_queue_clear(void)
{
nes_vram_queue_used = 0;
nes_vram_queue_overflow = 0;
}nes_vram_queue_nmi_flush
依序執行 C 執行階段佇列中的全部待處理記錄,不需要提交旗標。為每筆記錄設定 PPU 位址,再傳送已保存的資料或重複寫入填滿值。完成後將 nes_vram_queue_used 歸零,但保留溢位旗標。空佇列不會存取 PPU。
語法
void nes_vram_queue_nmi_flush(void);回傳值
無(void)。
使用條件與限制
這是 runtime.c 在 CPU 位址 0x0300–0x03BF 使用的獨立 192 位元組佇列。資料記錄占 3+len 位元組,填滿記錄占四位元組。nes_vram_queue_used 表示編碼後的記錄位元組數,不是待執行的 PPU 寫入次數或剩餘 VRAM。__vramq_* 內建佇列使用不同格式,這些函式不會清空、查詢或執行它。
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
請把建立批次和執行批次分成兩個階段;這裡沒有鎖定或雙緩衝。要確保準備過程穩定,應在附加記錄時停用 NMI,接著在關閉繪製時執行,或準備好能在 VBlank 內完成的批次後再啟用 NMI。runtime.c 會從 __nes_nmi 自動執行非空佇列,不需要提交呼叫。執行過程不設時間預算、不拆分工作,也不還原捲動狀態。佇列放得下並不表示 VBlank 時間足夠。
PPU位元組位址(0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。
使用範例
// Rendering and NMI are disabled; PPUCTRL selects increment 1.
nes_vram_queue_nmi_flush(); // No commit flag: consume all queued records now.
after_flush=nes_vram_queue_used;
if(after_flush!=0)failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例先填滿全部 192 個佇列位元組,並刻意讓下一筆記錄被拒絕。清空該批次後,確認長度 128 被拒絕,再用五筆記錄占用 145 位元組,安排 255 次 PPU 寫入。應顯示 CAPACITY 192、ENCODED BYTES 145、AFTER FLUSH 000、REJECTED LENGTH 001、OVERFLOW SEEN 001、FAILED CHECKS 000。拒絕相關數字保存的是程式先前步驟中觀察到的結果,不代表最終的旗標狀態。
藍色複製圖塊從 (0,16) 開始,綠色填滿圖塊從 (0,64) 開始。每區共 127 個圖塊:三整列,加上第四列的 31 個,最後一個 8×8 儲存格保持黑色。藍色序列重複實心、半寬、三角圖塊;即使來源資料改變,第一個仍為實心。在 y=112,x=16 的紅色方塊在零長度記錄後仍保留,x=224 的紅色半寬圖塊驗證 NMI 自動執行,被取消的 x=248 儲存格保持黑色。驗證比對 18,432 個像素,並確認畫面繪製期間沒有 VRAM 寫入。尚未在實體硬體上驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_queue.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_queue.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/runtime.h:51
Consume complete records in order during a safe PPU access period. Reading PPUSTATUS resets the shared address latch before each address pair. The caller is responsible for ensuring the transfer fits its NMI/VBlank time budget.
kitaqfc/lib/runtime.c:127
void nes_vram_queue_nmi_flush(void)
{
unsigned char i;
unsigned char cmd;
unsigned char len;
unsigned char data_index;
unsigned char latch;
i = 0;
while (i != nes_vram_queue_used)
{
latch = PPUSTATUS;
PPUADDR = nes_vram_queue_data[i];
PPUADDR = nes_vram_queue_data[(unsigned char)(i + 1)];
cmd = nes_vram_queue_data[(unsigned char)(i + 2)];
if ((cmd & 0x80) != 0)
{
len = (unsigned char)(cmd & 0x7F);
data_index = nes_vram_queue_data[(unsigned char)(i + 3)];
while (len != 0)
{
PPUDATA = data_index;
len = len - 1;
}
i = (unsigned char)(i + 4);
}
else
{
len = cmd;
data_index = (unsigned char)(i + 3);
while (len != 0)
{
PPUDATA = nes_vram_queue_data[data_index];
data_index = data_index + 1;
len = len - 1;
}
i = data_index;
}
latch = latch;
}
nes_vram_queue_used = 0;
}nes_vram_queue_try_fill
向 C 執行階段佇列附加四位元組填滿記錄。執行時向 PPUDATA 寫入 value,共 len 次。位元組值會立即保存在記錄中,之後修改呼叫端變數不會影響填滿結果。它重複的是單一位元組,而不是圖塊圖案。
語法
unsigned char nes_vram_queue_try_fill(unsigned short ppu_addr, unsigned char value, unsigned char len);參數
ppu_addrPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。value重複寫入0至255的單一位元組。顯示意義取決於目標是圖塊索引、像素位元平面還是其他位元組結構。
len寫入 PPU 的位元組數,範圍為 0–127。記錄使用長度位元組的位元 7 區分填滿,因此拒絕 128–255。零長度 write 仍占三個佇列位元組,零長度 fill 占四個。兩者在執行時都會設定 PPU 位址,但不寫入 PPUDATA。
回傳值
完整記錄入列成功回傳 1;長度無效或空間不足回傳 0。拒絕時將 nes_vram_queue_overflow 設為 1,既有記錄和已用長度保持不變。錯誤旗標會保留到清除為止,但不會阻止後續放得下的記錄。請檢查每次呼叫的回傳值。
使用條件與限制
這是 runtime.c 在 CPU 位址 0x0300–0x03BF 使用的獨立 192 位元組佇列。資料記錄占 3+len 位元組,填滿記錄占四位元組。nes_vram_queue_used 表示編碼後的記錄位元組數,不是待執行的 PPU 寫入次數或剩餘 VRAM。__vramq_* 內建佇列使用不同格式,這些函式不會清空、查詢或執行它。
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
請把建立批次和執行批次分成兩個階段;這裡沒有鎖定或雙緩衝。要確保準備過程穩定,應在附加記錄時停用 NMI,接著在關閉繪製時執行,或準備好能在 VBlank 內完成的批次後再啟用 NMI。runtime.c 會從 __nes_nmi 自動執行非空佇列,不需要提交呼叫。執行過程不設時間預算、不拆分工作,也不還原捲動狀態。佇列放得下並不表示 VBlank 時間足夠。
使用範例
if(nes_vram_queue_try_fill(0x2100,fill_value,127)!=1)failures++;
fill_value=3; // The queued fill remains the solid tile 1.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例先填滿全部 192 個佇列位元組,並刻意讓下一筆記錄被拒絕。清空該批次後,確認長度 128 被拒絕,再用五筆記錄占用 145 位元組,安排 255 次 PPU 寫入。應顯示 CAPACITY 192、ENCODED BYTES 145、AFTER FLUSH 000、REJECTED LENGTH 001、OVERFLOW SEEN 001、FAILED CHECKS 000。拒絕相關數字保存的是程式先前步驟中觀察到的結果,不代表最終的旗標狀態。
藍色複製圖塊從 (0,16) 開始,綠色填滿圖塊從 (0,64) 開始。每區共 127 個圖塊:三整列,加上第四列的 31 個,最後一個 8×8 儲存格保持黑色。藍色序列重複實心、半寬、三角圖塊;即使來源資料改變,第一個仍為實心。在 y=112,x=16 的紅色方塊在零長度記錄後仍保留,x=224 的紅色半寬圖塊驗證 NMI 自動執行,被取消的 x=248 儲存格保持黑色。驗證比對 18,432 個像素,並確認畫面繪製期間沒有 VRAM 寫入。尚未在實體硬體上驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_queue.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_queue.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/runtime.h:47
Queue a four-byte fill record: address high/low, length with bit 7 set, value. Reject lengths above 127 and latch overflow on any capacity/format failure.
kitaqfc/lib/runtime.c:90
unsigned char nes_vram_queue_try_fill(unsigned short ppu_addr, unsigned char value, unsigned char len)
{
unsigned char used;
unsigned char need;
used = nes_vram_queue_used;
need = 4;
if ((unsigned char)(used + need) < used)
{
nes_vram_queue_overflow = 1;
return 0;
}
if ((unsigned char)(used + need) > 192)
{
nes_vram_queue_overflow = 1;
return 0;
}
if ((len & 0x80) != 0)
{
nes_vram_queue_overflow = 1;
return 0;
}
nes_vram_queue_data[used] = (unsigned char)(ppu_addr >> 8);
nes_vram_queue_data[(unsigned char)(used + 1)] = (unsigned char)ppu_addr;
nes_vram_queue_data[(unsigned char)(used + 2)] = (unsigned char)(len | 0x80);
nes_vram_queue_data[(unsigned char)(used + 3)] = value;
nes_vram_queue_used = (unsigned char)(used + need);
return 1;
}nes_vram_queue_try_write
向 C 執行階段佇列附加攜帶實際資料的記錄。在此次呼叫中將來源的 len 個位元組複製進佇列,最後更新已用長度。PPU 傳送在執行佇列時發生。呼叫成功後修改或重用來源緩衝區,不會改變已入列的資料。
語法
unsigned char nes_vram_queue_try_write(unsigned short ppu_addr, unsigned char* src, unsigned char len);參數
ppu_addrPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。src指向目前已映射記憶體中至少
len個可讀位元組。來源區域只須在此次呼叫期間保持有效;函式會複製資料,不會寫入來源區域。長度為零時不讀取來源位元組。len寫入 PPU 的位元組數,範圍為 0–127。記錄使用長度位元組的位元 7 區分填滿,因此拒絕 128–255。零長度 write 仍占三個佇列位元組,零長度 fill 占四個。兩者在執行時都會設定 PPU 位址,但不寫入 PPUDATA。
回傳值
完整記錄入列成功回傳 1;長度無效或空間不足回傳 0。拒絕時將 nes_vram_queue_overflow 設為 1,既有記錄和已用長度保持不變。錯誤旗標會保留到清除為止,但不會阻止後續放得下的記錄。請檢查每次呼叫的回傳值。
使用條件與限制
這是 runtime.c 在 CPU 位址 0x0300–0x03BF 使用的獨立 192 位元組佇列。資料記錄占 3+len 位元組,填滿記錄占四位元組。nes_vram_queue_used 表示編碼後的記錄位元組數,不是待執行的 PPU 寫入次數或剩餘 VRAM。__vramq_* 內建佇列使用不同格式,這些函式不會清空、查詢或執行它。
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
請把建立批次和執行批次分成兩個階段;這裡沒有鎖定或雙緩衝。要確保準備過程穩定,應在附加記錄時停用 NMI,接著在關閉繪製時執行,或準備好能在 VBlank 內完成的批次後再啟用 NMI。runtime.c 會從 __nes_nmi 自動執行非空佇列,不需要提交呼叫。執行過程不設時間預算、不拆分工作,也不還原捲動狀態。佇列放得下並不表示 VBlank 時間足夠。
使用範例
if(nes_vram_queue_try_write(0x2040,source_bytes,127)!=1)failures++;
source_bytes[0]=3; // The queued first tile stays 1: payload was copied immediately.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例先填滿全部 192 個佇列位元組,並刻意讓下一筆記錄被拒絕。清空該批次後,確認長度 128 被拒絕,再用五筆記錄占用 145 位元組,安排 255 次 PPU 寫入。應顯示 CAPACITY 192、ENCODED BYTES 145、AFTER FLUSH 000、REJECTED LENGTH 001、OVERFLOW SEEN 001、FAILED CHECKS 000。拒絕相關數字保存的是程式先前步驟中觀察到的結果,不代表最終的旗標狀態。
藍色複製圖塊從 (0,16) 開始,綠色填滿圖塊從 (0,64) 開始。每區共 127 個圖塊:三整列,加上第四列的 31 個,最後一個 8×8 儲存格保持黑色。藍色序列重複實心、半寬、三角圖塊;即使來源資料改變,第一個仍為實心。在 y=112,x=16 的紅色方塊在零長度記錄後仍保留,x=224 的紅色半寬圖塊驗證 NMI 自動執行,被取消的 x=248 儲存格保持黑色。驗證比對 18,432 個像素,並確認畫面繪製期間沒有 VRAM 寫入。尚未在實體硬體上驗證。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_queue.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_queue.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/runtime.h:44
Copy a literal payload into the queue and publish its new used length last. Accept lengths 0..127; reject larger lengths and latch overflow without changing the queue. The caller must ensure queue production cannot race its NMI consumer.
kitaqfc/lib/runtime.c:40
unsigned char nes_vram_queue_try_write(unsigned short ppu_addr, unsigned char* src, unsigned char len)
{
unsigned char used;
unsigned char need;
unsigned char i;
unsigned char dst_index;
// Bit 7 selects a fill record; accepting it here would misdecode a literal
// and lengths 253..255 would also wrap the byte-sized allocation cost.
if ((len & 0x80) != 0)
{
nes_vram_queue_overflow = 1;
return 0;
}
used = nes_vram_queue_used;
// Each literal record costs three header bytes plus len payload bytes.
need = (unsigned char)(len + 3);
if ((unsigned char)(used + need) < used)
{
nes_vram_queue_overflow = 1;
return 0;
}
if ((unsigned char)(used + need) > 192)
{
nes_vram_queue_overflow = 1;
return 0;
}
nes_vram_queue_data[used] = (unsigned char)(ppu_addr >> 8);
nes_vram_queue_data[(unsigned char)(used + 1)] = (unsigned char)ppu_addr;
nes_vram_queue_data[(unsigned char)(used + 2)] = len;
i = 0;
dst_index = (unsigned char)(used + 3);
while (i != len)
{
nes_vram_queue_data[dst_index] = src[i];
dst_index = dst_index + 1;
i = i + 1;
}
nes_vram_queue_used = (unsigned char)(used + need);
return 1;
}nes_wait_nmi
等待 nes_nmi_counter 與進入函式時記錄的值不同。runtime.c 的 __nes_nmi 在處理待執行佇列後遞增這個八位元計數器;採用不等比較,因此也能處理從 255 回到 0 的情況。請啟用 NMI,並使用該處理函式或等效的計數器更新機制。此輪詢沒有逾時,不會啟用 NMI、還原捲動,也不保證恰好經過一整個影格。
語法
void nes_wait_nmi(void);回傳值
無(void)。
使用條件與限制
使用 runtime.h 中的宣告,並僅引入或編譯一次 runtime.c。除了此佇列,該檔案還提供 __nes_nmi、執行階段影格計數器、直接 PPU 操作函式,以及第 02 頁的 OAM 儲存區。請與程式的 NMI 處理協調;僅宣告函式並不會連結實作。
使用範例
__scroll_set(0,0);start_counter=nes_nmi_counter;
__ppu_ctrl_set(0x80); // Enable runtime.c's NMI handler before waiting.
nes_wait_nmi(); // Returns after the runtime completion counter changes.
nmi_seen=(u8)(nes_nmi_counter!=start_counter);
if(nmi_seen!=1)failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
執行階段範例用於學習直接傳輸和兩種等待方式。(0,16) 顯示藍色實心圖塊、左半直條與三角形的重複圖案;(0,96) 顯示綠色實心區域。每塊區域為 256×64 像素,來自 256 個圖塊位元組。修改來源後,第一個藍色圖塊仍為實心。y=208 的 x=16、224、240 處分別用紅色 8×8 正方形、左半 4×8 直條和八行三角形表示位址設定、零長度寫入和零長度填滿。兩項等待指示均為 1,FAILED CHECKS 為 0。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/runtime.h:23
Wait until the NMI handler advances its counter. NMI must already be enabled and able to execute; this polling loop has no timeout.
kitaqfc/lib/runtime.c:185
void nes_wait_nmi(void)
{
unsigned char start;
start = nes_nmi_counter;
while (nes_nmi_counter == start)
{
}
}scene.h — 場景註冊、切換與更新
透過單一共用傳輸狀態,將場景圖形串流送入 VRAM 佇列。請區分 step 完成與佇列消費端完成 PPU 寫入。
透過呼叫場景表中的 enter、update、draw、exit 處理函式,切換標題畫面、遊戲畫面等場景。
nes_scene_stream_begin
儲存目的地、來源、長度及區塊大小,並將共用串流標記為啟用。
語法
void nes_scene_stream_begin(unsigned short ppu_addr, unsigned char* src, unsigned short len, unsigned char chunk);參數
ppu_addr目的 PPU 位址,不是 CPU 位址。
src含有
len個位元組的來源;所有位元組排入佇列前,必須維持可讀取狀態。len位元組數,範圍為 0–65535;呼叫端也必須檢查目的區域邊界。
chunk每筆佇列記錄的最大有效資料量:零表示 32,大於 127 的值限制為 127。這不是單次 step 的總量上限。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
只追蹤一個串流。呼叫 begin 會替換目前串流,但不會取消已複製到佇列的資料。請保持來源空間與 ROM 映射有效,並由呼叫端驅動 step 呼叫及佇列消費。
使用範例
nes_scene_stream_begin(0x2100,small,4,2);result[0]=nes_scene_stream_state.remaining;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明如何把串流複製為佇列區塊,再消費佇列以寫入 PPU。傳送 960 個圖塊位元組、64 個屬性位元組及 32 個調色盤位元組,在 (16,32) 顯示紅色 64×32 矩形。僅呼叫 begin 不會更新畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/scene.h:47
Replace the single active transfer and retain its source pointer. Keep the source storage and any required ROM bank readable until all bytes are queued.
kitaqfc/lib/scene.c:86
void nes_scene_stream_begin(unsigned short ppu_addr, unsigned char* src, unsigned short len, unsigned char chunk)
{
nes_scene_stream_state.ppu_addr = ppu_addr;
nes_scene_stream_state.src = src;
nes_scene_stream_state.remaining = len;
nes_scene_stream_state.chunk = chunk;
nes_scene_stream_state.active = 1;
}nes_scene_stream_begin_attr
以每筆 16 位元組的佇列記錄,準備將 64 個屬性位元組傳至名稱表基底位址+0x03C0。
語法
void nes_scene_stream_begin_attr(unsigned short nt_base, unsigned char* src64);參數
nt_base名稱表的 PPU 基底位址,例如 0x2000。
src6464 個屬性位元組;全部排入佇列前須持續保留。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
只追蹤一個串流。呼叫 begin 會替換目前串流,但不會取消已複製到佇列的資料。請保持來源空間與 ROM 映射有效,並由呼叫端驅動 step 呼叫及佇列消費。
使用範例
nes_scene_stream_begin_attr(0x2000,attrs);while(nes_scene_stream_step()!=0){nes_vram_queue_nmi_flush();}nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明如何把串流複製為佇列區塊,再消費佇列以寫入 PPU。傳送 960 個圖塊位元組、64 個屬性位元組及 32 個調色盤位元組,在 (16,32) 顯示紅色 64×32 矩形。僅呼叫 begin 不會更新畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/scene.h:51
Prepare the 64-byte attribute table at nametable base + 0x03C0.
kitaqfc/lib/scene.c:102
void nes_scene_stream_begin_attr(unsigned short nt_base, unsigned char* src64)
{
nes_scene_stream_begin((unsigned short)(nt_base + 0x03C0), src64, 64, 16);
}nes_scene_stream_begin_nametable
以每筆 32 位元組的佇列記錄,準備傳輸 960 位元組的名稱表圖塊資料。
語法
void nes_scene_stream_begin_nametable(unsigned short nt_base, unsigned char* src960);參數
nt_base名稱表的 PPU 基底位址,例如 0x2000。
src960名稱表的 960 個圖塊位元組,不含其 64 個屬性位元組。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
只追蹤一個串流。呼叫 begin 會替換目前串流,但不會取消已複製到佇列的資料。請保持來源空間與 ROM 映射有效,並由呼叫端驅動 step 呼叫及佇列消費。
使用範例
nes_scene_stream_begin_nametable(0x2000,tiles960);while(nes_scene_stream_step()!=0){nes_vram_queue_nmi_flush();}nes_vram_queue_nmi_flush();result[4]=nes_scene_stream_state.remaining;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明如何把串流複製為佇列區塊,再消費佇列以寫入 PPU。傳送 960 個圖塊位元組、64 個屬性位元組及 32 個調色盤位元組,在 (16,32) 顯示紅色 64×32 矩形。僅呼叫 begin 不會更新畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/scene.h:49
Prepare the 960-byte tile portion of a nametable using 32-byte queue records.
kitaqfc/lib/scene.c:96
void nes_scene_stream_begin_nametable(unsigned short nt_base, unsigned char* src960)
{
nes_scene_stream_begin(nt_base, src960, 960, 32);
}nes_scene_stream_begin_palette
以每筆 16 位元組的佇列記錄,準備將 32 個調色盤位元組傳至 PPU 位址 0x3F00。
語法
void nes_scene_stream_begin_palette(unsigned char* src32);參數
src3232 個調色盤位元組,包含 16 個背景色與 16 個精靈色;請遵守色碼限制並注意 PPU 鏡像。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
只追蹤一個串流。呼叫 begin 會替換目前串流,但不會取消已複製到佇列的資料。請保持來源空間與 ROM 映射有效,並由呼叫端驅動 step 呼叫及佇列消費。
使用範例
nes_scene_stream_begin_palette(colors);while(nes_scene_stream_step()!=0){nes_vram_queue_nmi_flush();}nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明如何把串流複製為佇列區塊,再消費佇列以寫入 PPU。傳送 960 個圖塊位元組、64 個屬性位元組及 32 個調色盤位元組,在 (16,32) 顯示紅色 64×32 矩形。僅呼叫 begin 不會更新畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/scene.h:53
Prepare a 32-byte palette transfer to PPU address 0x3F00.
kitaqfc/lib/scene.c:108
void nes_scene_stream_begin_palette(unsigned char* src32)
{
nes_scene_stream_begin(0x3F00, src32, 32, 16);
}nes_scene_stream_step
將剩餘資料分塊,盡可能複製到執行階段 VRAM 佇列可容納的範圍。
語法
unsigned char nes_scene_stream_step(void);回傳值
因佇列容量而仍有待排入資料時為 1;全部排入或串流未啟用時為 0。區塊排入失敗時不會推進來源及目的位置,因此可重試。即使傳回零,仍可能有待執行的 PPU 傳輸。
使用條件與限制
只追蹤一個串流。呼叫 begin 會替換目前串流,但不會取消已複製到佇列的資料。請保持來源空間與 ROM 映射有效,並由呼叫端驅動 step 呼叫及佇列消費。
使用範例
result[1]=nes_scene_stream_step();result[2]=nes_scene_stream_state.active;result[3]=nes_vram_queue_used;nes_vram_queue_nmi_flush();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明如何把串流複製為佇列區塊,再消費佇列以寫入 PPU。傳送 960 個圖塊位元組、64 個屬性位元組及 32 個調色盤位元組,在 (16,32) 顯示紅色 64×32 矩形。僅呼叫 begin 不會更新畫面。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr實作與原始碼
kitaqfc/lib/scene.h:57
Queue as many chunks as available capacity allows, capped at 127 bytes each. Return one when queue exhaustion requires a later retry, zero when all data has been queued. Zero does not mean the NMI consumer has already written the PPU.
kitaqfc/lib/scene.c:116
unsigned char nes_scene_stream_step(void)
{
unsigned char chunk;
while (nes_scene_stream_state.active != 0)
{
if (nes_scene_stream_state.remaining == 0)
{
nes_scene_stream_state.active = 0;
return 0;
}
// A step may enqueue several chunks; chunk limits record size, not the total bytes or time per frame.
chunk = nes_scene_stream_state.chunk;
if (chunk == 0)
{
chunk = 32;
}
if ((unsigned short)chunk > nes_scene_stream_state.remaining)
{
chunk = (unsigned char)nes_scene_stream_state.remaining;
}
if (chunk > 127)
{
chunk = 127;
}
// A failed enqueue leaves this chunk pending so a later step can retry after the queue drains.
if (nes_vram_queue_try_write(nes_scene_stream_state.ppu_addr, nes_scene_stream_state.src, chunk) == 0)
{
return 1;
}
nes_scene_stream_state.ppu_addr = (unsigned short)(nes_scene_stream_state.ppu_addr + chunk);
nes_scene_stream_state.src = nes_scene_stream_state.src + chunk;
nes_scene_stream_state.remaining = (unsigned short)(nes_scene_stream_state.remaining - chunk);
}
return 0;
}scene_change
離開目前作用中的場景(若有),再進入指定場景。
語法
void scene_change(u8 scene_id);參數
scene_id要進入的場景索引,範圍為 0 到 count−1。
回傳值
無傳回值。
使用條件與限制
超出範圍的 ID 會被忽略。有效切換會依序執行 exit、儲存新 ID 並設定切換旗標,再執行 enter。即使選擇相同 ID,也會執行 exit 與 enter。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
使用範例
scene_change(0);scene_change(9);result[11]=events;result[12]=scene_was_changed();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
程式啟用場景 0、忽略無效 ID 9,再執行 0→1 切換與 1→1 重新進入,以檢查回呼順序。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/scene.h:33
Ignore invalid IDs; otherwise exit the current scene and enter the requested one. Selecting the current ID still performs exit/enter. Callbacks run synchronously.
kitaqfc/lib/scene.c:28
void scene_change(u8 scene_id)
{
SceneFunc fn;
if (scene_id >= kq_scene_count) return;
// Exit/enter handlers must not recursively change scenes or replace this shared table.
if (kq_scene_has_current != 0) {
fn = kq_scene_table[(__safe_index u8)kq_scene_current].exit;
if (fn != 0) fn();
}
kq_scene_current = scene_id;
kq_scene_has_current = 1;
kq_scene_changed = 1;
fn = kq_scene_table[(__safe_index u8)kq_scene_current].enter;
if (fn != 0) fn();
}scene_draw
呼叫作用中場景的 draw 回呼一次。
語法
void scene_draw();回傳值
無傳回值。
使用條件與限制
沒有作用中的場景或 draw 回呼為空時,不執行任何動作。不會清除切換旗標。請在回呼或外層遊戲迴圈中安排顯示資料傳輸與影格時序。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
使用範例
scene_draw();result[15]=events;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
事件序列包含場景 0 的 draw 所記錄的 12,以及場景 1 的 draw 所記錄的 22。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/scene.h:38
Call the active scene's draw handler if one exists; no current scene is a no-op.
kitaqfc/lib/scene.c:61
void scene_draw()
{
SceneFunc fn;
if (kq_scene_has_current == 0) return;
fn = kq_scene_table[(__safe_index u8)kq_scene_current].draw;
if (fn != 0) fn();
}scene_get_current
讀取儲存的目前場景 ID。
語法
u8 scene_get_current();回傳值
傳回儲存的 8 位元 ID;初始化後此值也為零。
使用條件與限制
僅憑傳回值為零,無法判斷場景 0 是否已啟用。請另行記錄初始化後是否已首次呼叫 scene_change()。
使用範例
result[16]=scene_get_current();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例在啟用場景 0 後讀到零,切換至場景 1 後讀到一。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/scene.h:40
Return the stored scene ID; zero is also returned before the first transition.
kitaqfc/lib/scene.c:71
u8 scene_get_current()
{
return kq_scene_current;
}scene_init
註冊場景表,但尚不啟用任何場景。
語法
void scene_init(const SceneDef* scenes, u8 count);參數
scenes由
SceneDef項目組成的陣列,各項目包含 enter、update、draw 和 exit 回呼。count項目數量;為零時沒有有效的場景 ID。
回傳值
無傳回值。
使用條件與限制
將儲存的 ID 與切換旗標歸零。不會呼叫 enter;請使用 scene_change() 啟用場景。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
使用範例
scene_init(scenes,2);scene_update();scene_draw();result[9]=events;result[10]=scene_was_changed();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例註冊兩個場景,確認啟用場景前呼叫 update 與 draw 不會產生事件。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/scene.h:28
Attach the caller-owned scene table and clear current-scene state without invoking callbacks.
kitaqfc/lib/scene.c:11
void scene_init(const SceneDef* scenes, u8 count)
{
kq_scene_table = scenes;
kq_scene_count = count;
kq_scene_current = 0;
kq_scene_changed = 0;
kq_scene_has_current = 0;
}scene_set_table
替換場景表,並清除作用中的場景。
語法
void scene_set_table(const SceneDef* scenes, u8 count);參數
scenes由
SceneDef項目組成的陣列,各項目包含 enter、update、draw 和 exit 回呼。count項目數量;為零時沒有有效的場景 ID。
回傳值
無傳回值。
使用條件與限制
像 scene_init() 一樣重設狀態,既不呼叫原場景的 exit 回呼,也不呼叫新場景的 enter 回呼。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
使用範例
scene_set_table(scenes,2);result[23]=events;result[24]=scene_was_changed();scene_draw();result[25]=events;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
九個事件發生後替換場景表,事件數仍為九;切換旗標歸零,接著呼叫 draw 不會執行任何動作。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/scene.h:30
Replace the table by resetting scene state; this does not call the old scene's exit handler.
kitaqfc/lib/scene.c:21
void scene_set_table(const SceneDef* scenes, u8 count)
{
scene_init(scenes, count);
}scene_update
呼叫作用中場景的 update 回呼一次。
語法
void scene_update();回傳值
無傳回值。
使用條件與限制
沒有作用中的場景時不執行任何動作。否則會在呼叫回呼前清除切換旗標,因此 update 內發生的切換仍可在回呼結束後透過旗標得知。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
使用範例
scene_update();result[13]=events;result[14]=scene_was_changed();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
場景 0 的 update 會記錄事件 11。這次一般更新結束後,原本為 1 的切換旗標會變成 0。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/scene.h:36
Clear the change flag before calling the active scene's update handler, so a transition made during that handler is visible afterward.
kitaqfc/lib/scene.c:50
void scene_update()
{
SceneFunc fn;
if (kq_scene_has_current == 0) return;
kq_scene_changed = 0;
fn = kq_scene_table[(__safe_index u8)kq_scene_current].update;
if (fn != 0) fn();
}scene_was_changed
讀取目前是否記錄了場景切換。
語法
u8 scene_was_changed();回傳值
切換旗標已設定時傳回 1,否則傳回 0。
使用條件與限制
讀取不會清除旗標。初始化、替換場景表,以及開始更新作用中場景時會清除旗標;無效的場景 ID 不會改變它。
使用範例
result[17]=scene_was_changed();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
檢查切換後立即讀到 1、一般更新後讀到 0,以及替換場景表後讀到 0。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/scene.h:42
Read the transition flag, which is cleared at the start of an active scene update.
kitaqfc/lib/scene.c:77
u8 scene_was_changed()
{
return kq_scene_changed;
}scroll.h — 背景、視窗與分割捲動
以 16 位元世界座標建立 PPUCTRL 的名稱表選擇及 PPUSCROLL。Y 也以 256 為單位分段,因此須考量畫面高度為 240 像素。
nes_camera_follow_center
從目標的世界位置減去畫面錨點,將結果存為相機座標。
語法
void nes_camera_follow_center(unsigned short target_x, unsigned short target_y, unsigned char center_x, unsigned char center_y);參數
target_x目標的世界 X 座標,以像素表示,範圍為 0–65535。
target_y目標的世界 Y 座標,以像素表示,範圍為 0–65535。
center_x目標所需的畫面 X 座標,範圍為 0–255。
center_y目標所需的畫面 Y 座標,範圍為 0–255。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
共用一組座標。請呼叫 nes_scroll_apply 更新硬體。減法結果為負時會在 u16 中回捲;請由遊戲限制世界邊界。
使用範例
nes_camera_follow_center(300,260,128,120);result[4]=nes_scroll_camera_x;result[5]=nes_scroll_camera_y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明已儲存的 16 位元座標如何產生 PPUCTRL 與捲動值。基本控制值為 144,套用 (264,272) 後控制值為 147。以錨點 (128,120) 追蹤目標 (300,260),相機位置為 (172,140)。另以狀態檢查確認實際 PPU 寫入。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr使用範例
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 NROM 垂直鏡像模式下顯示名稱表 1。相機位於 (264,16) 時,世界 (288,32) 的紅色 32×16 矩形出現在畫面 (24,16),示範位元 8 的表格選擇及低位元組捲動。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll_view.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_view.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --mirroring=vertical實作與原始碼
kitaqfc/lib/scroll.h:21
Subtract the screen anchor from the world point into unsigned camera coordinates. Underflow wraps; world-edge clamping belongs to the game.
kitaqfc/lib/scroll.c:56
void nes_camera_follow_center(unsigned short target_x, unsigned short target_y, unsigned char center_x, unsigned char center_y)
{
nes_scroll_camera_x = target_x - center_x;
nes_scroll_camera_y = target_y - center_y;
}nes_scroll_apply
將已存座標與基本 PPUCTRL 值合併,重設鎖存器,再寫入 PPUCTRL 及 X/Y 捲動值。
語法
void nes_scroll_apply(void);回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
各軸的位元 8 選擇名稱表,低位元組提供捲動值。Y=240–255 並非一般的垂直捲動位置。整個 PPUCTRL 都會被替換,因此請明確初始化 NMI 與其他基本位元。不會等待 VBlank;讀取 PPUSTATUS 也會影響 VBlank 旗標及共用鎖存器。
使用範例
nes_scroll_apply();result[3]=nes_scroll_ctrl_base|((nes_scroll_camera_x>>8)&1)|((nes_scroll_camera_y>>7)&2);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明已儲存的 16 位元座標如何產生 PPUCTRL 與捲動值。基本控制值為 144,套用 (264,272) 後控制值為 147。以錨點 (128,120) 追蹤目標 (300,260),相機位置為 (172,140)。另以狀態檢查確認實際 PPU 寫入。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr使用範例
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 NROM 垂直鏡像模式下顯示名稱表 1。相機位於 (264,16) 時,世界 (288,32) 的紅色 32×16 矩形出現在畫面 (24,16),示範位元 8 的表格選擇及低位元組捲動。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll_view.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_view.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --mirroring=vertical實作與原始碼
kitaqfc/lib/scroll.h:18
Combine bit 8 of each camera coordinate with base PPUCTRL, reset the latch by reading PPUSTATUS, and write low-byte X/Y scroll. This uses 256-unit wrapping on both axes rather than normalizing Y to a 240-pixel nametable height. Initialize base control to the intended PPUCTRL value, including NMI enable, before applying. Only coordinate bits 0..8 are used; arrange safe PPU timing in the caller.
kitaqfc/lib/scroll.c:34
void nes_scroll_apply(void)
{
unsigned char ctrl;
unsigned char x_hi;
unsigned char y_hi;
unsigned char latch;
x_hi = (unsigned char)((nes_scroll_camera_x >> 8) & 1);
y_hi = (unsigned char)((nes_scroll_camera_y >> 8) & 1);
ctrl = (unsigned char)(nes_scroll_ctrl_base | x_hi | (unsigned char)(y_hi << 1));
// Replace the whole control register, so the saved base also determines NMI and increment mode.
PPUCTRL = ctrl;
latch = PPUSTATUS;
PPUSCROLL = (unsigned char)nes_scroll_camera_x;
PPUSCROLL = (unsigned char)nes_scroll_camera_y;
latch = latch;
}nes_scroll_set
儲存 16 位元相機座標,不寫入 PPU。
語法
void nes_scroll_set(unsigned short camera_x, unsigned short camera_y);參數
camera_x以整數像素表示的水平座標;套用時使用最低九個位元。
camera_y垂直座標;套用時直接使用最低九個位元,不按名稱表的 240 像素高度正規化。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
共用一組座標。請呼叫 nes_scroll_apply 更新硬體。減法結果為負時會在 u16 中回捲;請由遊戲限制世界邊界。
使用範例
nes_scroll_set(264,272);result[1]=nes_scroll_camera_x;result[2]=nes_scroll_camera_y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明已儲存的 16 位元座標如何產生 PPUCTRL 與捲動值。基本控制值為 144,套用 (264,272) 後控制值為 147。以錨點 (128,120) 追蹤目標 (300,260),相機位置為 (172,140)。另以狀態檢查確認實際 PPU 寫入。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr使用範例
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 NROM 垂直鏡像模式下顯示名稱表 1。相機位於 (264,16) 時,世界 (288,32) 的紅色 32×16 矩形出現在畫面 (24,16),示範位元 8 的表格選擇及低位元組捲動。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll_view.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_view.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --mirroring=vertical實作與原始碼
kitaqfc/lib/scroll.h:12
Store camera coordinates without touching hardware registers.
kitaqfc/lib/scroll.c:25
void nes_scroll_set(unsigned short camera_x, unsigned short camera_y)
{
nes_scroll_camera_x = camera_x;
nes_scroll_camera_y = camera_y;
}nes_scroll_set_base_ctrl
清除兩個名稱表選擇位元後,儲存基本 PPUCTRL 值。
語法
void nes_scroll_set_base_ctrl(unsigned char ctrl);參數
ctrl包含 NMI、圖樣表及遞增設定的 PPUCTRL 值;最低兩個位元由座標決定。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
共用一組座標。請呼叫 nes_scroll_apply 更新硬體。減法結果為負時會在 u16 中回捲;請由遊戲限制世界邊界。
使用範例
nes_scroll_set_base_ctrl(0x93);result[0]=nes_scroll_ctrl_base;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明已儲存的 16 位元座標如何產生 PPUCTRL 與捲動值。基本控制值為 144,套用 (264,272) 後控制值為 147。以錨點 (128,120) 追蹤目標 (300,260),相機位置為 (172,140)。另以狀態檢查確認實際 PPU 寫入。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr使用範例
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 NROM 垂直鏡像模式下顯示名稱表 1。相機位於 (264,16) 時,世界 (288,32) 的紅色 32×16 矩形出現在畫面 (24,16),示範位元 8 的表格選擇及低位元組捲動。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll_view.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_view.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --mirroring=vertical實作與原始碼
kitaqfc/lib/scroll.h:10
Store PPUCTRL bits other than the two nametable-selection bits for later application.
kitaqfc/lib/scroll.c:19
void nes_scroll_set_base_ctrl(unsigned char ctrl)
{
nes_scroll_ctrl_base = (unsigned char)(ctrl & 0xFC);
}sprite.h — OBJ 配置、定位、組合精靈與動畫
精靈是可移動的硬體圖形,通常為 8×8 或 8×16 像素,由物件屬性記憶體 OAM 的項目描述。先分配欄位,在工作副本中設定位置、圖塊與屬性,再進行傳輸。複合精靈將多個欄位組成一個物件。GB 有 40 個欄位,每條掃描線最多 10 個;FC 有 64 個,每條掃描線最多 8 個。
FC 屬性:位元 0..1 選擇四種精靈調色盤之一;位元 5 將精靈放在非零背景色編號之後;位元 6/7 控制 X/Y 翻轉。未使用的位元 2..4 應為零。GB 與 FC 的旗標值不同,請使用對應平台的常數。
anim_update
推進 SpriteAnim 計時器並傳回選取的圖塊編號。每呼叫 ticks_per_frame 次就切換到下一個連續圖塊,經過 frame_count 影格後回到首格。呼叫端透過 sprite_set_tile 套用傳回值。
語法
u8 anim_update(SpriteAnim* anim);參數
anim可寫入的 SpriteAnim 狀態,包含 first_tile、frame_count、frame、ticks 與 ticks_per_frame。計數非零時,frame 應小於 frame_count,ticks 應小於 ticks_per_frame。
回傳值
選取的 8 位元圖塊編號;狀態指標為空時傳回 0。函式不寫入 OAM。
使用條件與限制
frame_count 為零時不推進,直接傳回 first_tile;ticks_per_frame 為零時凍結目前影格。計時器依呼叫次數而非影像影格推進。圖塊編號在 256 處循環,8×16 模式下也不會隔一個編號遞增。
使用範例
sprite_example_animation.first_tile=128;sprite_example_animation.frame_count=2;
sprite_example_animation.frame=0;sprite_example_animation.ticks=0;
sprite_example_animation.ticks_per_frame=2;
sprite_example_expect(anim_update(&sprite_example_animation)==128);
tile=anim_update(&sprite_example_animation);
sprite_example_expect(tile==129);sprite_set_tile(5,tile);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
設定 first_tile=128、兩影格、每影格兩次呼叫後,第一次更新傳回箭頭圖塊 128,第二次傳回正方形圖塊 129。ANIMATION 旁的正方形可確認傳回值已套用至 OAM。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:74
Advance animation ticks and wrap the frame index, returning the selected tile. Zero ticks-per-frame freezes advancement; null state returns zero.
kitaqfc/lib/sprite.c:174
u8 anim_update(SpriteAnim* anim)
{
if (anim == 0) return 0;
if (anim->frame_count == 0) return anim->first_tile;
if (anim->ticks_per_frame == 0) return (u8)(anim->first_tile + anim->frame);
anim->ticks = (u8)(anim->ticks + 1);
if (anim->ticks >= anim->ticks_per_frame) {
anim->ticks = 0;
anim->frame = (u8)(anim->frame + 1);
if (anim->frame >= anim->frame_count) anim->frame = 0;
}
return (u8)(anim->first_tile + anim->frame);
}metasprite_draw
將指定數量的精靈零件放入連續欄位。每個零件包含有號偏移、圖塊與屬性。函式啟用空閒欄位、覆寫已啟用欄位,並在欄位上限處停止。
語法
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count);參數
first_id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
x以像素為單位的橫向位置,使用無號位元組表示,並非圖塊座標。
y直接寫入 OAM 的 Y 位元組。若要將頂端放在第 1 條掃描線或更下方,應傳入頂端座標減一;239..255 位於 240 行可見區域之外。
parts至少含有 count 個可讀 MetaSpritePart 的陣列。每個 4 位元組記錄依序為有號 dx/dy、圖塊與屬性,沒有結束標記。
count零件數量,以無號位元組表示。為零時不寫入;連續欄位達到 SPRITE_MAX 時,只寫入此前能容納的零件。
回傳值
傳回實際寫入的零件數,範圍為 0..count。可藉此判斷是否因欄位上限而截斷。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
將有號位元組偏移加到基準座標後,結果以 8 位元循環。整個呼叫期間零件陣列必須可讀。已啟用的欄位也會被覆寫,函式不會保護其他物件使用的欄位。
使用範例
sprite_example_expect(metasprite_draw(10,88,SPRITE_EXAMPLE_Y(64),sprite_example_pair,2)==2);
sprite_example_expect(sprite_count_used()==9); // Sparse IDs count actual active slots.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:71
Place consecutive parts, counting each newly activated slot once. Existing active slots are overwritten without increasing the allocation count. Return the number written; an invalid first slot or zero count writes nothing.
kitaqfc/lib/sprite.c:152
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count)
{
u8 i;
i = 0;
while (i < count) {
u8 id;
id = (u8)(first_id + i);
if (id >= SPRITE_MAX) return i;
if (kq_sprite_active[id] == 0) {
kq_sprite_active[id] = 1;
kq_sprite_used = (u8)(kq_sprite_used + 1);
}
__sprite_set(id, (u8)(x + parts[i].dx), (u8)(y + parts[i].dy), parts[i].tile, parts[i].flags);
kq_sprite_x[id] = (u8)(x + parts[i].dx);
kq_sprite_y[id] = (u8)(y + parts[i].dy);
i = (u8)(i + 1);
}
return count;
}sprite_alloc
分配第一個空閒精靈欄位,並先將其隱藏。隱藏不會解除分配;顯示前請設定位置、圖塊與屬性。
語法
u8 sprite_alloc(void);回傳值
傳回分配的欄位編號;全部已用時傳回 0xFF。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
使用範例
for(i=0;i<8;i++) sprite_example_expect(sprite_alloc()==i);
sprite_example_expect(sprite_count_used()==8);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:45
Claim and hide the first free slot, or return 0xFF if all slots are active.
kitaqfc/lib/sprite.c:35
u8 sprite_alloc(void)
{
u8 i;
i = 0;
while (i < SPRITE_MAX) {
if (kq_sprite_active[i] == 0) {
kq_sprite_active[i] = 1;
kq_sprite_used = (u8)(kq_sprite_used + 1);
sprite_hide(i);
return i;
}
i = (u8)(i + 1);
}
return 0xFF;
}sprite_count_used
傳回已分配欄位數,包括隱藏的精靈與由 metasprite_draw 啟用的欄位。這是分配數量,並非畫面上的可見數量。
語法
u8 sprite_count_used(void);回傳值
0 到 SPRITE_MAX 之間的無號位元組。
使用範例
sprite_example_expect(sprite_count_used()==9); // After hiding, freeing and drawing the pair.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:62
Return the number of active slots, including slots activated by metasprite_draw. Hidden allocated slots remain active until sprite_free releases them.
kitaqfc/lib/sprite.c:108
u8 sprite_count_used(void)
{
return kq_sprite_used;
}sprite_flush_oam
等待 NMI 影格計數器遞增,再傳輸 256 位元組的 OAM 工作頁。必須啟用 NMI,且處理常式須更新該計數器。
語法
void sprite_flush_oam(void);回傳值
無(void)。
使用條件與限制
FC 常式將 OAMADDR 設為零,從 CPU 頁面 $02($0200–$02FF)啟動 DMA。應在 VBlank 或關閉繪製時使用,並避免與中斷同時修改同一工作頁。
使用範例
while(1) { sprite_flush_oam(); } // Transfer prepared sprites at the next frame boundary.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:59
Wait for NMI before requesting OAM DMA.
kitaqfc/lib/sprite.c:100
void sprite_flush_oam(void)
{
__nmi_wait();
__oam_dma();
}sprite_flush_oam_now
立即將 OAM 工作副本傳輸至硬體。函式不等待安全的顯示時段,呼叫端須安排執行時機。
語法
void sprite_flush_oam_now(void);回傳值
無(void)。
使用條件與限制
FC 常式將 OAMADDR 設為零,從 CPU 頁面 $02($0200–$02FF)啟動 DMA。應在 VBlank 或關閉繪製時使用,並避免與中斷同時修改同一工作頁。
使用範例
// Rendering is disabled here; all shadow entries have been prepared.
sprite_flush_oam_now();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:57
Transfer intrinsic shadow OAM immediately; this wrapper does not wait for VBlank.
kitaqfc/lib/sprite.c:94
void sprite_flush_oam_now(void)
{
__oam_dma();
}sprite_free
釋放已分配的欄位、將其隱藏,並把使用數減一。編號超出範圍或欄位已空閒時不執行操作。
語法
void sprite_free(u8 id);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
使用範例
sprite_free(7);sprite_free(7);
sprite_example_expect(sprite_count_used()==7); // Repeated release is ignored.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:47
Release an active valid slot and hide it; invalid/repeated frees are ignored.
kitaqfc/lib/sprite.c:52
void sprite_free(u8 id)
{
if (sprite_valid(id) == 0) return;
if (kq_sprite_active[id] == 0) return;
kq_sprite_active[id] = 0;
if (kq_sprite_used != 0) kq_sprite_used = (u8)(kq_sprite_used - 1);
sprite_hide(id);
}sprite_hide
藉由修改工作副本中的位置來隱藏精靈。分配狀態、圖塊與屬性維持不變,因此重新設定可見位置即可顯示,不必再次分配。
語法
void sprite_hide(u8 id);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
使用範例
sprite_hide(6);
sprite_example_expect(sprite_count_used()==8); // Hiding retains allocation.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:55
Mark the software position off screen and hide its OAM entry without freeing it.
kitaqfc/lib/sprite.c:85
void sprite_hide(u8 id)
{
if (sprite_valid(id) == 0) return;
kq_sprite_x[id] = 0;
kq_sprite_y[id] = 0xF0;
__sprite_hide(id);
}sprite_init
重設精靈分配狀態,並在 OAM 工作副本中隱藏所有欄位。軟體記錄的高度設為 8 像素;硬體精靈尺寸與 OAM 傳輸須另外設定。
語法
void sprite_init(void);回傳值
無(void)。
使用條件與限制
FC 初始化重設分配狀態與軟體座標,但隱藏 OAM 項目時會保留圖塊與屬性位元組。SPRITE_MAX 必須在 1..64 內。
使用範例
sprite_init();
sprite_example_expect(sprite_count_used()==0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:43
Reset allocation/position state and hide each OAM slot through the intrinsic. The software height defaults to eight; hardware sprite size is configured elsewhere.
kitaqfc/lib/sprite.c:19
void sprite_init(void)
{
u8 i;
kq_sprite_used = 0;
kq_sprite_height = 8;
i = 0;
while (i < SPRITE_MAX) {
kq_sprite_active[i] = 0;
kq_sprite_x[i] = 0;
kq_sprite_y[i] = 0;
__sprite_hide(i);
i = (u8)(i + 1);
}
}sprite_max_scanline_count
根據記錄的縱向位置與 kq_sprite_height,估算可見範圍內同一掃描線上最多重疊多少個已啟用精靈。
語法
u8 sprite_max_scanline_count(void);回傳值
0 到 SPRITE_MAX 之間的無號位元組。
使用條件與限制
將 kq_sprite_height 設為硬體高度 8 或 16。估算不考慮透明像素、橫向可見範圍或硬體優先順序。FC 讀取函式庫記錄的座標,因此直接用 OAM 內建函式更改的位置不會反映在估算中。
使用範例
sprite_example_expect(sprite_max_scanline_count()==SPRITE_EXAMPLE_LINE_COUNT);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:67
Estimate peak overlap across 240 lines from software Y/height values. This does not model pixel transparency, OAM priority or every hardware overflow quirk.
kitaqfc/lib/sprite.c:117
u8 sprite_max_scanline_count(void)
{
u8 line;
u8 best;
line = 0;
best = 0;
while (line < 240) {
u8 i;
u8 count;
i = 0;
count = 0;
while (i < SPRITE_MAX) {
if (kq_sprite_active[i] != 0) {
if (line > kq_sprite_y[i] && (u8)(line - kq_sprite_y[i]) <= kq_sprite_height) {
count = (u8)(count + 1);
}
}
i = (u8)(i + 1);
}
if (count > best) best = count;
line = (u8)(line + 1);
}
return best;
}sprite_set_flags
替換整個精靈屬性位元組。組合對應平台的旗標常數以選擇翻轉、調色盤與背景優先順序;未指定的位元會清零。
語法
void sprite_set_flags(u8 id, u8 flags);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
flags使用本平台 SPRITE_FLAG_* 常數組成的完整屬性位元組。多個旗標透過位元 OR(|)組合。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
FC 屬性:位元 0..1 選擇四種精靈調色盤之一;位元 5 將精靈放在非零背景色編號之後;位元 6/7 控制 X/Y 翻轉。未使用的位元 2..4 應為零。GB 與 FC 的旗標值不同,請使用對應平台的常數。
使用範例
sprite_set_flags(1,SPRITE_FLAG_XFLIP);
sprite_set_flags(2,SPRITE_FLAG_YFLIP);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:53
Replace the hardware attribute byte of a valid OAM slot.
kitaqfc/lib/sprite.c:78
void sprite_set_flags(u8 id, u8 flags)
{
if (sprite_valid(id) == 0) return;
__sprite_attr(id, flags);
}sprite_set_pos
更新 FC 精靈的軟體座標與 OAM 工作副本。X 是畫面位置;Y 是直接寫入 OAM 的位元組,因此要讓精靈頂端位於像素 32,應傳入 Y=31。
語法
void sprite_set_pos(u8 id, u8 x, u8 y);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
x以像素為單位的橫向位置,使用無號位元組表示,並非圖塊座標。
y直接寫入 OAM 的 Y 位元組。若要將頂端放在第 1 條掃描線或更下方,應傳入頂端座標減一;239..255 位於 240 行可見區域之外。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
座標加法採用 8 位元運算,超出後以 256 循環,不做畫面裁切。只要欄位編號有效,即使未分配也能修改。
使用範例
sprite_set_pos(0,88,SPRITE_EXAMPLE_Y(16)); // Visible top-left: (88,16).這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:49
Update software coordinates and the intrinsic OAM position for a valid slot.
kitaqfc/lib/sprite.c:62
void sprite_set_pos(u8 id, u8 x, u8 y)
{
if (sprite_valid(id) == 0) return;
kq_sprite_x[id] = x;
kq_sprite_y[id] = y;
__sprite_move(id, x, y);
}sprite_set_tile
替換一個 OAM 工作副本項目的圖塊編號。它只選取圖塊記憶體中已有的圖形,不上傳圖形,也不分配精靈。
語法
void sprite_set_tile(u8 id, u8 tile);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
tile8 位元圖塊編號。須先載入圖形。8×16 精靈仍遵循硬體規則,函式不會自動調整成成對圖塊編號。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
使用範例
sprite_set_tile(5,129); // Select the green square beside ANIMATION.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
設定 first_tile=128、兩影格、每影格兩次呼叫後,第一次更新傳回箭頭圖塊 128,第二次傳回正方形圖塊 129。ANIMATION 旁的正方形可確認傳回值已套用至 OAM。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:51
Replace the tile byte of a valid OAM slot without changing allocation state.
kitaqfc/lib/sprite.c:71
void sprite_set_tile(u8 id, u8 tile)
{
if (sprite_valid(id) == 0) return;
__sprite_tile(id, tile);
}sprite_warn_scanline_overflow
將 sprite_max_scanline_count 與每條掃描線的精靈上限比較:GB 為 10,FC 為 8。它回報軟體估算結果,不讀取硬體溢位旗標。
語法
u8 sprite_warn_scanline_overflow(void);回傳值
估算值超過每條掃描線的上限時為 1,否則為 0。
使用條件與限制
將 kq_sprite_height 設為硬體高度 8 或 16。估算不考慮透明像素、橫向可見範圍或硬體優先順序。FC 讀取函式庫記錄的座標,因此直接用 OAM 內建函式更改的位置不會反映在估算中。
使用範例
sprite_example_expect(sprite_warn_scanline_overflow()==1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/sprite.h:64
Flag software overlap estimates above eight sprites on one scanline.
kitaqfc/lib/sprite.c:143
u8 sprite_warn_scanline_overflow(void)
{
return (u8)(sprite_max_scanline_count() > 8);
}system.h — 啟動、影格計數、等待與中斷
管理影格等待次數、等待後的回呼,以及可遮罩 CPU 中斷。
fc_frame_count
fc_frame_count 是 system_get_frame 的別名,讀取封裝等待函式完成次數的 16 位元軟體計數。
讀取影格等待包裝函式的 16 位元計數器。
語法
u16 fc_frame_count(void);回傳值
傳回目前計數器值,範圍為 0~65535。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
result[3]=fc_frame_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例等待三次後讀到三。回繞檢查會明確將計數器設為 65535,再確認下一次等待後為零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:30
#define fc_frame_count system_get_framekitaqfc/lib/system.c:30
u16 system_get_frame(void)
{
return kq_system_frame;
}fc_init
fc_init 是 system_init 的別名,重設軟體影格計數與回呼註冊。
清除計數器與已註冊回呼,以初始化影格管理。
語法
void fc_init(void);回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
fc_init();result[0]=fc_frame_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例在註冊回呼前,確認初始影格編號為零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:27
#define fc_init system_initkitaqfc/lib/system.c:7
void system_init(void)
{
kq_system_frame = 0;
system_vblank_callback = 0;
// NMI waits require a running PPU and its enabled NMI source, independently of the CPU IRQ mask.
__nmi_enable();
}fc_set_vblank_callback
fc_set_vblank_callback 是 system_set_vblank_callback 的別名,註冊或移除影格等待後同步呼叫的回呼。
註冊、替換或移除影格等待後要呼叫的函式。
語法
void fc_set_vblank_callback(SystemCallback callback);參數
callback要呼叫的函式;0 會移除回呼。
回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
這是指向無引數、無傳回值函式的一般指標,不含記憶體庫編號。只要仍可能被呼叫,就必須維持目標程式碼的映射。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
fc_set_vblank_callback(on_frame);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
回呼執行三次後,註冊 0 會停用呼叫。下一次等待使影格計數前進到四,但回呼次數仍為三。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:29
#define fc_set_vblank_callback system_set_vblank_callbackkitaqfc/lib/system.c:24
void system_set_vblank_callback(SystemCallback callback)
{
system_vblank_callback = callback;
}fc_wait_vblank
fc_wait_vblank 是 system_wait_vblank 的別名,等待影格邊界、推進軟體影格計數,並呼叫已註冊回呼。
等待下一個影格、遞增計數器,再呼叫已註冊的回呼。
語法
void fc_wait_vblank(void);回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
回呼在此函式內同步執行;註冊回呼不會安裝中斷處理常式。計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數,並在超出 16 位元範圍時回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
fc_wait_vblank();fc_wait_vblank();fc_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
等待三次會呼叫回呼三次,最後一次回呼內讀到的計數器值為三。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:28
#define fc_wait_vblank system_wait_vblankkitaqfc/lib/system.c:16
void system_wait_vblank(void)
{
__nmi_wait();
kq_system_frame = (u16)(kq_system_frame + 1);
if (system_vblank_callback != 0) system_vblank_callback();
}gb_frame_count
gb_frame_count 是 system_get_frame 的別名,讀取封裝等待函式完成次數的 16 位元軟體計數。
讀取影格等待包裝函式的 16 位元計數器。
語法
u16 gb_frame_count(void);回傳值
傳回目前計數器值,範圍為 0~65535。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
這是 FC 函式庫提供的 gb_ 寫法,呼叫 FC 的 system_* 實作,不是 Game Boy 硬體。對應的 fc_ 名稱也呼叫相同 FC 實作。
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
result[3]=gb_frame_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例等待三次後讀到三。回繞檢查會明確將計數器設為 65535,再確認下一次等待後為零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_gb_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_gb_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:34
#define gb_frame_count system_get_framekitaqfc/lib/system.c:30
u16 system_get_frame(void)
{
return kq_system_frame;
}gb_init
gb_init 是 system_init 的別名,重設軟體影格計數與回呼註冊。
清除計數器與已註冊回呼,以初始化影格管理。
語法
void gb_init(void);回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
這是 FC 函式庫提供的 gb_ 寫法,呼叫 FC 的 system_* 實作,不是 Game Boy 硬體。對應的 fc_ 名稱也呼叫相同 FC 實作。
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
gb_init();result[0]=gb_frame_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例在註冊回呼前,確認初始影格編號為零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_gb_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_gb_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:31
#define gb_init system_initkitaqfc/lib/system.c:7
void system_init(void)
{
kq_system_frame = 0;
system_vblank_callback = 0;
// NMI waits require a running PPU and its enabled NMI source, independently of the CPU IRQ mask.
__nmi_enable();
}gb_set_vblank_callback
gb_set_vblank_callback 是 system_set_vblank_callback 的別名,註冊或移除影格等待後同步呼叫的回呼。
註冊、替換或移除影格等待後要呼叫的函式。
語法
void gb_set_vblank_callback(SystemCallback callback);參數
callback要呼叫的函式;0 會移除回呼。
回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
這是 FC 函式庫提供的 gb_ 寫法,呼叫 FC 的 system_* 實作,不是 Game Boy 硬體。對應的 fc_ 名稱也呼叫相同 FC 實作。
這是指向無引數、無傳回值函式的一般指標,不含記憶體庫編號。只要仍可能被呼叫,就必須維持目標程式碼的映射。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
gb_set_vblank_callback(on_frame);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
回呼執行三次後,註冊 0 會停用呼叫。下一次等待使影格計數前進到四,但回呼次數仍為三。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_gb_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_gb_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:33
#define gb_set_vblank_callback system_set_vblank_callbackkitaqfc/lib/system.c:24
void system_set_vblank_callback(SystemCallback callback)
{
system_vblank_callback = callback;
}gb_wait_vblank
gb_wait_vblank 是 system_wait_vblank 的別名,等待影格邊界、推進軟體影格計數,並呼叫已註冊回呼。
等待下一個影格、遞增計數器,再呼叫已註冊的回呼。
語法
void gb_wait_vblank(void);回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
這是 FC 函式庫提供的 gb_ 寫法,呼叫 FC 的 system_* 實作,不是 Game Boy 硬體。對應的 fc_ 名稱也呼叫相同 FC 實作。
回呼在此函式內同步執行;註冊回呼不會安裝中斷處理常式。計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數,並在超出 16 位元範圍時回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
gb_wait_vblank();gb_wait_vblank();gb_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
等待三次會呼叫回呼三次,最後一次回呼內讀到的計數器值為三。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_gb_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_gb_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:32
#define gb_wait_vblank system_wait_vblankkitaqfc/lib/system.c:16
void system_wait_vblank(void)
{
__nmi_wait();
kq_system_frame = (u16)(kq_system_frame + 1);
if (system_vblank_callback != 0) system_vblank_callback();
}system_disable_interrupts
停用 CPU 的可遮罩中斷。
語法
void system_disable_interrupts(void);回傳值
無傳回值。
使用條件與限制
受保護的更新區段應保持簡短,之後須適當還原中斷。中斷遮罩與影格等待函式所需的條件是兩回事。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
system_disable_interrupts();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例成對使用停用與啟用操作;另有專用驗證程式檢查 CPU 中斷狀態。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:25
Disable maskable CPU IRQs; this does not disable the PPU's NMI source.
kitaqfc/lib/system.c:48
void system_disable_interrupts(void)
{
__irq_disable();
}system_enable_interrupts
啟用 CPU 的可遮罩中斷。
語法
void system_enable_interrupts(void);回傳值
無傳回值。
使用條件與限制
啟用前請先準備好中斷來源與處理常式。在 FC 上,此操作與 NMI 的啟用或停用互相獨立。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
system_enable_interrupts();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例還原中斷。FC 程式會先停用 APU 影格與 DMC IRQ 來源,避免重複處理尚未清除的 IRQ。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:23
Enable maskable CPU IRQs through the intrinsic; NMI is controlled separately.
kitaqfc/lib/system.c:42
void system_enable_interrupts(void)
{
__irq_enable();
}system_get_frame
讀取影格等待包裝函式的 16 位元計數器。
語法
u16 system_get_frame(void);回傳值
傳回目前計數器值,範圍為 0~65535。
使用條件與限制
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
result[3]=system_get_frame();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例等待三次後讀到三。回繞檢查會明確將計數器設為 65535,再確認下一次等待後為零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:19
Return the wrapping 16-bit count of completed waits through this wrapper.
kitaqfc/lib/system.c:30
u16 system_get_frame(void)
{
return kq_system_frame;
}system_get_frame8
讀取影格計數器的低八位元,供短週期循環使用。
語法
u8 system_get_frame8(void);回傳值
傳回低位元組,範圍為 0~255。
使用條件與限制
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
result[4]=system_get_frame8();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例等待三次後讀到三,16 位元計數器回繞時讀到零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:21
Return the low byte of the software frame counter.
kitaqfc/lib/system.c:36
u8 system_get_frame8(void)
{
return (u8)kq_system_frame;
}system_init
清除計數器與已註冊回呼,以初始化影格管理。
語法
void system_init(void);回傳值
無傳回值。
使用條件與限制
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
system_init();result[0]=system_get_frame();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例在註冊回呼前,確認初始影格編號為零。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:13
Reset the software frame counter and callback storage, then enable NMI.
kitaqfc/lib/system.c:7
void system_init(void)
{
kq_system_frame = 0;
system_vblank_callback = 0;
// NMI waits require a running PPU and its enabled NMI source, independently of the CPU IRQ mask.
__nmi_enable();
}system_set_vblank_callback
註冊、替換或移除影格等待後要呼叫的函式。
語法
void system_set_vblank_callback(SystemCallback callback);參數
callback要呼叫的函式;0 會移除回呼。
回傳值
無傳回值。
使用條件與限制
這是指向無引數、無傳回值函式的一般指標,不含記憶體庫編號。只要仍可能被呼叫,就必須維持目標程式碼的映射。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
system_set_vblank_callback(on_frame);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
回呼執行三次後,註冊 0 會停用呼叫。下一次等待使影格計數前進到四,但回呼次數仍為三。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:17
Replace the per-wait callback; null disables callback dispatch.
kitaqfc/lib/system.c:24
void system_set_vblank_callback(SystemCallback callback)
{
system_vblank_callback = callback;
}system_wait_vblank
等待下一個影格、遞增計數器,再呼叫已註冊的回呼。
語法
void system_wait_vblank(void);回傳值
無傳回值。
使用條件與限制
回呼在此函式內同步執行;註冊回呼不會安裝中斷處理常式。計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數,並在超出 16 位元範圍時回繞。
FC 初始化會啟用 NMI;等待功能需要 NMI 正常送達。遮罩 CPU IRQ 不會停止 NMI。
使用範例
system_wait_vblank();system_wait_vblank();system_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
等待三次會呼叫回呼三次,最後一次回呼內讀到的計數器值為三。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/system.h:15
Wait for NMI, count the completed wait, then invoke the registered callback.
kitaqfc/lib/system.c:16
void system_wait_vblank(void)
{
__nmi_wait();
kq_system_frame = (u16)(kq_system_frame + 1);
if (system_vblank_callback != 0) system_vblank_callback();
}tilemap.h — 矩形圖塊地圖操作
讀取逐列儲存的圖塊陣列,依圖塊 ID 門檻測試是否為實體。矩形測試僅檢查四個角,不掃描整個內部。
nes_tilemap_get
讀取圖塊 ID;座標位於地圖外時傳回 255。
語法
unsigned char nes_tilemap_get(struct NesTilemap* map, unsigned char tx, unsigned char ty);參數
map有效地圖,包含逐列儲存的圖塊陣列、尺寸及實體判定門檻;呼叫期間其儲存空間必須可讀取。
tx圖塊 X 座標;一個單位為八個像素。
ty圖塊 Y 座標;一個單位為八個像素。
回傳值
圖塊位元組或 255;儲存的 255 無法與超出邊界的結果區分。
使用條件與限制
需要有效的地圖及可讀取的非空陣列。實體判定採用圖塊 ID 門檻,不使用獨立碰撞遮罩。
使用範例
result[1]=nes_tilemap_get(&map,2,1);result[2]=nes_tilemap_get(&map,5,1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 5×3 地圖的 (2,1) 放置實體圖塊 5;其陣列索引為 7,讀取地圖外位置會傳回 255。角落碰到障礙物時傳回 1,但 40×24 矩形僅以內部包住障礙物時傳回 0,示範只檢查四角的限制。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/tilemap.h:19
Return a tile byte, or 0xFF when coordinates exceed map dimensions. The map/storage pointers must be valid; 0xFF may also be an actual stored tile.
kitaqfc/lib/tilemap.c:32
unsigned char nes_tilemap_get(struct NesTilemap* map, unsigned char tx, unsigned char ty)
{
if (tx >= map->width)
{
return 0xFF;
}
if (ty >= map->height)
{
return 0xFF;
}
return map->tiles[nes_tilemap_index(map, tx, ty)];
}nes_tilemap_index
將圖塊座標轉為逐列儲存的位元組偏移 ty*width+tx。
語法
unsigned short nes_tilemap_index(struct NesTilemap* map, unsigned char tx, unsigned char ty);參數
map有效地圖,包含逐列儲存的圖塊陣列、尺寸及實體判定門檻;呼叫期間其儲存空間必須可讀取。
tx圖塊 X 座標;一個單位為八個像素。
ty圖塊 Y 座標;一個單位為八個像素。
回傳值
計算出的 16 位元偏移;不檢查座標邊界。
使用條件與限制
需要有效的地圖及可讀取的非空陣列。實體判定採用圖塊 ID 門檻,不使用獨立碰撞遮罩。
使用範例
result[0]=nes_tilemap_index(&map,2,1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 5×3 地圖的 (2,1) 放置實體圖塊 5;其陣列索引為 7,讀取地圖外位置會傳回 255。角落碰到障礙物時傳回 1,但 40×24 矩形僅以內部包住障礙物時傳回 0,示範只檢查四角的限制。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/tilemap.h:16
Compute a row-major byte offset by adding the row stride ty times. This internal arithmetic helper does not validate coordinates.
kitaqfc/lib/tilemap.c:14
unsigned short nes_tilemap_index(struct NesTilemap* map, unsigned char tx, unsigned char ty)
{
unsigned short index;
unsigned char y;
index = tx;
y = 0;
while (y != ty)
{
index = (unsigned short)(index + map->width);
y = y + 1;
}
return index;
}nes_tilemap_point_solid
將圖塊與 solid_from 比較;圖塊 255 及超出邊界的座標一律視為實體。
語法
unsigned char nes_tilemap_point_solid(struct NesTilemap* map, unsigned char tx, unsigned char ty);參數
map有效地圖,包含逐列儲存的圖塊陣列、尺寸及實體判定門檻;呼叫期間其儲存空間必須可讀取。
tx圖塊 X 座標;一個單位為八個像素。
ty圖塊 Y 座標;一個單位為八個像素。
回傳值
實體為 1,否則為 0。
使用條件與限制
需要有效的地圖及可讀取的非空陣列。實體判定採用圖塊 ID 門檻,不使用獨立碰撞遮罩。
使用範例
result[3]=nes_tilemap_point_solid(&map,2,1);result[4]=nes_tilemap_point_solid(&map,0,0);result[5]=nes_tilemap_point_solid(&map,5,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 5×3 地圖的 (2,1) 放置實體圖塊 5;其陣列索引為 7,讀取地圖外位置會傳回 255。角落碰到障礙物時傳回 1,但 40×24 矩形僅以內部包住障礙物時傳回 0,示範只檢查四角的限制。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/tilemap.h:22
Treat out-of-bounds/0xFF tiles as solid, then compare other tile IDs with the map's solid_from threshold.
kitaqfc/lib/tilemap.c:47
unsigned char nes_tilemap_point_solid(struct NesTilemap* map, unsigned char tx, unsigned char ty)
{
unsigned char tile;
tile = nes_tilemap_get(map, tx, ty);
if (tile == 0xFF)
{
return 1;
}
if (tile >= map->solid_from)
{
return 1;
}
return 0;
}nes_tilemap_world_box_solid
檢查世界座標矩形的左上、右上、左下及右下四個角。
語法
unsigned char nes_tilemap_world_box_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y, unsigned char width, unsigned char height);參數
map有效地圖,包含逐列儲存的圖塊陣列、尺寸及實體判定門檻;呼叫期間其儲存空間必須可讀取。
world_x以整數像素表示的世界 X;請保持小於 2048,以避免回捲。
world_y以整數像素表示的世界 Y;請保持小於 2048,以避免回捲。
width矩形寬度,為 1–255 像素;遠端邊緣
world_x+width-1必須小於 2048。height矩形高度,為 1–255 像素;遠端邊緣
world_y+height-1必須小於 2048。
回傳值
任一角落為實體時為 1,否則為 0。
使用條件與限制
寬度與高度不可為零。不掃描角落之間的邊緣或內部,因此大型矩形可能漏掉障礙物。範例中,當四角皆為空時,即使中央有障礙物仍會傳回零。
使用範例
result[12]=nes_tilemap_world_box_solid(&map,8,8,16,8);result[13]=nes_tilemap_world_box_solid(&map,0,0,40,24);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 5×3 地圖的 (2,1) 放置實體圖塊 5;其陣列索引為 7,讀取地圖外位置會傳回 255。角落碰到障礙物時傳回 1,但 40×24 矩形僅以內部包住障礙物時傳回 0,示範只檢查四角的限制。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/tilemap.h:33
Test only the four corners of a nonempty world box. Interior/edge tiles between the corners are not scanned, so large boxes can miss obstacles. Width/height must be nonzero and endpoint arithmetic must not overflow.
kitaqfc/lib/tilemap.c:86
unsigned char nes_tilemap_world_box_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y, unsigned char width, unsigned char height)
{
unsigned short x2;
unsigned short y2;
x2 = (unsigned short)(world_x + width - 1);
y2 = (unsigned short)(world_y + height - 1);
if (nes_tilemap_world_point_solid(map, world_x, world_y) != 0)
{
return 1;
}
if (nes_tilemap_world_point_solid(map, x2, world_y) != 0)
{
return 1;
}
if (nes_tilemap_world_point_solid(map, world_x, y2) != 0)
{
return 1;
}
if (nes_tilemap_world_point_solid(map, x2, y2) != 0)
{
return 1;
}
return 0;
}nes_tilemap_world_point_solid
將世界中的點轉成八像素圖塊座標,並檢查是否為實體。
語法
unsigned char nes_tilemap_world_point_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y);參數
map有效地圖,包含逐列儲存的圖塊陣列、尺寸及實體判定門檻;呼叫期間其儲存空間必須可讀取。
world_x以整數像素表示的世界 X;請保持小於 2048,以避免回捲。
world_y以整數像素表示的世界 Y;請保持小於 2048,以避免回捲。
回傳值
對應圖塊為實體時為 1,否則為 0。
使用條件與限制
需要有效的地圖及可讀取的非空陣列。實體判定採用圖塊 ID 門檻,不使用獨立碰撞遮罩。
使用範例
result[10]=nes_tilemap_world_point_solid(&map,16,8);result[11]=nes_tilemap_world_point_solid(&map,0,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 5×3 地圖的 (2,1) 放置實體圖塊 5;其陣列索引為 7,讀取地圖外位置會傳回 255。角落碰到障礙物時傳回 1,但 40×24 矩形僅以內部包住障礙物時傳回 0,示範只檢查四角的限制。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/tilemap.h:29
Convert a world point to tile coordinates and apply the tile solidity rule.
kitaqfc/lib/tilemap.c:77
unsigned char nes_tilemap_world_point_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y)
{
return nes_tilemap_point_solid(map, nes_world_to_tile8_x(world_x), nes_world_to_tile8_y(world_y));
}nes_world_to_tile8_x
將世界 X 除以八,再縮限為一個位元組的圖塊座標。
語法
unsigned char nes_world_to_tile8_x(unsigned short world_x);參數
world_x以整數像素表示的世界 X;請保持小於 2048,以避免回捲。
回傳值
world_x >> 3 的低八個位元;每 2048 像素回捲一次。
使用條件與限制
需要有效的地圖及可讀取的非空陣列。實體判定採用圖塊 ID 門檻,不使用獨立碰撞遮罩。
使用範例
result[6]=nes_world_to_tile8_x(23);result[7]=nes_world_to_tile8_x(24);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 5×3 地圖的 (2,1) 放置實體圖塊 5;其陣列索引為 7,讀取地圖外位置會傳回 255。角落碰到障礙物時傳回 1,但 40×24 矩形僅以內部包住障礙物時傳回 0,示範只檢查四角的限制。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/tilemap.h:25
Convert pixels to eight-pixel tile X and narrow to a byte. Keep world X below 2048 when wraparound is not intended.
kitaqfc/lib/tilemap.c:65
unsigned char nes_world_to_tile8_x(unsigned short world_x)
{
return (unsigned char)(world_x >> 3);
}nes_world_to_tile8_y
將世界 Y 除以八,再縮限為一個位元組的圖塊座標。
語法
unsigned char nes_world_to_tile8_y(unsigned short world_y);參數
world_y以整數像素表示的世界 Y;請保持小於 2048,以避免回捲。
回傳值
world_y >> 3 的低八個位元;每 2048 像素回捲一次。
使用條件與限制
需要有效的地圖及可讀取的非空陣列。實體判定採用圖塊 ID 門檻,不使用獨立碰撞遮罩。
使用範例
result[8]=nes_world_to_tile8_y(15);result[9]=nes_world_to_tile8_y(16);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 5×3 地圖的 (2,1) 放置實體圖塊 5;其陣列索引為 7,讀取地圖外位置會傳回 255。角落碰到障礙物時傳回 1,但 40×24 矩形僅以內部包住障礙物時傳回 0,示範只檢查四角的限制。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr實作與原始碼
kitaqfc/lib/tilemap.h:27
Convert pixels to eight-pixel tile Y with the same byte-coordinate limit.
kitaqfc/lib/tilemap.c:71
unsigned char nes_world_to_tile8_y(unsigned short world_y)
{
return (unsigned char)(world_y >> 3);
}vram.h — VRAM 佇列更新與傳輸
將延後執行的VRAM寫入命令佇列初始化為空,並清除溢位旗標。不會清除畫面、上傳圖塊圖形或配置硬體VRAM。
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
用__vramq_commit提交內建佇列,再用__nmi_wait等待NMI處理。預設處理常式會執行就緒佇列。應保持NMI及其處理常式有效;此呼叫不會把大型傳輸拆分到多個VBlank中。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
vram_clear_queue
丟棄待執行的 VRAM 命令並清除溢位旗標,不進行寫入。
語法
void vram_clear_queue(void);回傳值
無(void)。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
vram_clear_queue();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:15
Discard queued commands and explicitly reset the overflow latch.
kitaqfc/lib/vram.c:17
void vram_clear_queue(void)
{
__vramq_clear();
__vramq_clear_overflow();
}vram_flush
用__vramq_commit提交內建佇列,再用__nmi_wait等待NMI處理。預設處理常式會執行就緒佇列。應保持NMI及其處理常式有效;此呼叫不會把大型傳輸拆分到多個VBlank中。
語法
void vram_flush(void);回傳值
無(void)。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
PPU位元組位址(0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。
使用範例
vram_flush(); // One small write through the VBlank/NMI path.
__scroll_set(0,0);
if (vram_get_queue_used()!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:41
Commit queued records for consumption and wait for the NMI path.
kitaqfc/lib/vram.c:115
void vram_flush(void)
{
__vramq_commit();
__nmi_wait();
}vram_flush_now
立即呼叫__vramq_exec。只有__vramq_commit設定了就緒旗標才會執行,未提交的佇列保持不變。執行完成後清除長度與就緒旗標,但保留溢位旗標。此函式既不提交佇列,也不等待安全的PPU寫入時機。
語法
void vram_flush_now(void);回傳值
無(void)。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
PPU位元組位址(0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。
使用範例
// Rendering is stopped here. On FC, commit readiness before direct execution.
__vramq_commit();
vram_flush_now();
after_flush=vram_get_queue_used();
if (after_flush!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:39
Invoke the queue executor directly. Its ready flag must already be set by commit, and the caller supplies appropriate PPU timing.
kitaqfc/lib/vram.c:109
void vram_flush_now(void)
{
__vramq_exec();
}vram_get_overflowed
讀取佇列溢位旗標而不清除;先前的失敗紀錄可能仍保留。
語法
u8 vram_get_overflowed(void);回傳值
未記錄溢位時為0;加入被拒絕後為1,直到明確重設。執行佇列不會清除此旗標。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
overflow_seen=vram_get_overflowed();
if (overflow_seen!=1) failures++;
// Reading the latch again does not clear it.
if (vram_get_overflowed()!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:52
Read the overflow latch without clearing it.
kitaqfc/lib/vram.c:144
u8 vram_get_overflowed(void)
{
return __vramq_overflow();
}vram_get_queue_capacity
回傳命令緩衝區的總容量,與目前使用量無關。
語法
u8 vram_get_queue_capacity(void);回傳值
以此處說明的平台單位表示的無號八位元值。讀取不會修改或執行佇列。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
capacity=vram_get_queue_capacity();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:50
Return the queue's total capacity in bytes, independent of its current usage. This describes the command buffer, not free space in PPU VRAM.
kitaqfc/lib/vram.c:138
u8 vram_get_queue_capacity(void)
{
return __vramq_capacity();
}vram_get_queue_free
回傳命令緩衝區總容量減去目前用量。加入前應確認下一筆完整記錄或整個批次能否放下;此查詢不會預留空間。
語法
u8 vram_get_queue_free(void);回傳值
以此處說明的平台單位表示的無號八位元值。讀取不會修改或執行佇列。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
available=vram_get_queue_free();
if (used+available!=capacity) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:47
Return the remaining command-buffer capacity in bytes. A command requires space for its complete encoded record, including its address and metadata. Read before committing: NMI may consume a committed queue asynchronously.
kitaqfc/lib/vram.c:131
u8 vram_get_queue_free(void)
{
return (u8)(__vramq_capacity() - __vramq_len());
}vram_get_queue_used
回傳待執行命令目前占用的命令緩衝區用量,不是將寫入視訊記憶體的資料位元組數。
語法
u8 vram_get_queue_used(void);回傳值
以此處說明的平台單位表示的無號八位元值。讀取不會修改或執行佇列。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
used=vram_get_queue_used();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:43
Return the encoded queue length in bytes, not the number of commands.
kitaqfc/lib/vram.c:122
u8 vram_get_queue_used(void)
{
return __vramq_len();
}vram_init
將延後執行的VRAM寫入命令佇列初始化為空,並清除溢位旗標。不會清除畫面、上傳圖塊圖形或配置硬體VRAM。
語法
void vram_init(void);回傳值
無(void)。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
vram_init();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:13
Clear the intrinsic queue and its overflow latch.
kitaqfc/lib/vram.c:10
void vram_init(void)
{
__vramq_clear();
__vramq_clear_overflow();
}vram_queue_bg_block
將從src讀取w × h個圖塊編號並寫入base地圖矩形的操作加入佇列。來源資料每行緊密排列w位元組,目標行相隔32位元組。命令保留來源指標,因此執行前修改來源資料會改變最後顯示的區塊。
語法
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);參數
base單圖塊和矩形命令使用編譯時的
VRAM_NT_BASE,預設值為0x2000。區塊傳輸使用指定的名稱表基底位址(0x2000、0x2400、0x2800或0x2C00),仍受名稱表鏡像影響。位址在加入佇列時以每列32位元組計算;應限制在32×30圖塊區域內,以免覆寫屬性位元組。x, y以8×8圖塊為單位的左上角座標,不是像素座標。不執行裁切。應滿足
x + w <= 32;GB的y + h <= 32,FC名稱表圖塊區域的y + h <= 30。單一圖塊以寬高均為1計算。w, h以無號八位元值指定圖塊寬高。來源區塊依行排列,共
w * h位元組。零尺寸不產生可見寫入,但佇列儲存用量遵循平台的記錄規則。src指向可讀位元組的近指標,保留到執行時。整個執行期間必須保持資料有效且其記憶體或ROM記憶體庫可存取;不儲存記憶體庫編號或資料副本。非空傳輸需要有效來源,不可使用生命週期已結束的區域陣列。
回傳值
嘗試操作後溢位旗標未設定則回傳1,否則回傳0。即使目前記錄能放下,也可能因先前的溢位回傳0。多記錄操作可能只加入一部分且不復原。零長度操作也可能因既有旗標回傳0。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
完整加入本次操作需要6 * h位元組的命令緩衝區。公式計算的是包含管理資訊的編碼記錄,不是傳輸資料量。多記錄操作前應確認可用容量足夠。
單圖塊和矩形命令使用編譯時的VRAM_NT_BASE,預設值為0x2000。區塊傳輸使用指定的名稱表基底位址(0x2000、0x2400、0x2800或0x2C00),仍受名稱表鏡像影響。位址在加入佇列時以每列32位元組計算;應限制在32×30圖塊區域內,以免覆寫屬性位元組。
每列使用一筆記錄。高度0不加入記錄;寬度0仍為每列加入記錄,但不寫入位元組。列座標轉換為u8,因此y + row到256會回繞。不提供裁切或部分加入復原。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_bg_block(MAP_BASE,10,4,3,2,block);
block[0]=1; // The queued pointer sees this change when the queue executes.
if (check_result!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:27
Queue each tightly packed source row as a pointer-based copy record. Keep source storage and its ROM bank accessible until queue execution finishes; partial queuing remains possible on overflow.
kitaqfc/lib/vram.c:54
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src)
{
u8 row;
row = 0;
while (row < h) {
__vramq_copy(vram_xy_addr(base, x, (u8)(y + row)), src, w);
src = src + w;
row = (u8)(row + 1);
}
return (u8)(__vramq_overflow() == 0);
}vram_queue_bg_rect
將使用同一圖塊編號填滿背景地圖矩形的操作加入佇列。左上角圖塊座標為(x, y),大小為w × h個圖塊。純色圖塊會形成實心矩形,有圖案的圖塊則會在每個格子重複圖案。
語法
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);參數
x, y以8×8圖塊為單位的左上角座標,不是像素座標。不執行裁切。應滿足
x + w <= 32;GB的y + h <= 32,FC名稱表圖塊區域的y + h <= 30。單一圖塊以寬高均為1計算。w, h以無號八位元值指定圖塊寬高。來源區塊依行排列,共
w * h位元組。零尺寸不產生可見寫入,但佇列儲存用量遵循平台的記錄規則。tile0至255的圖塊地圖位元組。應另行載入對應圖形並選擇合適的圖案表或定址模式。圖塊編號不是指標或顏色值。
回傳值
嘗試操作後溢位旗標未設定則回傳1,否則回傳0。即使目前記錄能放下,也可能因先前的溢位回傳0。多記錄操作可能只加入一部分且不復原。零長度操作也可能因既有旗標回傳0。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
完整加入本次操作需要5 * h位元組的命令緩衝區。公式計算的是包含管理資訊的編碼記錄,不是傳輸資料量。多記錄操作前應確認可用容量足夠。
單圖塊和矩形命令使用編譯時的VRAM_NT_BASE,預設值為0x2000。區塊傳輸使用指定的名稱表基底位址(0x2000、0x2400、0x2800或0x2C00),仍受名稱表鏡像影響。位址在加入佇列時以每列32位元組計算;應限制在32×30圖塊區域內,以免覆寫屬性位元組。
每列使用一筆記錄。高度0不加入記錄;寬度0仍為每列加入記錄,但不寫入位元組。列座標轉換為u8,因此y + row到256會回繞。不提供裁切或部分加入復原。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_bg_rect(2,4,4,3,1); // A filled 32x24 rectangle at (16,32).
if (check_result!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:23
Queue one fill per row. This is not transactional: capacity exhaustion can leave earlier rows queued, and the loop continues attempting later rows.
kitaqfc/lib/vram.c:40
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile)
{
u8 row;
row = 0;
while (row < h) {
__vramq_fill(vram_xy_addr(VRAM_NT_BASE, x, (u8)(y + row)), tile, w);
row = (u8)(row + 1);
}
return (u8)(__vramq_overflow() == 0);
}vram_queue_bg_tile
將一個向背景(x, y)寫入圖塊編號的命令加入佇列。可見圖塊在佇列執行時才改變。此命令寫入地圖項目,不上傳圖塊像素資料,也不改變調色盤屬性。
語法
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);參數
x, y以8×8圖塊為單位的左上角座標,不是像素座標。不執行裁切。應滿足
x + w <= 32;GB的y + h <= 32,FC名稱表圖塊區域的y + h <= 30。單一圖塊以寬高均為1計算。tile0至255的圖塊地圖位元組。應另行載入對應圖形並選擇合適的圖案表或定址模式。圖塊編號不是指標或顏色值。
回傳值
嘗試操作後溢位旗標未設定則回傳1,否則回傳0。即使目前記錄能放下,也可能因先前的溢位回傳0。多記錄操作可能只加入一部分且不復原。零長度操作也可能因既有旗標回傳0。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
完整加入本次操作需要4位元組的命令緩衝區。公式計算的是包含管理資訊的編碼記錄,不是傳輸資料量。多記錄操作前應確認可用容量足夠。
單圖塊和矩形命令使用編譯時的VRAM_NT_BASE,預設值為0x2000。區塊傳輸使用指定的名稱表基底位址(0x2000、0x2400、0x2800或0x2C00),仍受名稱表鏡像影響。位址在加入佇列時以每列32位元組計算;應限制在32×30圖塊區域內,以免覆寫屬性位元組。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_bg_tile(2,2,1); // A solid 8x8 tile at pixel (16,16).
if (check_result!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:18
Queue one tile at the default nametable base. Return the current overflow status, which may include a failure from an earlier operation.
kitaqfc/lib/vram.c:25
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile)
{
__vramq_put(vram_xy_addr(VRAM_NT_BASE, x, y), tile);
return (u8)(__vramq_overflow() == 0);
}vram_queue_memcpy
將從src向dst複製連續len位元組的操作加入佇列。來源與目標均逐位元組遞增,不使用圖塊行間距。可傳輸地圖位元組或可寫圖塊圖案位元組,但不會轉換格式或推算每個圖塊的位元組數。
語法
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);參數
dstPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。src指向可讀位元組的近指標,保留到執行時。整個執行期間必須保持資料有效且其記憶體或ROM記憶體庫可存取;不儲存記憶體庫編號或資料副本。非空傳輸需要有效來源,不可使用生命週期已結束的區域陣列。
len連續位元組數,範圍0至65535,不是圖塊數。整個範圍應位於有效來源與可寫目標區域內;API不檢查邊界,也不防止十六位元位址回繞。
回傳值
嘗試操作後溢位旗標未設定則回傳1,否則回傳0。即使目前記錄能放下,也可能因先前的溢位回傳0。多記錄操作可能只加入一部分且不復原。零長度操作也可能因既有旗標回傳0。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
完整加入本次操作需要6 * ceil(len / 127)位元組的命令緩衝區。公式計算的是包含管理資訊的編碼記錄,不是傳輸資料量。多記錄操作前應確認可用容量足夠。
將len拆成最多127位元組一段;ceil表示無條件進位。len=0不加入記錄。127位元組分段是本函式庫包裝函式的處理,下層內建函式接受無號8位元計數。溢位後仍繼續嘗試加入,不撤銷先前記錄。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_memcpy(MAP_BASE+8*32+2,strip,3);
if (check_result!=1) failures++; // Copy three map bytes, not three tile patterns.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:31
Split a byte transfer into copy records of at most 127 bytes. The runtime retains source pointers rather than copying payloads into the queue. Return the overflow latch state after all records have been attempted.
kitaqfc/lib/vram.c:70
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len)
{
const u8* p;
u8 chunk;
p = (const u8*)src;
while (len != 0) {
if (len > 127) chunk = 127;
else chunk = (u8)len;
__vramq_copy(dst, p, chunk);
dst = (u16)(dst + chunk);
p = p + chunk;
len = (u16)(len - chunk);
}
return (u8)(__vramq_overflow() == 0);
}vram_queue_memset
將從dst開始的連續len位元組填為單一位元組value的操作加入佇列。重複的是一個位元組,不是多位元組圖塊圖案,也不會自動插入32位元組的地圖行間距。
語法
u8 vram_queue_memset(u16 dst, u8 value, u16 len);參數
dstPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。value重複寫入0至255的單一位元組。顯示意義取決於目標是圖塊索引、像素位元平面還是其他位元組結構。
len連續位元組數,範圍0至65535,不是圖塊數。整個範圍應位於有效來源與可寫目標區域內;API不檢查邊界,也不防止十六位元位址回繞。
回傳值
嘗試操作後溢位旗標未設定則回傳1,否則回傳0。即使目前記錄能放下,也可能因先前的溢位回傳0。多記錄操作可能只加入一部分且不復原。零長度操作也可能因既有旗標回傳0。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
完整加入本次操作需要5 * ceil(len / 127)位元組的命令緩衝區。公式計算的是包含管理資訊的編碼記錄,不是傳輸資料量。多記錄操作前應確認可用容量足夠。
將len拆成最多127位元組一段;ceil表示無條件進位。len=0不加入記錄。127位元組分段是本函式庫包裝函式的處理,下層內建函式接受無號8位元計數。溢位後仍繼續嘗試加入,不撤銷先前記錄。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_memset(MAP_BASE+8*32+10,1,5);
if (check_result!=1) failures++; // Five solid tiles form a 40x8 horizontal bar.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:36
Queue fills of at most 127 bytes each. Overflow can leave a partially queued transfer; no rollback is performed.
kitaqfc/lib/vram.c:94
u8 vram_queue_memset(u16 dst, u8 value, u16 len)
{
u8 chunk;
while (len != 0) {
if (len > 127) chunk = 127;
else chunk = (u8)len;
__vramq_fill(dst, value, chunk);
dst = (u16)(dst + chunk);
len = (u16)(len - chunk);
}
return (u8)(__vramq_overflow() == 0);
}vram_queue_tile
vram_queue_tile用相同參數直接呼叫vram_queue_bg_tile並回傳相同結果。這是寫入單一背景地圖項目的簡寫名稱,不是精靈操作或圖塊圖形上傳。
語法
u8 vram_queue_tile(u8 x, u8 y, u8 tile);參數
x, y以8×8圖塊為單位的左上角座標,不是像素座標。不執行裁切。應滿足
x + w <= 32;GB的y + h <= 32,FC名稱表圖塊區域的y + h <= 30。單一圖塊以寬高均為1計算。tile0至255的圖塊地圖位元組。應另行載入對應圖形並選擇合適的圖案表或定址模式。圖塊編號不是指標或顏色值。
回傳值
嘗試操作後溢位旗標未設定則回傳1,否則回傳0。即使目前記錄能放下,也可能因先前的溢位回傳0。多記錄操作可能只加入一部分且不復原。零長度操作也可能因既有旗標回傳0。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
完整加入本次操作需要4位元組的命令緩衝區。公式計算的是包含管理資訊的編碼記錄,不是傳輸資料量。多記錄操作前應確認可用容量足夠。
單圖塊和矩形命令使用編譯時的VRAM_NT_BASE,預設值為0x2000。區塊傳輸使用指定的名稱表基底位址(0x2000、0x2400、0x2800或0x2C00),仍受名稱表鏡像影響。位址在加入佇列時以每列32位元組計算;應限制在32×30圖塊區域內,以免覆寫屬性位元組。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_tile(4,2,1); // The short alias draws at pixel (32,16).
if (check_result!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:20
Alias the queued background-tile operation.
kitaqfc/lib/vram.c:32
u8 vram_queue_tile(u8 x, u8 y, u8 tile)
{
return vram_queue_bg_tile(x, y, tile);
}vram_queue_tiles
vram_queue_tiles直接呼叫vram_queue_memcpy。len仍是位元組數,不是圖塊數。保留的來源指標、佇列記錄、回傳值及執行時機均相同。
語法
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);參數
dstPPU位元組位址(
0x0000–0x3FFF),不是CPU指標。目的區域必須可寫;改寫圖樣需要CHR RAM,不能寫入CHR ROM。PPU對映與鏡像規則照常適用。連續複製和填滿應將PPUCTRL位址增量設為1。在安全的PPU寫入時段執行,然後恢復所需的捲動狀態;執行器會寫入PPUADDR和PPUDATA,不會恢復捲動設定。src指向可讀位元組的近指標,保留到執行時。整個執行期間必須保持資料有效且其記憶體或ROM記憶體庫可存取;不儲存記憶體庫編號或資料副本。非空傳輸需要有效來源,不可使用生命週期已結束的區域陣列。
len連續位元組數,範圍0至65535,不是圖塊數。整個範圍應位於有效來源與可寫目標區域內;API不檢查邊界,也不防止十六位元位址回繞。
回傳值
嘗試操作後溢位旗標未設定則回傳1,否則回傳0。即使目前記錄能放下,也可能因先前的溢位回傳0。多記錄操作可能只加入一部分且不復原。零長度操作也可能因既有旗標回傳0。
使用條件與限制
FC以固定128位元組內建緩衝區中的編碼命令位元組數計量。單圖塊寫入占4位元組,填滿記錄占5位元組,指標複製記錄占6位元組,均含中繼資料。就緒佇列可能由NMI執行,應在提交前檢查及建立,並協調產生與執行階段。
完整加入本次操作需要6 * ceil(len / 127)位元組的命令緩衝區。公式計算的是包含管理資訊的編碼記錄,不是傳輸資料量。多記錄操作前應確認可用容量足夠。
將len拆成最多127位元組一段;ceil表示無條件進位。len=0不加入記錄。127位元組分段是本函式庫包裝函式的處理,下層內建函式接受無號8位元計數。溢位後仍繼續嘗試加入,不撤銷先前記錄。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_tiles(MAP_BASE+8*32+6,strip+1,2);
if (check_result!=1) failures++; // This alias also measures length in bytes.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
在 FC 上,上方兩個正方形、三圖樣複製和最後透過 VBlank 寫入的正方形為紅色;32×24 矩形和雙圖樣複製為藍色;3×2 圖塊區塊和 40×8 橫條為綠色。背景為黑色,測試會檢查每個繪製像素的位置與顏色。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vram.h:33
Alias the byte-copy queue helper; len remains a byte count, not a tile count.
kitaqfc/lib/vram.c:87
u8 vram_queue_tiles(u16 dst, const void* src, u16 len)
{
return vram_queue_memcpy(dst, src, len);
}vrc6_sound.h — VRC6 擴充音源
此暫存器接線使用 --mapper=vrc6(映射器 24)。沒有 VRC6 的卡匣無法產生這些聲音。只使用 period 的低 12 位元;這些函式不設定頻率控制暫存器 $9003。
VRC6_PULSE_DUTY_12/25/50/75 對應值 0x00/0x10/0x20/0x30。後綴不是量測的工作週期百分比。KUROSAKI 將代碼 d 模擬為 (d+1)/16。
nes_vrc6_pulse1_off
清除 VRC6 脈波 1 的計時器高位/啟用暫存器以停止發聲。
語法
void nes_vrc6_pulse1_off(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此暫存器接線使用 --mapper=vrc6(映射器 24)。沒有 VRC6 的卡匣無法產生這些聲音。只使用 period 的低 12 位元;這些函式不設定頻率控制暫存器 $9003。
使用範例
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}預期結果
依序聽到 VRC6 脈波 1、不同工作週期的脈波 2 與鋸齒波,各持續 45 影格,間隔 15 影格。三者音高皆約 440 Hz,結尾全部停止。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc6_sound.h:22
Disable pulse 1 by clearing its high timer/enable register.
kitaqfc/lib/vrc6_sound.c:43
void nes_vrc6_pulse1_off(void)
{
VRC6_P1_HI = 0x00;
}nes_vrc6_pulse1_set
寫入 VRC6 脈波 1 控制與 12 位元計時器,再啟用聲部。
語法
void nes_vrc6_pulse1_set(u8 control, u16 period);參數
controlVRC6 脈波控制:位元 7 為閘控,位元 6..4 為工作週期代碼,低半位元組為音量 0..15。
period12 位元計時器 0..4095,高位元丟棄。範例使用脈波 253、鋸齒波 289。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此暫存器接線使用 --mapper=vrc6(映射器 24)。沒有 VRC6 的卡匣無法產生這些聲音。只使用 period 的低 12 位元;這些函式不設定頻率控制暫存器 $9003。
使用範例
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}預期結果
依序聽到 VRC6 脈波 1、不同工作週期的脈波 2 與鋸齒波,各持續 45 影格,間隔 15 影格。三者音高皆約 440 Hz,結尾全部停止。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc6_sound.h:18
Write pulse-1 control and the low 12 timer bits, then enable the channel.
kitaqfc/lib/vrc6_sound.c:27
void nes_vrc6_pulse1_set(u8 control, u16 period)
{
VRC6_P1_CTRL = control;
VRC6_P1_LO = (u8)period;
VRC6_P1_HI = (u8)(0x80 | ((period >> 8) & 0x0F));
}nes_vrc6_pulse2_off
清除 VRC6 脈波 2 的計時器高位/啟用暫存器以停止發聲。
語法
void nes_vrc6_pulse2_off(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此暫存器接線使用 --mapper=vrc6(映射器 24)。沒有 VRC6 的卡匣無法產生這些聲音。只使用 period 的低 12 位元;這些函式不設定頻率控制暫存器 $9003。
使用範例
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}預期結果
依序聽到 VRC6 脈波 1、不同工作週期的脈波 2 與鋸齒波,各持續 45 影格,間隔 15 影格。三者音高皆約 440 Hz,結尾全部停止。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc6_sound.h:24
Disable pulse 2 by clearing its high timer/enable register.
kitaqfc/lib/vrc6_sound.c:49
void nes_vrc6_pulse2_off(void)
{
VRC6_P2_HI = 0x00;
}nes_vrc6_pulse2_set
寫入 VRC6 脈波 2 控制與 12 位元計時器,再啟用聲部。
語法
void nes_vrc6_pulse2_set(u8 control, u16 period);參數
controlVRC6 脈波控制:位元 7 為閘控,位元 6..4 為工作週期代碼,低半位元組為音量 0..15。
period12 位元計時器 0..4095,高位元丟棄。範例使用脈波 253、鋸齒波 289。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此暫存器接線使用 --mapper=vrc6(映射器 24)。沒有 VRC6 的卡匣無法產生這些聲音。只使用 period 的低 12 位元;這些函式不設定頻率控制暫存器 $9003。
使用範例
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}預期結果
依序聽到 VRC6 脈波 1、不同工作週期的脈波 2 與鋸齒波,各持續 45 影格,間隔 15 影格。三者音高皆約 440 Hz,結尾全部停止。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc6_sound.h:20
Write pulse-2 control and the low 12 timer bits, then enable the channel.
kitaqfc/lib/vrc6_sound.c:35
void nes_vrc6_pulse2_set(u8 control, u16 period)
{
VRC6_P2_CTRL = control;
VRC6_P2_LO = (u8)period;
VRC6_P2_HI = (u8)(0x80 | ((period >> 8) & 0x0F));
}nes_vrc6_saw_off
清除 VRC6 鋸齒波的計時器高位/啟用暫存器以停止發聲。
語法
void nes_vrc6_saw_off(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此暫存器接線使用 --mapper=vrc6(映射器 24)。沒有 VRC6 的卡匣無法產生這些聲音。只使用 period 的低 12 位元;這些函式不設定頻率控制暫存器 $9003。
使用範例
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}預期結果
依序聽到 VRC6 脈波 1、不同工作週期的脈波 2 與鋸齒波,各持續 45 影格,間隔 15 影格。三者音高皆約 440 Hz,結尾全部停止。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc6_sound.h:28
Disable the saw channel by clearing its high timer/enable register.
kitaqfc/lib/vrc6_sound.c:63
void nes_vrc6_saw_off(void)
{
VRC6_SAW_HI = 0x00;
}nes_vrc6_saw_set
寫入 VRC6 鋸齒波的 6 位元累加增量與 12 位元計時器,再啟用。
語法
void nes_vrc6_saw_set(u8 rate, u16 period);參數
rate鋸齒波累加器增量 0..63;只使用低六位元。
period12 位元計時器 0..4095,高位元丟棄。範例使用脈波 253、鋸齒波 289。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此暫存器接線使用 --mapper=vrc6(映射器 24)。沒有 VRC6 的卡匣無法產生這些聲音。只使用 period 的低 12 位元;這些函式不設定頻率控制暫存器 $9003。
使用範例
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}預期結果
依序聽到 VRC6 脈波 1、不同工作週期的脈波 2 與鋸齒波,各持續 45 影格,間隔 15 影格。三者音高皆約 440 Hz,結尾全部停止。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc6_sound.h:26
Mask the saw accumulation rate to six bits, load a 12-bit timer and enable output.
kitaqfc/lib/vrc6_sound.c:55
void nes_vrc6_saw_set(u8 rate, u16 period)
{
VRC6_SAW_RATE = (u8)(rate & 0x3F);
VRC6_SAW_LO = (u8)period;
VRC6_SAW_HI = (u8)(0x80 | ((period >> 8) & 0x0F));
}nes_vrc6_silence_all
停用全部三個 VRC6 聲部,並清除脈波控制與鋸齒波增量。
語法
void nes_vrc6_silence_all(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此暫存器接線使用 --mapper=vrc6(映射器 24)。沒有 VRC6 的卡匣無法產生這些聲音。只使用 period 的低 12 位元;這些函式不設定頻率控制暫存器 $9003。
使用範例
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}預期結果
依序聽到 VRC6 脈波 1、不同工作週期的脈波 2 與鋸齒波,各持續 45 影格,間隔 15 影格。三者音高皆約 440 Hz,結尾全部停止。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc6_sound.h:16
Clear channel-enable/high-timer registers and output controls for all VRC6 voices. Requires the VRC6 register layout used by this module. No mapper setup or global frequency-control write is included.
kitaqfc/lib/vrc6_sound.c:16
void nes_vrc6_silence_all(void)
{
VRC6_P1_HI = 0x00;
VRC6_P2_HI = 0x00;
VRC6_SAW_HI = 0x00;
VRC6_P1_CTRL = 0x00;
VRC6_P2_CTRL = 0x00;
VRC6_SAW_RATE = 0x00;
}vrc7_sound.h — VRC7 FM 音源
適用於 --mapper=vrc7(映射器 85)。須避免中斷寫入穿插在暫存器選擇/資料配對中。函式不插入裝置穩定延遲。錄音呈現 KUROSAKI 的 FM 模型,未驗證實機音色或寫入時序。
nes_vrc7_channel_set
設定一個 FM 聲部的頻率、區塊、按鍵旗標、樂器與衰減。
語法
void nes_vrc7_channel_set(u8 channel, u8 instrument, u8 volume, u16 fnum, u8 block, u8 key_flags);參數
channelVRC7 通道 0..5;較大值不執行任何操作。
instrument樂器 0..15:0 為使用者音色,1..15 為預設音色。只使用低半位元組。
volumeVRC7 衰減 0..15:0 最響,15 衰減最大。只使用低半位元組。
fnum頻率數值 0..511,與 block 共同決定音高。只使用九位元。
block八度區塊 0..7;只使用低三位元。
key_flags0x10 為發音啟動,0x20 為延音旗標;其餘位元丟棄。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
適用於 --mapper=vrc7(映射器 85)。須避免中斷寫入穿插在暫存器選擇/資料配對中。函式不插入裝置穩定延遲。錄音呈現 KUROSAKI 的 FM 模型,未驗證實機音色或寫入時序。
樂器 0 由所有聲部共用。channel_set 先寫入按鍵/頻率高位,再寫樂器/衰減。key_off 之後,下一音符也須還原頻率高位與區塊。
使用範例
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}預期結果
比較預設樂器 1 與原創持續型使用者樂器 0,各以相同音高播放 60 影格。序列以停止發音及最大衰減結束。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc7_sound.h:18
Validate channel 0..5, then pack a 9-bit frequency, 3-bit block, key flags, instrument and volume nibbles into its registers. Volume is the raw hardware attenuation field, not a linear loudness value.
kitaqfc/lib/vrc7_sound.c:32
void nes_vrc7_channel_set(u8 channel, u8 instrument, u8 volume, u16 fnum, u8 block, u8 key_flags)
{
u8 reg;
u8 hi;
if (channel >= 6) return;
reg = channel;
hi = (u8)(((fnum >> 8) & 0x01) | ((block & 0x07) << 1) | (key_flags & 0x30));
nes_vrc7_write((u8)(0x10 + reg), (u8)fnum);
// Key/frequency-high is written before instrument/attenuation; this sequence is not an atomic note update.
nes_vrc7_write((u8)(0x20 + reg), hi);
nes_vrc7_write((u8)(0x30 + reg), (u8)(((instrument & 0x0F) << 4) | (volume & 0x0F)));
}nes_vrc7_key_off
清除所選聲部整個頻率高位/區塊/按鍵暫存器。
語法
void nes_vrc7_key_off(u8 channel);參數
channelVRC7 通道 0..5;較大值不執行任何操作。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
適用於 --mapper=vrc7(映射器 85)。須避免中斷寫入穿插在暫存器選擇/資料配對中。函式不插入裝置穩定延遲。錄音呈現 KUROSAKI 的 FM 模型,未驗證實機音色或寫入時序。
樂器 0 由所有聲部共用。channel_set 先寫入按鍵/頻率高位,再寫樂器/衰減。key_off 之後,下一音符也須還原頻率高位與區塊。
使用範例
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}預期結果
比較預設樂器 1 與原創持續型使用者樂器 0,各以相同音高播放 60 影格。序列以停止發音及最大衰減結束。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc7_sound.h:21
Clear the channel's entire frequency-high/block/key register, not just the key-on bit. A later note must restore frequency and block settings.
kitaqfc/lib/vrc7_sound.c:47
void nes_vrc7_key_off(u8 channel)
{
if (channel >= 6) return;
nes_vrc7_write((u8)(0x20 + channel), 0x00);
}nes_vrc7_set_user_patch
依序將八個位元組寫入 VRC7 使用者樂器暫存器。
語法
void nes_vrc7_set_user_patch(const u8* patch8);參數
patch8定義樂器 0 的八個位元組。不檢查 NULL。呼叫期間須維持來源記憶體庫映射。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
適用於 --mapper=vrc7(映射器 85)。須避免中斷寫入穿插在暫存器選擇/資料配對中。函式不插入裝置穩定延遲。錄音呈現 KUROSAKI 的 FM 模型,未驗證實機音色或寫入時序。
樂器 0 由所有聲部共用。channel_set 先寫入按鍵/頻率高位,再寫樂器/衰減。key_off 之後,下一音符也須還原頻率高位與區塊。
使用範例
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}預期結果
比較預設樂器 1 與原創持續型使用者樂器 0,各以相同音高播放 60 影格。序列以停止發音及最大衰減結束。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc7_sound.h:14
Copy eight caller-supplied patch bytes into user-instrument registers 0..7.
kitaqfc/lib/vrc7_sound.c:16
void nes_vrc7_set_user_patch(const u8* patch8)
{
const u8* p;
u8 i;
p = patch8;
i = 0;
while (i < 8) {
nes_vrc7_write(i, *p);
p = p + 1;
i = (u8)(i + 1);
}
}nes_vrc7_silence_all
關閉全部六個聲部的發音,並以最大衰減選擇樂器 0。
語法
void nes_vrc7_silence_all(void);回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
適用於 --mapper=vrc7(映射器 85)。須避免中斷寫入穿插在暫存器選擇/資料配對中。函式不插入裝置穩定延遲。錄音呈現 KUROSAKI 的 FM 模型,未驗證實機音色或寫入時序。
樂器 0 由所有聲部共用。channel_set 先寫入按鍵/頻率高位,再寫樂器/衰減。key_off 之後,下一音符也須還原頻率高位與區塊。
使用範例
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}預期結果
比較預設樂器 1 與原創持續型使用者樂器 0,各以相同音高播放 60 影格。序列以停止發音及最大衰減結束。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc7_sound.h:23
Key off all six voices and set instrument zero with maximum attenuation.
kitaqfc/lib/vrc7_sound.c:54
void nes_vrc7_silence_all(void)
{
u8 i;
i = 0;
while (i < 6) {
nes_vrc7_key_off(i);
nes_vrc7_write((u8)(0x30 + i), 0x0F);
i = (u8)(i + 1);
}
}nes_vrc7_write
先將暫存器編號寫入 VRC7 選擇埠,再將數值寫入資料埠。
語法
void nes_vrc7_write(u8 reg, u8 value);參數
regVRC7 暫存器編號。通道 0:0x10 為頻率低位、0x20 為高位/區塊/按鍵、0x30 為樂器/衰減。
value要寫入所選 VRC7 暫存器的位元組。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
適用於 --mapper=vrc7(映射器 85)。須避免中斷寫入穿插在暫存器選擇/資料配對中。函式不插入裝置穩定延遲。錄音呈現 KUROSAKI 的 FM 模型,未驗證實機音色或寫入時序。
樂器 0 由所有聲部共用。channel_set 先寫入按鍵/頻率高位,再寫樂器/衰減。key_off 之後,下一音符也須還原頻率高位與區塊。
使用範例
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}預期結果
比較預設樂器 1 與原創持續型使用者樂器 0,各以相同音高播放 60 影格。序列以停止發音及最大衰減結束。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm實作與原始碼
kitaqfc/lib/vrc7_sound.h:12
Write register selection followed immediately by data. No explicit device settling delay or cartridge detection is inserted by this wrapper. The caller must arrange device timing and serialize register/data pairs against interrupt writers.
kitaqfc/lib/vrc7_sound.c:8
void nes_vrc7_write(u8 reg, u8 value)
{
VRC7_ADDR = reg;
VRC7_DATA = value;
}結構、常數與完整標頭
非函式巨集、結構、陣列上限、列舉和別名,請查看這些標頭。內容依收集的原始碼原樣呈現,也包含原始註解。
actor.h — 遊戲 actor 陣列
/*
* Optional declarations for the phase 11 actor helper.
*/
// Callers initialize size and metadata and pass non-null actors.
// attr/flags are retained fields; this helper does not interpret or apply them.
struct NesActor {
unsigned short world_x;
unsigned short world_y;
unsigned char width;
unsigned char height;
unsigned char screen_x;
unsigned char screen_y;
unsigned char attr;
unsigned char flags;
};
// Set the actor's 16-bit world position without updating cached screen coordinates.
void nes_actor_set_world(struct NesActor* actor, unsigned short x, unsigned short y);
// Subtract the camera and retain only the low coordinate bytes. This performs
// wrapping projection, not clipping; callers must hide actors outside the viewport.
void nes_actor_update_screen(struct NesActor* actor, unsigned short camera_x, unsigned short camera_y);
// Draw the byte-stream metasprite at cached screen coordinates and return its
// next OAM index. Actor attr/flags are not applied by this wrapper.
unsigned char nes_actor_draw_metasprite(struct NesActor* actor, unsigned char oam_index, unsigned char* metasprite);
// Test overlap in world coordinates with exclusive right/bottom edges. Keep
// position-plus-size sums within u16; touching edges are not collisions.
// Require positive widths and heights; zero extents are not rejected before the edge tests.
unsigned char nes_actor_collide(struct NesActor* a, struct NesActor* b);kitaqfc/lib/actor.h
asset.h — 素材 ID 與資料描述
#ifndef ASSET_H
#define ASSET_H
#include "core.h"
#include "bank.h"
#define ASSET_TYPE_RAW ((u8)0)
#define ASSET_TYPE_TILES ((u8)1)
#define ASSET_TYPE_MAP ((u8)2)
#define ASSET_TYPE_SONG ((u8)3)
// The descriptor table bank and each payload bank are independent.
// ptr is a CPU-visible address and len counts bytes; type is a tag, not a decoder selection.
typedef __packed struct AssetDesc {
u8 type;
u8 bank;
const u8* ptr;
u16 len;
} AssetDesc;
// Retain a bank-qualified descriptor table; the caller keeps its storage valid.
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);
// Copy a descriptor from its ROM bank into caller storage. Null output or an
// out-of-range ID returns zero without reading the table.
u8 asset_get(u8 asset_id, AssetDesc* out_desc);
// Copy the smaller of the asset length and max_len using a bank-aware transfer.
// Return one for a valid ID even when the payload is truncated.
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);
// Switch to the asset bank, upload tile/raw data in chunks of at most 128 bytes,
// then restore the bank recorded by this library. The caller supplies safe PPU timing.
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);
// Return the asset bank or zero on lookup failure; bank zero may also be valid.
u8 asset_get_bank(u8 asset_id);
// Return the stored address without switching banks. Pair it with the descriptor
// bank before reading banked ROM; a failed lookup returns null.
const u8* asset_get_ptr(u8 asset_id);
// Return the descriptor byte length, or zero for an invalid ID.
u16 asset_get_len(u8 asset_id);
#endifkitaqfc/lib/asset.h
attribute.h — 名稱表屬性
/*
* KITAQFC phase15 attribute patch helpers.
*/
// Copy 64 already-packed attribute bytes into shadow storage. This does not
// convert one palette ID per tile into NES attribute bitfields.
// The source must expose all 64 packed bytes and stay readable for the duration of this copy.
void nes_attr_shadow_build_from_palette_map(unsigned char* src64);
// Apply a palette to every two-by-two tile quadrant touched by the rectangle.
// Empty or out-of-range rectangles leave the shadow unchanged.
void nes_attr_shadow_fill_rect(unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pal_index);
// Queue the attribute bytes covering a tile rectangle within 32x30 tiles.
// Empty rectangles succeed; invalid bounds fail without queuing.
// Capacity failure may leave earlier rows queued.
unsigned char nes_attr_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height);kitaqfc/lib/attribute.h
audio.h — 音樂、音效與音訊控制
#ifndef AUDIO_H
#define AUDIO_H
#include "core.h"
// Channel bits form a complete replacement mask for nes_apu_channel_enable.
#define NES_APU_ENABLE_PULSE1 0x01
#define NES_APU_ENABLE_PULSE2 0x02
#define NES_APU_ENABLE_TRIANGLE 0x04
#define NES_APU_ENABLE_NOISE 0x08
#define NES_APU_ENABLE_DMC 0x10
// Disable frame IRQs, enable the four tonal/noise channels and install quiet
// control defaults. DMC remains disabled.
void nes_apu_init(void);
// Replace all five channel-enable bits in APU_STATUS; this is not an additive enable.
void nes_apu_channel_enable(u8 mask);
// Disable every channel and clear volume/DMC output settings used by this helper.
void nes_apu_silence_all(void);
// Enable only pulse 1, disable its sweep and load control, 11-bit timer and
// length-table index. Starting this effect disables the other APU channels.
void nes_sfx_square1(u8 duty_volume, u16 period, u8 length_index);
// Enable only pulse 2 and load its control/timer/length fields, disabling other channels.
void nes_sfx_square2(u8 duty_volume, u16 period, u8 length_index);
// Enable only triangle and load linear-counter, timer and length fields.
void nes_sfx_triangle(u8 linear, u16 period, u8 length_index);
// Enable only noise and load envelope/control, period/mode and length fields.
void nes_sfx_noise(u8 volume, u8 period_mode, u8 length_index);
// Trigger the predefined pulse-1 tick effect; it inherits the exclusive-channel behavior.
void nes_sfx_tick_blip(void);
// Trigger the predefined pulse-1 movement effect.
void nes_sfx_move_blip(void);
// Convert a CPU sample address and byte length to DMC register units. Supply
// an address in 0xC000-0xFFC0 aligned to 64 bytes and a representable length
// 16*n+1 in 1..4081; inputs are narrowed without validation or bank management.
void nes_dmc_config(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);
// Enable DMC together with all four other channels by replacing the status mask.
void nes_dmc_start(void);
// Disable DMC while leaving all four other channel-enable bits set.
void nes_dmc_stop(void);
// Install sample parameters, then start DMC using the full-channel enable mask.
void nes_dmc_play(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);
#endifkitaqfc/lib/audio.h
audio_vblank.h — 透過 VBlank IRQ 播放音樂
#ifndef NES_AUDIO_VBLANK_H
#define NES_AUDIO_VBLANK_H
#include "core.h"
// Original MIT-licensed NMI sequencer. Channel order follows the physical APU:
// CH1 pulse 1, CH2 pulse 2, CH3 triangle, CH4 noise (indices 0, 1, 2, 3).
// Every record is five bytes: delay, CH1, CH2, CH3, CH4.
// Delay 1..255 holds the new state for that many NMI ticks. Delay 0 ends playback.
// Tonal notes 0..71 are C2..B7, tuned for NTSC. Noise 0..15 selects a long-mode
// period; 16..31 selects short mode. HOLD preserves a channel; STOP silences it.
#define NES_AUDIO_NOISE_ENVELOPE 128
#define NES_AUDIO_HOLD 255
#define NES_AUDIO_STOP 254
#define NES_AUDIO_RECORD_BYTES 5
#define NES_AUDIO_QUEUE_CAPACITY 7
// Reset the queue, feeder and diagnostic counters; silence and initialize the
// APU. Owns the four basic channels and disables DMC and APU frame IRQs.
void nes_audio_vblank_init(void);
// Copy one complete validated record to RAM and publish it atomically last.
// Return 1 on success, 0 for null/invalid/full. Call from one foreground producer.
u8 nes_audio_vblank_enqueue(const u8* record);
// Return queued records (0..7), excluding the record whose delay is in progress.
u8 nes_audio_vblank_queued(void);
// Return available record slots (0..7), not bytes.
u8 nes_audio_vblank_free(void);
// Enable consumption at the next NMI. Does not enable PPU NMI itself.
void nes_audio_vblank_start(void);
// Disable consumption, silence, discard queued records and clear the feeder.
void nes_audio_vblank_stop(void);
// Stop and attach a readable five-byte-record stream; return 0 for null, zero
// count or a count above 13107. Nonzero loop repeats the stream. Does not start.
u8 nes_audio_vblank_set_music(const u8* records,u16 count,u8 loop);
// Copy at most seven records from the attached stream. Return copies accepted.
// A one-shot feeder appends a delay-zero terminator after the last timed record.
// Keep the stream's ROM bank mapped during this foreground call only.
u8 nes_audio_vblank_refill(void);
// Set the stream, prefill the queue and start. Return 0 for invalid setup/data.
u8 nes_audio_vblank_play_music(const u8* records,u16 count,u8 loop);
// Return 1 while the BGM consumer is enabled, including a recoverable queue underrun.
u8 nes_audio_vblank_is_playing(void);
// Saturating count of starvation episodes, cleared by init; END is not starvation.
u8 nes_audio_vblank_underruns(void);
// Configure the next note: pulse bits 7..6 select duty and 3..0 select volume;
// noise uses volume 3..0, or NES_AUDIO_NOISE_ENVELOPE | decay_period (0..15)
// for a one-shot hardware envelope (larger periods decay more slowly). The
// next noise note starts at volume 15; its length permits a full decay.
// Triangle uses zero for silent, nonzero for full level.
// Return 0 for channel >=4. Hardware has no triangle volume control.
u8 nes_audio_vblank_set_timbre(u8 channel,u8 control);
// Any nonzero argument freezes both timelines and mutes immediately. Zero
// resumes from the stored delays and restores held notes on the next NMI.
// BGM is_playing remains enabled during pause. Refill may still fill the queue.
void nes_audio_vblank_pause(u8 on);
// Copy 1..7 timed records. Bits 0..3 select channels temporarily owned by SFX.
// BGM continues underneath and its current notes return when the effect ends.
// Return 1 after copying; 0 for null, invalid count/data or an empty low mask.
// Ignore mask bits 4..7. All fields are validated, even unselected channels.
// Delay zero is not accepted for SFX. Invalid input preserves the current SFX.
// Replacement restarts the effect; the first HOLD starts from a stopped note.
// The source need only stay mapped/readable until this foreground call returns.
u8 nes_audio_vblank_play_sfx(const u8* records,u8 count,u8 mask);
// Release effect ownership at the next NMI, restoring current BGM notes.
// This does not stop or restart the BGM and does not write the APU immediately.
void nes_audio_vblank_stop_sfx(void);
// NMI hook: invoke exactly once per NMI. With a custom handler or a compiler
// without automatic audio-hook linking, call it there. Never call from main
// or call it again if the compiler already inserts the hook.
// Saves A/X/Y, uses no compiler scratch bytes and reads only RAM/fixed ROM.
void __nes_audio_vblank_tick(void);
#endifkitaqfc/lib/audio_vblank.h
bank.h — 考慮 bank 的程式碼與資料存取
#ifndef BANK_H
#define BANK_H
#include "core.h"
#include "intrinsics.h"
// Pair a bank selector with its CPU-window address; a near pointer alone cannot select the bank.
typedef __packed struct BankPtr {
u8 bank;
const u8* ptr;
} BankPtr;
extern u8 kq_bank_current;
// Record the bank in the library shadow and invoke the mapper-aware compiler intrinsic.
void bank_switch(u8 bank);
// Read this wrapper's bank shadow; arbitrary mapper writes do not update it.
u8 bank_get_current(void);
// Read one byte from an explicit ROM bank and 16-bit CPU address.
u8 far_data_read8(u8 bank, const void* addr);
// Read a 16-bit value through the bank-aware compiler intrinsic.
u16 far_data_read16(u8 bank, const void* addr);
// Copy len bytes from banked ROM to caller-owned writable storage.
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);
// Store a bank/address pair without reading memory; null output is ignored.
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);
// Read one byte using both the bank and address of the supplied far pointer.
u8 farptr_read8(BankPtr ptr);
// Read a 16-bit value using both components of the far pointer.
u16 farptr_read16(BankPtr ptr);
// Copy len bytes from a far pointer; the caller provides a sufficiently large destination.
void farptr_read(BankPtr ptr, void* dst, u16 len);
// Route a declared zero-argument function through the far-call intrinsic; this is not a general
// callback-pointer dispatcher. Mapper support and fixed-bank call-site rules still apply.
#define far_call(bank, func) __farcall((bank), func)
#endifkitaqfc/lib/bank.h
chain.h — 位置歷史環狀緩衝區
#ifndef CHAIN_H
#define CHAIN_H
#include "core.h"
typedef __packed struct ChainPoint {
s16 x;
s16 y;
} ChainPoint;
// head identifies the newest point; count grows to capacity, then old points are overwritten.
// Capacity at most 128 keeps every head + age sum within a byte for this implementation.
typedef __packed struct Chain {
ChainPoint* points;
u8 capacity;
u8 count;
u8 head;
} Chain;
// Attach caller-owned ring storage and start with no recorded points.
// The storage must remain valid for the lifetime of the chain.
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity);
// Forget the recorded points without clearing or freeing the backing storage.
void chain_clear(Chain* chain);
// Move the ring head backward and store the newest point. Once full, each push
// replaces the oldest point; zero capacity is a no-op.
void chain_push_head(Chain* chain, s16 x, s16 y);
// Read a point by age, with index zero denoting the newest point. Return zero
// for an invalid request and clear a non-null output first. Keep head + index
// within the 8-bit range: addition is narrowed before the capacity wrap.
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out);
// Return the number of stored points, or zero for a null chain.
u8 chain_get_count(const Chain* chain);
// Return target minus current along the shortest wrapped route.
// Supply size 1..256 and coordinates in 0..size-1; inputs are not normalized.
// Exactly half a field retains the direct displacement sign.
s16 chain_wrap_delta(u8 target, u8 current, u16 size);
// Articulated body: one current pose per joint, including the head at index 0.
// Caller-owned byte arrays keep the inner loop compact on both GB and FC.
// Heading sectors run clockwise: 0=right, 4=down, 8=left, 12=up.
// Coordinates are pixels; each wrapped dimension accepts 1..256 pixels.
typedef __packed struct {
u8* x;
u8* y;
u8* heading;
u8 capacity;
u8 count;
u16 width;
u16 height;
} ChainBody;
// Attach three non-overlapping capacity-byte arrays. Return 1 on success.
// Invalid storage, zero capacity or dimensions outside 1..256 disable the body.
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height);
// Seed count joints in a straight pose behind the head; count includes the head.
// Return 0 without changing the pose if count is zero or exceeds capacity.
// Coordinates wrap to the playfield and headings are masked to 0..15.
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading);
// Install the caller's head pose, then pull joints from front to rear.
// Each joint aims four pixels behind its updated predecessor and receives that
// predecessor's OLD heading. Each axis moves 1 pixel, or 2 when error exceeds 4.
// Call once per simulation tick; this does not advance head physics or render.
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading);
// Append a copy of the current tail; later steps separate the new joint.
// Return 1 on growth, or 0 for an empty, disabled or full body.
u8 chain_body_grow(ChainBody* body);
// Remove all joints while retaining caller-owned storage and playfield settings.
void chain_body_clear(ChainBody* body);
#endifkitaqfc/lib/chain.h
collision.h — 矩形與其他碰撞測試
/*
* Optional declarations for the phase 11 collision helper.
*/
struct NesBox16 {
unsigned short x;
unsigned short y;
unsigned char w;
unsigned char h;
};
// Test two axis-aligned world boxes using exclusive right/bottom edges.
// Coordinate-plus-size sums must fit u16; touching edges return false.
// Both boxes must have positive dimensions; the overlap test has no separate empty-box guard.
unsigned char nes_box16_intersects(struct NesBox16* a, struct NesBox16* b);
// Test a half-open box: left/top edges are included and right/bottom edges
// excluded. Callers provide valid pointers and non-overflowing edge coordinates.
unsigned char nes_box16_contains_point(struct NesBox16* box, unsigned short px, unsigned short py);kitaqfc/lib/collision.h
core.h — 基本整數型別
#ifndef CORE_H
#define CORE_H
// Public scalar aliases for the compiler's byte and 16-bit integer types.
typedef unsigned char u8;
typedef unsigned short u16;
typedef signed char s8;
typedef signed short s16;
// Boolean convenience values; API functions returning bit masks need not normalize to TRUE.
#define TRUE 1
#define FALSE 0
#endifkitaqfc/lib/core.h
danmaku.h — 彈池、扇形發射、命中與擦彈
// Copyright (c) 2026 DAISUKE OBA. SPDX-License-Identifier: MIT
#ifndef KITAQFC_DANMAKU_H
#define KITAQFC_DANMAKU_H
#include "core.h"
#include "intrinsics.h"
#define DANMAKU_MAX 64
// Reserve cartridge PRG RAM 0x6000..0x627F (640 bytes), enabled and writable.
// Bullet centers remain in [8,248) x [24,232). These margins prevent byte
// wraparound even at the largest signed Q4.4 velocity accepted by spawn.
extern u8 dm_x[64];
extern u8 dm_y[64];
extern u8 dm_active[64];
extern u8 dm_grazed[64];
extern u8 dm_count;
extern u8 dm_peak;
extern u8 dm_hit;
extern u8 dm_graze;
extern u8 dm_player_x;
extern u8 dm_player_y;
extern u8 dm_invulnerable;
extern u16 dm_spawned;
extern u16 dm_rejected;
// Reset the pool, counters and rotating OAM priority. Player settings survive.
void danmaku_reset(void);
// Remove all bullets and step events; preserve lifetime/peak counters.
void danmaku_clear(void);
// Allocate a bullet at pixel-center x/y with signed 1/16-pixel velocities.
// Return one on success, zero outside the playfield or when all 64 slots are full.
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);
// Emit up to 64 bullets. Angles wrap in 32 steps: 0 right, 8 down, 16 left,
// 24 up. Speed is in 1/16 pixel, clamped to 64. Each failed allocation counts.
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);
// Move all live bullets once. Remove offscreen/hitting bullets. Hit uses a
// +/-3-pixel box; graze uses +/-11, once per bullet. Events describe this step.
// This updates logic only; it neither writes OAM nor calls a game damage handler.
void danmaku_step(void);
// Write up to slots consecutive shadow-OAM entries starting at first_oam.
// Rotate bullet priority by 13 modulo 64 and hide unused entries in that range.
// tile is an 8x8 sprite centered at (4,4). Return the number emitted. DMA is
// caller-owned and belongs in VBlank. Hardware's eight-per-scanline limit remains.
u8 danmaku_draw(u8 first_oam, u8 slots, u8 tile, u8 attributes);
#endifkitaqfc/lib/danmaku.h
debug.h — RAM 紀錄與斷言
#ifndef DEBUG_H
#define DEBUG_H
#include "core.h"
// Choose 1..255 consistently across units; the valid-entry count is a byte.
#ifndef DEBUG_TRACE_MAX
#define DEBUG_TRACE_MAX 32
#endif
// Names are retained pointers, not copied strings; keep their storage and ROM mapping readable.
typedef __packed struct DebugTraceEntry {
const u8* name;
u16 value;
u16 frame;
} DebugTraceEntry;
extern DebugTraceEntry kq_debug_trace_log[DEBUG_TRACE_MAX];
extern u8 kq_debug_trace_count;
extern u16 kq_debug_frame;
extern u16 kq_debug_last_assert;
// Build the RAM-resident ASSERT label and reset log length, frame tag and last
// assertion code. Old log storage bytes are not erased.
void debug_init(void);
// Choose the frame tag stored in subsequent debug entries.
void debug_set_frame(u16 frame);
// Append a named marker with the reserved marker value 0xFFFF.
void debug_mark_frame(const u8* label);
// Widen a byte value into the trace entry's 16-bit value field.
void debug_trace_u8(const u8* name, u8 value);
// Append a 16-bit value with the current frame tag.
void debug_trace_u16(const u8* name, u16 value);
// Store the assertion code even if the log is full, then attempt an ASSERT
// entry. The helper records failure but does not stop execution.
void debug_assert_fail(u16 code);
// Read the number of valid entries in the fixed trace buffer.
u8 debug_get_trace_count(void);
// Borrow the internal trace array; bound inspection by debug_get_trace_count.
const DebugTraceEntry* debug_get_trace_log(void);
// Read the latest assertion code, initially zero after debug_init.
u16 debug_get_last_assert(void);
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)
#endifkitaqfc/lib/debug.h
entity.h — 固定陣列物件池
#ifndef ENTITY_H
#define ENTITY_H
#include "core.h"
// Choose capacity 1..255 consistently across units; counters are bytes and FF is the failure sentinel.
#ifndef ENTITY_MAX
#define ENTITY_MAX ((u8)16)
#endif
// Coordinates, velocities, state and timer have game-defined units.
// The sprite byte is bookkeeping only; releasing a slot does not hide or free its sprite.
typedef __packed struct Entity {
u8 active;
u8 type;
s16 x;
s16 y;
s16 vx;
s16 vy;
u8 state;
u8 timer;
u8 sprite;
} Entity;
// An entity callback receives a slot ID, not a persistent object handle.
// Use a callback in common PRG bank 0, or keep its bank mapped throughout dispatch.
typedef void (*EntityFn)(u8 id);
// Reset every slot before the game starts using the pool.
void entity_init(void);
// Returns a reusable slot ID, or 0xFF if no slot is free.
u8 entity_create(u8 type, s16 x, s16 y);
// Release a valid slot without clearing its payload. Reallocation resets the payload;
// a saved pointer or ID must not be treated as a persistent entity identity.
void entity_destroy(u8 id);
// Returns null for an invalid or inactive ID; the returned pointer aliases reusable pool storage.
Entity* entity_get(u8 id);
// Call fn(id) for each active slot in ascending order. A null callback does nothing.
// Changes to later slots take effect during the same traversal. Do not reenter this traversal.
void entity_update_all(EntityFn fn);
// Call the drawing callback for each active slot, using the same traversal rules as update.
// The callback submits drawing data; the pool does not allocate sprites.
void entity_draw_all(EntityFn fn);
// Count occupied slots without changing entity state.
u8 entity_count_active(void);
// Release every entity and restore deterministic defaults, including the no-sprite sentinel.
void entity_clear_all(void);
#endifkitaqfc/lib/entity.h
fc.h — 函式庫統整標頭
#ifndef FC_H
#define FC_H
// Convenience header collecting FC interfaces. Inclusion provides declarations
// and aliases, not every implementation; link only the source modules required
// by the selected runtime, avoiding alternative helpers with conflicting symbols.
#include "core.h"
#include "intrinsics.h"
#include "system.h"
#include "input.h"
#include "runtime.h"
#include "ppu.h"
#include "ppu_direct.h"
#include "vram_queue.h"
#include "vram.h"
#include "oam.h"
#include "sprite.h"
#include "pad.h"
#include "input_repeat.h"
#include "palette.h"
#include "scroll.h"
#include "tilemap.h"
#include "nametable_asset.h"
#include "attribute.h"
#include "scene.h"
#include "metasprite.h"
#include "actor.h"
#include "entity.h"
#include "collision.h"
#include "fixed.h"
#include "physics2d.h"
#include "physics3d.h"
#include "bank.h"
#include "asset.h"
#include "debug.h"
#include "chain.h"
#include "audio.h"
#include "audio_vblank.h"
#include "fds_sound.h"
#include "vrc6_sound.h"
#include "vrc7_sound.h"
#include "mapper.h"
// This final include adds function-like macros, including zero-argument nes_oam_dma.
// Use selective headers when calling the page-argument runtime API with the same name.
#include "nes_game.h"
#endifkitaqfc/lib/fc.h
fds.h — FDS 磁碟操作
#ifndef FDS_H
#define FDS_H
#include "intrinsics.h"
// Return the compile-time FDS mapper selection as 0 or 1; this is not a hardware probe.
u8 __fds_available(void);
// Return the inverted disk-absent bit from 4032 as 0 or 1; this checks presence, not transfer completion.
u8 __fds_disk_ready(void);
// Return raw status mask 4032 & 04, either 0 or 4. This is not a numbered disk-side identifier.
u8 __fds_side(void);
// Read the entire 4030 status register; this is not a stored BIOS error code.
u8 __fds_error(void);
// Poll disk presence until the absent bit clears. There is no timeout or cancellation path.
void __fds_wait_ready(void);
// Alias the same disk-presence wait as __fds_wait_ready; the call can block indefinitely.
void __fds_wait_insert(void);
#endifkitaqfc/lib/fds.h
fds_file.h — 載入 FDS 檔案
#ifndef FDS_FILE_H
#define FDS_FILE_H
#include "intrinsics.h"
// Native FDS32: load a non-boot file at its disk-header address, then memmove
// PRG bytes to dst. Null dst keeps the native destination (also for PPU files).
// Both CPU spans must fit $0200-$07FF or $6000-$DFFF and be owned by the caller.
// Return 0, a BIOS error, $40 for a missing transfer, or $FF for invalid input.
// Call from common code with disk-I/O interrupt/display prerequisites satisfied.
u8 __fds_load_file(u8 id, u8* dst);
// Overwrite the final non-boot PRG slot on its side, preserving its ID/name/load
// address. len must equal its packaged size; src must be a valid CPU RAM span.
// The resolved physical ordinal selects the slot, independently of file ID.
// Return 0, a BIOS error, or $FF before any write for an invalid slot/span/size.
u8 __fds_save_file(u8 id, const u8* src, u16 len);
// Query the compiled --fds-meta/--fds-manifest table, not the inserted disk; return 0 or 1.
u8 __fds_file_exists(u8 id);
// Return the compiled metadata size, or zero if id is absent. No disk directory is read.
u16 __fds_file_size(u8 id);
#endifkitaqfc/lib/fds_file.h
fds_overlay.h — FDS 覆疊模組程式碼
#ifndef FDS_OVERLAY_H
#define FDS_OVERLAY_H
#include "intrinsics.h"
// Load disk file id through BIOS, return its error byte and mark bank residency FF (unknown).
u8 __fds_load_overlay(u8 id);
// Load logical bank 1 from its separate boot file, or bank 2+ from overlay-start-id+(bank-2).
// Return zero on success, FF for invalid/unavailable mappings, or the BIOS error.
// A failed BIOS transfer marks residency FF (unknown); a matching valid guard can skip loading.
u8 __fds_load_bank(u8 bank);
// Return zero when the software residency record matches, otherwise call __fds_load_bank.
u8 __fds_require_bank(u8 bank);
// Return the software resident-bank byte, or FF after a failed bank transfer.
// This is not a checksum of overlay memory.
u8 __fds_current_bank(void);
// Compare a valid bank with the software resident-bank byte; FF (unknown) never matches.
u8 __fds_is_bank_resident(u8 bank);
// Return the linker-generated overlay-function count; zero if the table is disabled.
u8 __fds_overlay_function_count(void);
// Evaluate bank once and call the named zero-argument function using its linked bank.
// Restore the caller window before returning; restoration failure stops in common code.
u8 __fds_overlay_farcall(u8 bank, u16 func);
// Same named, zero-argument dispatch as __fds_overlay_farcall; evaluate bank once.
u8 __fds_farcall(u8 bank, u16 func);
#endifkitaqfc/lib/fds_overlay.h
fds_save.h — FDS 儲存功能宣告
#ifndef FDS_SAVE_H
#define FDS_SAVE_H
// Compatibility include for FDS file/save declarations; this header adds no storage or implementation.
#include "fds_file.h"
#endifkitaqfc/lib/fds_save.h
fds_sound.h — FDS 波表音源
#ifndef FDS_SOUND_H
#define FDS_SOUND_H
#include "intrinsics.h"
// Write 83 to 4023 and zero to 4089/408A to initialize disk/sound register gates.
void __fds_sound_enable(void);
// Copy exactly 64 readable bytes to wave RAM with wave writes enabled, then set 4089 to zero.
void __fds_wave_load(const u8* wave64);
// Stream 32 readable bytes to 4088; the caller prepares modulation state and write conditions.
void __fds_mod_load(const u8* mod32);
// Write a 12-bit frequency to 4082/4083; upper control bits in 4083 are cleared.
void __fds_freq_set(u16 freq);
// Write (volume & 3F) | 80 to 4080 for direct volume control; masking wraps, rather than clamps.
void __fds_volume_set(u8 vol);
// Write the three raw arguments to 4080, 4084 and 408A in that order.
// The legacy parameter names do not describe three independently packed envelope fields.
void __fds_env_set(u8 speed, u8 gain, u8 mode);
#endifkitaqfc/lib/fds_sound.h
fixed.h — Q8.8 定點運算與矩形
#ifndef FIXED_H
#define FIXED_H
#include "core.h"
// Signed Q8.8 spans -128 to 127 + 255/256; one integer unit is represented by 256.
typedef s16 fix8;
#define FIX_ONE ((fix8)256)
#define FIX_HALF ((fix8)128)
typedef __packed struct Vec2 {
fix8 x;
fix8 y;
} Vec2;
typedef __packed struct KQRect {
s16 x;
s16 y;
s16 w;
s16 h;
} KQRect;
// Convert an integer to signed 8.8 fixed point by moving it into the high byte.
// The caller must keep the result within the representable 16-bit range.
fix8 fix_from_int(s16 n);
// Discard the eight fractional bits using a signed right shift.
s16 fix_to_int(fix8 x);
// Approximate 8.8 multiplication by discarding four low bits from each operand
// before multiplying. This trades precision for a smaller intermediate product.
fix8 fix_mul(fix8 a, fix8 b);
// Scale the reduced-precision quotient back to 8.8 and return zero for b == 0.
// Callers must also ensure (b >> 4) is nonzero; the explicit check only tests b.
// The intermediate product must fit the compiler's integer arithmetic.
fix8 fix_div(fix8 a, fix8 b);
// Interpolate toward b using a quantized Q0.8 weight. Both shifts discard low
// bits, so small changes may vanish and a weight of 255 need not reach b.
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8);
// Return the magnitude in s16. The most-negative s16 has no positive s16
// representation and must be excluded by callers needing a nonnegative result.
s16 kq_abs_s16(s16 v);
// Select the smaller signed value.
s16 kq_min_s16(s16 a, s16 b);
// Select the larger signed value.
s16 kq_max_s16(s16 a, s16 b);
// Clamp to an inclusive interval; callers must provide lo <= hi.
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi);
// Test overlap using exclusive right/bottom edges; touching edges do not collide.
// Require positive dimensions and edge sums that fit s16; zero-sized rectangles
// are not explicitly rejected and may be reported as overlapping.
u8 kq_rect_intersect(KQRect a, KQRect b);
// Test a half-open rectangle: left/top edges are included, right/bottom excluded.
// The coordinate-plus-size sums must remain representable as s16.
u8 kq_point_in_rect(s16 x, s16 y, KQRect r);
#endifkitaqfc/lib/fixed.h
input.h — 按鈕狀態、按下、放開及重複
#ifndef INPUT_H
#define INPUT_H
#include "core.h"
#include "intrinsics.h"
// These are shared logical masks, not raw controller-register bit positions.
// input_update translates controller 1 before these masks are applied.
#define BTN_RIGHT ((u8)0x01)
#define BTN_LEFT ((u8)0x02)
#define BTN_UP ((u8)0x04)
#define BTN_DOWN ((u8)0x08)
#define BTN_A ((u8)0x10)
#define BTN_B ((u8)0x20)
#define BTN_SELECT ((u8)0x40)
#define BTN_START ((u8)0x80)
// A new press pulses immediately; the next pulse occurs DELAY + 1 input updates later.
#ifndef INPUT_REPEAT_DELAY
#define INPUT_REPEAT_DELAY ((u8)18)
#endif
// Later pulses occur RATE + 1 updates apart; zero repeats on each held update.
#ifndef INPUT_REPEAT_RATE
#define INPUT_REPEAT_RATE ((u8)5)
#endif
extern u8 kq_input_prev_keys;
extern u8 kq_input_keys;
extern u8 kq_input_press_keys;
extern u8 kq_input_release_keys;
extern u8 kq_input_repeat_keys;
// Clear held/edge/repeat masks and reset each independent repeat countdown.
void input_init(void);
// Read controller 1 through the safe intrinsic, translate its bit order and
// derive press/release edges. Repeat delays count calls to this function, so
// call it once per intended input tick.
void input_update(void);
// Return true when any masked logical button is held.
u8 input_down(u8 mask);
// Return true when any masked button became pressed in the latest input update.
u8 input_pressed(u8 mask);
// Return true when any masked button became released in the latest update.
u8 input_released(u8 mask);
// Return true for a masked initial press or scheduled repeat pulse.
u8 input_repeat(u8 mask);
// Read the complete translated held-button mask.
u8 input_current(void);
// Read the translated held-button mask from before the latest update.
u8 input_previous(void);
#define btn_down input_down
#define btn_pressed input_pressed
#define btn_released input_released
#define btn_repeat input_repeat
#endifkitaqfc/lib/input.h
input_repeat.h — 長按重複輸入
/*
* Optional declarations for the phase 9 NES pad repeat helper.
*
* Button bit layout:
* bit0=A bit1=B bit2=Select bit3=Start bit4=Up bit5=Down bit6=Left bit7=Right
*/
extern unsigned char nes_pad_repeat_delay;
extern unsigned char nes_pad_repeat_interval;
extern unsigned char nes_pad1_repeat;
// Set initial/repeat countdowns and clear repeat output. Zero countdowns are
// allowed and cause a repeat on the next held-button step.
// A fresh press emits immediately. Held repeats follow after delay+1 and then interval+1 steps.
// These are call counts, not milliseconds; use one fresh pad poll before each step.
void nes_pad_repeat_config(unsigned char delay, unsigned char interval);
// Generate per-button repeat bits from the most recently polled pad state.
// Poll first, then call once per tick; a countdown reaching zero emits on the
// following step, so an interval N leaves N decrement steps between pulses.
void nes_pad_repeat_step(void);
// Return the requested newly-pressed bits, not a normalized Boolean.
unsigned char nes_pad_trigger(unsigned char mask);
// Return the requested repeat-pulse bits from the latest repeat step.
unsigned char nes_pad_repeat(unsigned char mask);
// Return the requested newly-released bits from the latest pad poll.
unsigned char nes_pad_release(unsigned char mask);
// Return the requested currently-held bits in the NES pad layout.
unsigned char nes_pad_held(unsigned char mask);kitaqfc/lib/input_repeat.h
intrinsics.h — 編譯器內建函式
#ifndef INTRINSICS_H
#define INTRINSICS_H
/*
* FC/NES native intrinsic API.
* This header intentionally does not expose KITAQGB/CGB compatibility stubs.
* The compiler recognizes these names and emits 6502-oriented code or
* calls an internal 6502 helper generated by the backend.
*/
// Direct PPU operations require caller-controlled access timing. Generated helpers share runtime
// argument/scratch storage: do not assume calls are reentrant across NMI or IRQ handlers.
typedef unsigned char u8;
typedef unsigned short u16;
/* memory / bit / math */
// Copy len bytes forward between readable/writable CPU ranges; overlapping copies are not memmove.
// Zero length performs no memory transfer; argument side effects are evaluated before expansion.
void __memcpy(u8* dst, const u8* src, u16 len);
// Fill len CPU bytes with value. Zero length still evaluates argument side effects.
void __memset(u8* dst, u8 value, u16 len);
// Forward copy with an 8-bit length, zero through 255; the dynamic helper promotes it to a word count.
void __memcpy_small(u8* dst, const u8* src, u8 len);
// Fill zero through 255 CPU bytes; this is ordinary RAM access, not a PPU transfer.
void __memset_small(u8* dst, u8 value, u8 len);
// Copy exactly 16 bytes forward; both ranges must be valid and suitably non-overlapping.
void __copy16(u8* dst, const u8* src);
// Copy exactly 32 bytes forward; bank selection and source lifetime belong to the caller.
void __copy32(u8* dst, const u8* src);
// Return 0 or 1 for half-open bounds. Zero extents are empty; coordinates do not wrap across 255.
u8 __xy_in_rect(u8 x, u8 y, u8 rx, u8 ry, u8 rw, u8 rh);
// Return abs(x1-x2)+abs(y1-y2) modulo 256; large distances are not saturated.
u8 __manhattan(u8 x1, u8 y1, u8 x2, u8 y2);
// Return y*width+x as a word without checking coordinates against map dimensions.
u16 __map_index(u8 x, u8 y, u8 width);
// Replace both persistent state bytes. Reusing a seed reproduces the sequence; this is not cryptographic randomness.
void __rng_seed(u16 seed);
// Advance the shared 16-bit LFSR and return the XOR of its two bytes; zero state is reseeded to A55A.
u8 __rng8(void);
// Return base[bit>>3] & (1<<(bit&7)): zero or the bit mask, not a normalized Boolean.
u8 __bit_test(u8* base, u16 bit);
// Set the indexed bit in caller storage without changing the other seven bits in that byte.
void __bit_set(u8* base, u16 bit);
// Clear the indexed bit in caller storage; no bounds check or interrupt exclusion is inserted.
void __bit_clear(u8* base, u16 bit);
// XOR the indexed bit in caller storage; coordinate concurrent writers to avoid lost updates.
void __bit_toggle(u8* base, u16 bit);
// Return the high byte of the unsigned 8-by-8 product, equivalent to floor(a*b/256).
u8 __mul8x8_hi(u8 a, u8 b);
// Return the low word of the unsigned product; overflow wraps without saturation.
u16 __mul16x8(u16 a, u8 b);
// Interpret a and b as signed two's-complement bit patterns and return the low word of their product.
u16 __smul16x8(u16 a, u8 b);
// Return acc+a*b modulo 65536 using unsigned multiplication.
u16 __mac16(u16 acc, u16 a, u8 b);
// Add the signed-pattern product to acc modulo 65536; the API carries the result as u16 bits.
u16 __smac16(u16 acc, u16 a, u8 b);
// FC alias of __smul16x8: signed-pattern raw product, with no Q1.7 scaling shift.
u16 __smul16x8_q1_7(u16 a, u8 b);
// FC alias of __smac16: accumulate a raw signed-pattern product modulo 65536.
u16 __smac16_q1_7(u16 acc, u16 a, u8 b);
// Return a0*b0+a1*b1 modulo 65536. The FC backend inserts no Q8.8 rescaling or rounding.
u16 __dot2_q8_8(u16 a0, u16 a1, u8 b0, u8 b1);
// Sum three unsigned word-by-byte products modulo 65536 without a final scaling shift.
u16 __dot3_q8_8(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
// Sum two signed-pattern products modulo 65536; no Q8.8 scaling shift is generated.
u16 __sdot2_q8_8(u16 a0, u16 a1, u8 b0, u8 b1);
// Sum three signed-pattern products modulo 65536; choose operand units explicitly in the caller.
u16 __sdot3_q8_8(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
// FC alias of __sdot2_q8_8: two raw signed-pattern products, summed without rescaling.
u16 __sdot2_q1_7(u16 a0, u16 a1, u8 b0, u8 b1);
// FC alias of __sdot3_q8_8: three raw signed-pattern products, summed without rescaling.
u16 __sdot3_q1_7(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
/* PRG bank */
// Resolve a symbol or function placement to its byte bank number at compilation time.
u8 __bankof(u16 symbol_or_function);
// Select the mapper-specific PRG bank; the common bank and legal bank range depend on the target board.
void __bankswitch(u8 bank);
// Use the same mapper PRG-switch helper as __bankswitch; retain executable code in a valid mapping.
void __prg_bank_set(u8 bank);
// Call a declared zero-argument function; placement selects its bank and its declared type determines the result.
u8 __farcall(u8 bank, u16 func);
// Switch to the source bank, copy len bytes forward and restore the previous bank.
// Keep destination RAM and helper code accessible throughout; overlapping copies are not memmove.
void __far_memcpy(u8* dst, u8 bank, u16 src, u16 len);
// Temporarily select bank, read one byte at addr and restore the prior bank mapping.
u8 __farpeek8(u8 bank, u16 addr);
// Temporarily select bank and read a little-endian word, then restore the previous mapping.
u16 __farpeek16(u8 bank, u16 addr);
/* PPU / VRAM */
// Invoke the compiler rendering-enable helper; this header contains declarations, not C fallback implementations.
void __ppu_on(void);
// Invoke the compiler rendering-disable helper before bulk direct PPU updates.
void __ppu_off(void);
// Replace PPUMASK with the supplied byte; the caller chooses rendering, clipping and emphasis bits.
void __ppu_mask_set(u8 value);
// Replace PPUCTRL, including NMI enable, pattern-table choices and address increment mode.
void __ppu_ctrl_set(u8 value);
// Read the software PPUCTRL/PPUMASK shadows; use the setters for coherent state.
// Raw writes to $2000/$2001 bypass these shadows. No PPU hardware read occurs.
u8 __ppu_ctrl_get(void);
u8 __ppu_mask_get(void);
// Set the PPU address through the compiler helper; address writes affect the shared scroll/address latch.
void __ppu_addr(u16 ppu_addr);
// Write one PPUDATA byte using the current PPU address and increment mode.
void __ppu_data(u8 value);
// Read PPUSTATUS; the hardware clears VBlank status and resets the shared write latch.
u8 __ppu_read_status(void);
// Read PPUSTATUS to reset the scroll/address write latch; the read also clears VBlank status.
void __scroll_latch_reset(void);
// Save X/Y in runtime shadows, reset the PPU latch and write both scroll bytes immediately.
void __scroll_set(u8 x, u8 y);
// Replace saved X and write an X/Y pair using the retained Y shadow.
void __scroll_x_set(u8 x);
// Replace saved Y and write an X/Y pair using the retained X shadow.
void __scroll_y_set(u8 y);
// Write a byte-counted source range directly; arrange PPU access timing and source-bank visibility.
void __vram_write(u16 ppu_addr, const u8* src, u8 len);
// Write repeated bytes directly; this is not an enqueue operation.
void __vram_fill(u16 ppu_addr, u8 value, u8 len);
// Write one tile directly at 2000+y*32+x; use x<32, y<30 for visible nametable cells.
void __nametable_put(u8 x, u8 y, u8 tile);
// Write one tile in nametable nt&3. Mirroring can alias logical nametables; coordinates are unchecked.
void __nametable_put_nt(u8 nt, u8 x, u8 y, u8 tile);
// Fill rows of nametable zero directly, advancing each row start by 32 bytes.
// Keep the rectangle in bounds and use PPU increment one; this does not enqueue or clip.
void __nametable_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
// Fill a rectangle in nametable nt&3 with the same unchecked, direct-write row loop.
void __nametable_rect_nt(u8 nt, u8 x, u8 y, u8 w, u8 h, u8 tile);
// Write the entire packed attribute byte at 23C0+(y>>2)*8+(x>>2).
// Use tile coordinates below 32; this does not merge a single palette quadrant.
void __attr_set(u8 x, u8 y, u8 attr);
// Write a whole packed attribute byte in nametable nt&3; other quadrant fields are overwritten.
void __attr_set_nt(u8 nt, u8 x, u8 y, u8 attr);
// Stream exactly 16 source bytes to 3F00. Arrange PPU access timing and increment one.
void __palette_bg_load(const u8* pal16);
// Stream exactly 16 source bytes to 3F10; hardware palette aliases also affect background entries.
void __palette_sp_load(const u8* pal16);
/* NMI VRAM transfer queue. Queue entries are consumed by __vramq_exec(),
* and the default NMI handler calls __vramq_exec() automatically.
*/
// Reset pending intrinsic-queue records; this is separate from runtime.c nes_vram_queue_clear.
void __vramq_clear(void);
// Append one address/value update; use the overflow latch to detect capacity failure.
void __vramq_put(u16 ppu_addr, u8 value);
// Retain the source address for later consumption; keep its storage and bank mapping valid.
void __vramq_copy(u16 ppu_addr, const u8* src, u8 len);
// Append a repeated-byte update; the source value is stored in the record.
void __vramq_fill(u16 ppu_addr, u8 value, u8 len);
// Publish the pending records to the configured consumer. Do not mutate them while consumption can run.
void __vramq_commit(void);
// Execute a ready queue directly; committing and safe PPU timing are caller responsibilities.
void __vramq_exec(void);
// Return encoded bytes currently occupied, not transfer payload bytes or command count.
u8 __vramq_len(void);
// Read the latched capacity failure; reading does not reset it.
u8 __vramq_overflow(void);
// Clear the overflow latch explicitly after handling the failed submission.
void __vramq_clear_overflow(void);
// Return total encoded command-buffer capacity; this is independent of PPU VRAM capacity.
u8 __vramq_capacity(void);
/* NMI / IRQ */
// Spin until the runtime NMI counter changes; the configured handler must advance it. No timeout is emitted.
void __nmi_wait(void);
// Return the current wrapping NMI counter byte, not a Boolean ready flag.
u8 __nmi_ready(void);
// Set bit 7 in the PPUCTRL shadow and write it to hardware, preserving the other shadow bits.
void __nmi_enable(void);
// Clear bit 7 in the PPUCTRL shadow and write it to hardware; CPU IRQ masking is separate.
void __nmi_disable(void);
// Emit SEI to mask CPU IRQs; NMI is unaffected.
void __irq_disable(void);
// Emit CLI to unmask CPU IRQs; the caller must have a valid interrupt handler.
void __irq_enable(void);
// Return the processor-status byte captured before SEI. Pass that byte to __irq_restore.
u8 __irq_save(void);
// Restore processor status with PLP, including arithmetic flags and the saved IRQ mask.
void __irq_restore(u8 state);
/* OAM / input */
// Set OAMADDR to zero and start DMA from CPU page 02; arrange safe PPU timing in the caller.
void __oam_dma(void);
// Set OAMADDR to zero and DMA 256 bytes from page<<8. The source page must remain readable.
void __oam_dma_page(u8 page);
// Hide all 64 page-02 shadow sprites by writing Y=F0; hardware OAM changes only after DMA.
void __oam_clear(void);
// Write Y, tile, attributes and X to one shadow entry. Use indices 0..63; coordinates are raw OAM bytes.
void __sprite_set(u8 index, u8 x, u8 y, u8 tile, u8 attr);
// Replace only shadow X/Y for index 0..63; tile and attribute bytes remain unchanged.
void __sprite_move(u8 index, u8 x, u8 y);
// Replace the selected shadow tile byte; this does not upload tile patterns.
void __sprite_tile(u8 index, u8 tile);
// Replace the selected shadow attribute byte, including palette, priority and flip bits.
void __sprite_attr(u8 index, u8 attr);
// Write F0 to the selected shadow Y byte; issue DMA to make the change visible.
void __sprite_hide(u8 index);
// Expand dx,dy,tile,attr records into page-02 shadow OAM until dx=FF; return the next index.
// Coordinates and the byte OAM cursor wrap; keep the terminated stream within the available slots.
u8 __metasprite_draw(u8 oam_index, u8 base_x, u8 base_y, const u8* metasprite);
// Latch and sample eight D0 bits from port 1; bit order is A,B,Select,Start,Up,Down,Left,Right.
u8 __pad_read1(void);
// Latch and sample eight D0 bits from port 2 in the same NES button order.
u8 __pad_read2(void);
// Repeat pairs of port-1 polls until both bytes match; the retry loop has no fixed limit.
u8 __pad_read1_safe(void);
// Repeat pairs of port-2 polls until both bytes match; this does not populate pad.c globals.
u8 __pad_read2_safe(void);
// Return pad & 0F for A/B/Select/Start; this masks a supplied snapshot and performs no polling.
u8 __pad_buttons(u8 pad);
// Return pad & F0 in the original bit positions; this does not normalize directions to bits 0..3.
u8 __pad_dirs(u8 pad);
/* Famicom/NES expansion input devices.
* D1 readers are for expansion-port controllers/joysticks that expose a
* standard 8-bit joypad stream on data line D1 instead of D0.
* __joypad2p_voice() / __mic_read2p() return the Famicom 2P microphone bit.
*/
// Latch and read an eight-button stream from port-1 data line D1 rather than D0.
u8 __pad_read1_d1(void);
// Latch and read an eight-button stream from port-2 data line D1 rather than D0.
u8 __pad_read2_d1(void);
// Alias the port-1 D1 controller reader; the attached device must use the expected serial protocol.
u8 __exp_pad_read1(void);
// Alias the port-2 D1 controller reader; this is not an expansion-device discovery operation.
u8 __exp_pad_read2(void);
// Return controller-port 4016 bit 2 normalized to 0 or 1; this is a microphone level bit, not PCM audio.
u8 __joypad2p_voice(void);
// Alias the same normalized microphone input bit as __joypad2p_voice.
u8 __mic_read2p(void);
/* Zapper / light gun. The no-suffix names default to the usual port-2/Famicom
* expansion-port mapping. __zapper_light*() returns 1 when light is detected.
*/
// Return raw 4016 & 18, retaining trigger and active-low light bits.
u8 __zapper_raw1(void);
// Return raw 4017 & 18 for the second port.
u8 __zapper_raw2(void);
// Return port-1 trigger bit 4 normalized to 0 or 1.
u8 __zapper_trigger1(void);
// Return port-2 trigger bit 4 normalized to 0 or 1.
u8 __zapper_trigger2(void);
// Invert port-1 bit 3 and normalize: one means light detected.
u8 __zapper_light1(void);
// Invert port-2 bit 3 and normalize: one means light detected.
u8 __zapper_light2(void);
// Default to the port-2 normalized trigger reader.
u8 __zapper_trigger(void);
// Default to the port-2 normalized light reader.
u8 __zapper_light(void);
/* Family BASIC Keyboard. __fkb_scan() writes 18 bytes: 9 rows x 2 columns,
* each byte containing raw $4017 & 0x1E for that row/column.
*/
// Probe selected-row and disabled-matrix bit patterns and return 0 or 1; this is a heuristic detection.
u8 __fkb_detect(void);
// Write 18 raw masked samples (4017 & 1E), two per row, to caller storage; reset 4016 afterward.
void __fkb_scan(u8* dst18);
// Select a matrix row and the low bit of col, then return raw 4017 & 1E.
// Use rows 0..8 for keys; row 9 is used by detection. No row-range validation is emitted.
u8 __fkb_read_row_col(u8 row, u8 col);
/* R.O.B. / Famicom Robot optical flash primitives. These are timing primitives;
* game-specific command sequences should be built on top of __rob_pulse() or
* __rob_send_byte().
*/
// Set PPUMASK and its shadow to 1E or 00, then wait for an NMI-counter change.
// The caller supplies image/palette brightness; rendering enable alone does not create a white screen.
void __rob_flash(u8 bright);
// Run on_frames enabled-mask waits followed by off_frames disabled-mask waits; NMI must advance.
void __rob_pulse(u8 on_frames, u8 off_frames);
// Send eight bits MSB first: one uses 4 on/2 off waits; zero uses 2 on/4 off.
// Requires an advancing runtime NMI counter; 48 waits in total, final PPUMASK=0.
// This raw pattern does not add a robot command preamble or validate reception.
void __rob_send_byte(u8 pattern);
/* Expansion-port TTL serial / MIDI adapter support.
* The low-level serial layer assumes an external adapter that maps OUT0 to TX
* and D4 on $4017 to RX. MIDI helpers bit-bang 8N1 bytes at an approximate
* 31250 bps timing suitable for adapter bring-up and simple music sync.
*/
// Write bit & 1 to 4016, replacing the port output value; coordinate with other port users.
void __serial_tx_bit(u8 bit);
// Read 4017 bit 4 and normalize it to 0 or 1; an external serial adapter supplies the signal.
u8 __serial_rx_bit(void);
// Send start-low, eight least-significant-first bits and stop-high in 57-cycle
// NTSC bit cells (about 31400 bps). Stop DMC DMA and mask IRQ/NMI during transfers;
// PAL timing and electrical adapter compatibility are not established here.
void __midi_out_byte(u8 byte);
// Block for a low start signal and sample eight bits. No timeout, framing check or receive buffer is provided.
u8 __midi_in_byte(void);
// Send 90|(ch&0F), note and velocity. Supply 7-bit data bytes; they are not masked by this helper.
void __midi_note_on(u8 ch, u8 note, u8 velocity);
// Send 80|(ch&0F), note and velocity through the same synchronous serial path.
void __midi_note_off(u8 ch, u8 note, u8 velocity);
// Send B0|(ch&0F), controller and value; both data arguments must be valid 7-bit values.
void __midi_control_change(u8 ch, u8 cc, u8 value);
// Send C0|(ch&0F) followed by the caller-supplied 7-bit program value.
void __midi_program_change(u8 ch, u8 program);
// Transmit the single realtime byte F8 synchronously; this does not schedule future ticks.
void __midi_clock(void);
// Transmit realtime Start (FA) through the serial adapter path.
void __midi_start(void);
// Transmit realtime Continue (FB) through the serial adapter path.
void __midi_continue(void);
// Transmit realtime Stop (FC) through the serial adapter path.
void __midi_stop(void);
/* Mapper */
// Return the low byte of the mapper number selected for this build; no cartridge probe is performed.
u8 __mapper_id(void);
// Select a CNROM bank or MMC3 register 0 bank; unsupported mapper profiles produce a compile error.
void __chr_bank_set(u8 bank);
// Use the same CNROM/MMC3 register 0 selection as __chr_bank_set.
void __chr_bank_set0(u8 bank);
// Select MMC3 register 1, or the same full CNROM bank register; this is mapper-specific banking.
void __chr_bank_set1(u8 bank);
// Emit the selected mapper mirroring operation; available modes and writable control depend on the board.
void __mirroring_set(u8 mode);
// Write the MMC3 IRQ latch and reload registers. This does not enable IRQ delivery.
void __irq_scanline_set(u8 line);
// Alias the MMC3 IRQ latch/reload operation; other mapper profiles are rejected.
void __mapper_irq_set(u8 scanline);
// Write MMC3 E001. The CPU IRQ mask and a valid handler are separate caller responsibilities.
void __mapper_irq_enable(void);
// Write MMC3 E000 to disable and acknowledge mapper IRQs.
void __mapper_irq_disable(void);
// Use the same E000 write as disable; explicitly re-enable when another interrupt is needed.
void __mapper_irq_ack(void);
// Wait for the current hit flag to clear, then for a new hit. No timeout is provided.
void __sprite0_wait_hit(void);
// Wait for a new sprite-zero hit, reset the PPU latch and write X/Y scroll; requires a visible hit setup.
void __split_scroll_sprite0(u8 x, u8 y);
/* FDS. Status and sound primitives are emitted on --mapper=fds.
* File/overlay APIs use the FDS BIOS direct-pointer routines. __fds_load_file()
* and __fds_load_overlay() load to the destination encoded in the disk file
* header. __fds_file_exists() and __fds_file_size() are side-effect-free when
* a disk-builder manifest is supplied with --fds-meta / --fds-manifest.
*/
// Return the compile-time FDS mapper selection as 0 or 1; this is not a hardware probe.
u8 __fds_available(void);
// Return the inverted disk-absent bit from 4032 as 0 or 1; this checks presence, not transfer completion.
u8 __fds_disk_ready(void);
// Return raw status mask 4032 & 04, either 0 or 4. This is not a numbered disk-side identifier.
u8 __fds_side(void);
// Read the entire 4030 status register; this is not a stored BIOS error code.
u8 __fds_error(void);
// Poll disk presence until the absent bit clears. There is no timeout or cancellation path.
void __fds_wait_ready(void);
// Alias the same disk-presence wait as __fds_wait_ready; the call can block indefinitely.
void __fds_wait_insert(void);
// Native FDS32: load a non-boot file at its disk-header address, then memmove
// PRG bytes to dst. Null dst keeps the native destination (also for PPU files).
// Both CPU spans must fit $0200-$07FF or $6000-$DFFF and be owned by the caller.
// Return 0, a BIOS error, $40 for a missing transfer, or $FF for invalid input.
// Call from common code with disk-I/O interrupt/display prerequisites satisfied.
u8 __fds_load_file(u8 id, u8* dst);
// Overwrite the final non-boot PRG slot on its side, preserving its ID/name/load
// address. len must equal its packaged size; src must be a valid CPU RAM span.
// The resolved physical ordinal selects the slot, independently of file ID.
// Return 0, a BIOS error, or $FF before any write for an invalid slot/span/size.
u8 __fds_save_file(u8 id, const u8* src, u16 len);
// Load disk file id through BIOS, return its error byte and mark bank residency FF (unknown).
u8 __fds_load_overlay(u8 id);
// Load logical bank 1 from its separate boot file, or bank 2+ from overlay-start-id+(bank-2).
// Return zero on success, FF for invalid/unavailable mappings, or the BIOS error.
// A failed BIOS transfer marks residency FF (unknown); a matching valid guard can skip loading.
u8 __fds_load_bank(u8 bank);
// Return zero when the software residency record matches, otherwise call __fds_load_bank.
u8 __fds_require_bank(u8 bank);
// Return the software resident-bank byte, or FF after a failed bank transfer.
// This is not a checksum of overlay memory.
u8 __fds_current_bank(void);
// Compare a valid bank with the software resident-bank byte; FF (unknown) never matches.
u8 __fds_is_bank_resident(u8 bank);
// Return the linker-generated overlay-function count; zero if the table is disabled.
u8 __fds_overlay_function_count(void);
// Evaluate bank once and call the named zero-argument function using its linked bank.
// Restore the caller window before returning; restoration failure stops in common code.
u8 __fds_overlay_farcall(u8 bank, u16 func);
// Same named, zero-argument dispatch as __fds_overlay_farcall; evaluate bank once.
u8 __fds_farcall(u8 bank, u16 func);
// Query the compiled --fds-meta/--fds-manifest table, not the inserted disk; return 0 or 1.
u8 __fds_file_exists(u8 id);
// Return the compiled metadata size, or zero if id is absent. No disk directory is read.
u16 __fds_file_size(u8 id);
// Write 83 to 4023 and zero to 4089/408A to initialize disk/sound register gates.
void __fds_sound_enable(void);
// Copy exactly 64 readable bytes to wave RAM with wave writes enabled, then set 4089 to zero.
void __fds_wave_load(const u8* wave);
// Stream 32 readable bytes to 4088; the caller prepares modulation state and write conditions.
void __fds_mod_load(const u8* mod);
// Write a 12-bit frequency to 4082/4083; upper control bits in 4083 are cleared.
void __fds_freq_set(u16 freq);
// Write (volume & 3F) | 80 to 4080 for direct volume control; masking wraps, rather than clamps.
void __fds_volume_set(u8 volume);
// Write the three raw arguments to 4080, 4084 and 408A in that order.
// The legacy parameter names do not describe three independently packed envelope fields.
void __fds_env_set(u8 a, u8 b, u8 c);
#endifkitaqfc/lib/intrinsics.h
keyboard.h — 鍵盤掃描
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include "intrinsics.h"
// Probe selected-row and disabled-matrix bit patterns and return 0 or 1; this is a heuristic detection.
u8 __fkb_detect(void);
// Write 18 raw masked samples (4017 & 1E), two per row, to caller storage; reset 4016 afterward.
void __fkb_scan(u8* dst18);
// Select a matrix row and the low bit of col, then return raw 4017 & 1E.
// Use rows 0..8 for keys; row 9 is used by detection. No row-range validation is emitted.
u8 __fkb_read_row_col(u8 row, u8 col);
#endifkitaqfc/lib/keyboard.h
mapper.h — Mapper bank 與 IRQ
#ifndef MAPPER_H
#define MAPPER_H
#include "intrinsics.h"
// Resolve a symbol or function placement to its byte bank number at compilation time.
u8 __bankof(u16 symbol_or_function);
// Select the mapper-specific PRG bank; the common bank and legal bank range depend on the target board.
void __bankswitch(u8 bank);
// Use the same mapper PRG-switch helper as __bankswitch; retain executable code in a valid mapping.
void __prg_bank_set(u8 bank);
// Invoke the compiler banked-call path; target placement and calling convention must match the selected mapper.
u8 __farcall(u8 bank, u16 func);
// Switch to the source bank, copy len bytes forward and restore the previous bank.
// Keep destination RAM and helper code accessible throughout; overlapping copies are not memmove.
void __far_memcpy(u8* dst, u8 bank, u16 src, u16 len);
// Temporarily select bank, read one byte at addr and restore the prior bank mapping.
u8 __farpeek8(u8 bank, u16 addr);
// Temporarily select bank and read a little-endian word, then restore the previous mapping.
u16 __farpeek16(u8 bank, u16 addr);
// Return the low byte of the mapper number selected for this build; no cartridge probe is performed.
u8 __mapper_id(void);
// Select a CNROM bank or MMC3 register 0 bank; unsupported mapper profiles produce a compile error.
void __chr_bank_set(u8 bank);
// Use the same CNROM/MMC3 register 0 selection as __chr_bank_set.
void __chr_bank_set0(u8 bank);
// Select MMC3 register 1, or the same full CNROM bank register; this is mapper-specific banking.
void __chr_bank_set1(u8 bank);
// Emit the selected mapper mirroring operation; available modes and writable control depend on the board.
void __mirroring_set(u8 mode);
// Write the MMC3 IRQ latch and reload registers. This does not enable IRQ delivery.
void __irq_scanline_set(u8 line);
// Alias the MMC3 IRQ latch/reload operation; other mapper profiles are rejected.
void __mapper_irq_set(u8 scanline);
// Write MMC3 E001. The CPU IRQ mask and a valid handler are separate caller responsibilities.
void __mapper_irq_enable(void);
// Write MMC3 E000 to disable and acknowledge mapper IRQs.
void __mapper_irq_disable(void);
// Use the same E000 write as disable; explicitly re-enable when another interrupt is needed.
void __mapper_irq_ack(void);
// Wait for the current hit flag to clear, then for a new hit. No timeout is provided.
void __sprite0_wait_hit(void);
// Wait for a new sprite-zero hit, reset the PPU latch and write X/Y scroll; requires a visible hit setup.
void __split_scroll_sprite0(u8 x, u8 y);
#endifkitaqfc/lib/mapper.h
math_fast.h — 快速整數運算
#ifndef MATH_FAST_H
#define MATH_FAST_H
#include "intrinsics.h"
/*
* Fast math primitives are compiler intrinsics. These declarations are kept
* here so game code can include a game-facing math header instead of the full
* intrinsic surface.
*/
// Return abs(x1-x2)+abs(y1-y2) modulo 256; large distances are not saturated.
u8 __manhattan(u8 x1, u8 y1, u8 x2, u8 y2);
// Return 0 or 1 for half-open bounds. Zero extents are empty; coordinates do not wrap across 255.
u8 __xy_in_rect(u8 x, u8 y, u8 rx, u8 ry, u8 rw, u8 rh);
// Return y*width+x as a word without checking coordinates against map dimensions.
u16 __map_index(u8 x, u8 y, u8 width);
// Advance the shared 16-bit LFSR and return the XOR of its two bytes; zero state is reseeded to A55A.
u8 __rng8(void);
// Replace both persistent state bytes. Reusing a seed reproduces the sequence; this is not cryptographic randomness.
void __rng_seed(u16 seed);
#endifkitaqfc/lib/math_fast.h
math_fixed.h — 定點數內建介面
#ifndef MATH_FIXED_H
#define MATH_FIXED_H
#include "intrinsics.h"
/* Fixed-point helpers are compiler-recognized intrinsic entry points. */
// Return the high byte of the unsigned 8-by-8 product, equivalent to floor(a*b/256).
u8 __mul8x8_hi(u8 a, u8 b);
// Return the low word of the unsigned product; overflow wraps without saturation.
u16 __mul16x8(u16 a, u8 b);
// Interpret a and b as signed two's-complement bit patterns and return the low word of their product.
u16 __smul16x8(u16 a, u8 b);
// Return acc+a*b modulo 65536 using unsigned multiplication.
u16 __mac16(u16 acc, u16 a, u8 b);
// Add the signed-pattern product to acc modulo 65536; the API carries the result as u16 bits.
u16 __smac16(u16 acc, u16 a, u8 b);
// Return a0*b0+a1*b1 modulo 65536. The FC backend inserts no Q8.8 rescaling or rounding.
u16 __dot2_q8_8(u16 a0, u16 a1, u8 b0, u8 b1);
// Sum three unsigned word-by-byte products modulo 65536 without a final scaling shift.
u16 __dot3_q8_8(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
// Sum two signed-pattern products modulo 65536; no Q8.8 scaling shift is generated.
u16 __sdot2_q8_8(u16 a0, u16 a1, u8 b0, u8 b1);
// Sum three signed-pattern products modulo 65536; choose operand units explicitly in the caller.
u16 __sdot3_q8_8(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
#endifkitaqfc/lib/math_fixed.h
math_lut.h — 查找表
#ifndef MATH_LUT_H
#define MATH_LUT_H
// Uniform 256-phase unsigned sine table in ROM. Range 1..255, centered at 128.
// Link math_lut.c once; indices 0..255 are valid and byte phase wrap is supported.
extern unsigned char MATH_SIN[256];
#endifkitaqfc/lib/math_lut.h
metasprite.h — 由多個精靈組成的圖像
/*
* Optional declarations for the phase 10 NES metasprite helper.
*
* Metasprite data layout:
* [dx, dy, tile, attr] repeated, terminated by dx=0xFF
*/
// Read four-byte records [dx,dy,tile,attr] until dx=0xFF, writing them to
// shadow OAM. Coordinates and destination offsets wrap as bytes. The caller
// must supply a terminator and enough unused slots; there is no capacity guard.
// Return the next slot index derived from the final wrapped byte offset.
unsigned char nes_metasprite_draw(unsigned char oam_index, unsigned char base_x, unsigned char base_y, unsigned char* metasprite);
// Compiler intrinsic counterpart; this declaration does not route through the C function above.
unsigned char __metasprite_draw(unsigned char oam_index, unsigned char base_x, unsigned char base_y, const unsigned char* metasprite);
// Hide consecutive shadow slots by setting Y to 0xF8. Keep the requested
// range within 64 slots to avoid wrapping and hiding earlier entries.
void nes_metasprite_hide_from(unsigned char oam_index, unsigned char sprite_count);kitaqfc/lib/metasprite.h
mic.h — 麥克風輸入
#ifndef MIC_H
#define MIC_H
#define VOICE_H
#include "intrinsics.h"
// Return controller-port 4016 bit 2 normalized to 0 or 1; this is a microphone level bit, not PCM audio.
u8 __joypad2p_voice(void);
// Alias the same normalized microphone input bit as __joypad2p_voice.
u8 __mic_read2p(void);
#endifkitaqfc/lib/mic.h
midi.h — MIDI 輸入輸出介面
#ifndef MIDI_H
#define MIDI_H
#include "intrinsics.h"
// Write bit & 1 to 4016, replacing the port output value; coordinate with other port users.
void __serial_tx_bit(u8 bit);
// Read 4017 bit 4 and normalize it to 0 or 1; an external serial adapter supplies the signal.
u8 __serial_rx_bit(void);
// Send start-low, eight least-significant-first bits and stop-high using fixed NOP delays.
// Instruction and interrupt overhead is additional; the emitted loop does not establish a verified MIDI baud rate.
void __midi_out_byte(u8 byte);
// Block for a low start signal and sample eight bits. No timeout, framing check or receive buffer is provided.
u8 __midi_in_byte(void);
// Send 90|(ch&0F), note and velocity. Supply 7-bit data bytes; they are not masked by this helper.
void __midi_note_on(u8 ch, u8 note, u8 velocity);
// Send 80|(ch&0F), note and velocity through the same synchronous serial path.
void __midi_note_off(u8 ch, u8 note, u8 velocity);
// Send B0|(ch&0F), controller and value; both data arguments must be valid 7-bit values.
void __midi_control_change(u8 ch, u8 cc, u8 value);
// Send C0|(ch&0F) followed by the caller-supplied 7-bit program value.
void __midi_program_change(u8 ch, u8 program);
// Transmit the single realtime byte F8 synchronously; this does not schedule future ticks.
void __midi_clock(void);
// Transmit realtime Start (FA) through the serial adapter path.
void __midi_start(void);
// Transmit realtime Continue (FB) through the serial adapter path.
void __midi_continue(void);
// Transmit realtime Stop (FC) through the serial adapter path.
void __midi_stop(void);
#endifkitaqfc/lib/midi.h
nametable_asset.h — 名稱表素材與放置
/*
* Optional declarations for phase12 nametable / attribute asset helpers.
*/
extern unsigned char nes_attr_shadow[64];
// Mask the index to the four logical nametables and return its PPU base.
// Physical storage still depends on the cartridge's mirroring configuration.
unsigned short nes_nt_base_from_index(unsigned char index);
// Locate the 64-byte attribute table at offset 0x03C0 from a nametable base.
unsigned short nes_attr_base_from_nt(unsigned short nt_base);
// Fill all 64 shadow bytes with an already-packed attribute value.
void nes_attr_shadow_clear(unsigned char value);
// Copy an entire packed attribute table into shadow RAM without writing the PPU.
void nes_attr_shadow_copy(unsigned char* src64);
// Replace only the chosen quadrant's palette bits, preserving its neighbors.
// Palette IDs are masked to two bits; tile coordinates must fit the shadow table.
void nes_attr_shadow_set_quad(unsigned char tile_x, unsigned char tile_y, unsigned char pal_index);
// Upload all attribute shadow bytes immediately; the caller provides safe PPU timing.
void nes_attr_apply_now(unsigned short nt_base);
// Copy all shadow attribute bytes into the runtime queue and return its admission result.
unsigned char nes_attr_queue_all(unsigned short nt_base);
// Write one complete 32-tile row directly. The caller validates the row and PPU timing.
void nes_nt_stream_row(unsigned short nt_base, unsigned char row, unsigned char* src32);
// Copy one complete nametable row into the runtime queue.
unsigned char nes_nt_queue_row(unsigned short nt_base, unsigned char row, unsigned char* src32);
// Write each rectangle row immediately, advancing source by pitch rather than
// width. Caller-provided coordinates, storage and timing are not clipped or checked.
void nes_nt_stream_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src);
// Copy rows into the runtime queue until complete or full. Failure leaves
// earlier rows queued; it does not roll back a partially admitted rectangle.
// Widths must respect the queue literal-record limit.
// Pitch is source bytes per row. Each copied literal record costs width+3 queue bytes;
// check total admission needs when partial updates are unacceptable.
unsigned char nes_nt_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src);
// Queue one fill record per row, stopping on failure while retaining previously
// queued rows. The runtime fill-length and rectangle bounds requirements apply.
unsigned char nes_nt_queue_fill_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char value);
// Upload 960 tile bytes followed by 64 attribute bytes. This bulk operation
// does not disable rendering or wait for VBlank on its own.
void nes_nametable_apply_now(unsigned short nt_base, unsigned char* nam960, unsigned char* attr64);kitaqfc/lib/nametable_asset.h
nes_game.h — 遊戲操作巨集
#ifndef NES_GAME_H
#define NES_GAME_H
#include "core.h"
#include "intrinsics.h"
/*
* AI-friendly NES operation aliases.
*
* These names intentionally describe gameplay-side operations. They are thin
* aliases over KITAQFC intrinsics so the compiler can still record the exact
* NES action for diagnostics and KUROSAKI metadata.
*/
// These aliases use the compiler intrinsic queue. They do not select the separate C runtime queue.
#define nes_vram_put(addr, value) __vramq_put((addr), (value))
#define nes_vram_copy(addr, src, len) __vramq_copy((addr), (src), (len))
#define nes_vram_fill(addr, value, len) __vramq_fill((addr), (value), (len))
#define nes_vram_commit() __vramq_commit()
#define nes_vram_clear_queue() __vramq_clear()
#define nes_oam_clear() __oam_clear()
// This zero-argument macro hides the same-named page-argument C runtime function in included code.
#define nes_oam_dma() __oam_dma()
#define nes_sprite_set(i,x,y,t,a) __sprite_set((i),(x),(y),(t),(a))
#define nes_sprite_move(i,x,y) __sprite_move((i),(x),(y))
#define nes_sprite_hide(i) __sprite_hide((i))
// Select the compiler intrinsic implementation even when the C metasprite header is also included.
#define nes_metasprite_draw(i,x,y,data) __metasprite_draw((i),(x),(y),(data))
#define nes_pad1() __pad_read1_safe()
#define nes_pad2() __pad_read2_safe()
#define nes_mapper_irq_set(scanline) __mapper_irq_set((scanline))
#define nes_mapper_irq_enable() __mapper_irq_enable()
#define nes_mapper_irq_disable() __mapper_irq_disable()
#define nes_mapper_irq_ack() __mapper_irq_ack()
#define nes_split_scroll_sprite0(x,y) __split_scroll_sprite0((x),(y))
#define nes_fds_wave_load(wave64) __fds_wave_load((wave64))
#define nes_fds_load_bank(bank) __fds_load_bank((bank))
#define nes_fds_farcall(bank, func) __fds_overlay_farcall((bank), (func))
#endifkitaqfc/lib/nes_game.h
oam.h — OAM 影子緩衝區操作
#ifndef OAM_H
#define OAM_H
#include "intrinsics.h"
// Set OAMADDR to zero and start DMA from CPU page 02; arrange safe PPU timing in the caller.
void __oam_dma(void);
// Set OAMADDR to zero and DMA 256 bytes from page<<8. The source page must remain readable.
void __oam_dma_page(u8 page);
// Hide all 64 page-02 shadow sprites by writing Y=F0; hardware OAM changes only after DMA.
void __oam_clear(void);
// Write Y, tile, attributes and X to one shadow entry. Use indices 0..63; coordinates are raw OAM bytes.
void __sprite_set(u8 index, u8 x, u8 y, u8 tile, u8 attr);
// Replace only shadow X/Y for index 0..63; tile and attribute bytes remain unchanged.
void __sprite_move(u8 index, u8 x, u8 y);
// Replace the selected shadow tile byte; this does not upload tile patterns.
void __sprite_tile(u8 index, u8 tile);
// Replace the selected shadow attribute byte, including palette, priority and flip bits.
void __sprite_attr(u8 index, u8 attr);
// Write F0 to the selected shadow Y byte; issue DMA to make the change visible.
void __sprite_hide(u8 index);
#endifkitaqfc/lib/oam.h
oam_fair.h — 保留優先順序的精靈輪替
#ifndef KQ_OAM_FAIR_H
#define KQ_OAM_FAIR_H
#include "core.h"
/* 64-entry software sprite pool. Define the five arrays/cursor declared below
* and include oam_fair_impl.h in ONE translation unit, in a fixed PRG bank.
* X/Y are center coordinates, ACTIVE is a byte array. OAM is a 256-byte
* DMA shadow; USED is its byte cursor. Entries already in OAM stay first.
* The odd stride selects every starting entry over 64 calls. Hardware still
* has a 64-sprite / 8-sprite-per-scanline limit: this distributes flicker.
* Call only from the main loop; commit the completed OAM in VBlank.
*/
extern u8 oam_fair_phase;
extern u8 oam_fair_x[64];
extern u8 oam_fair_y[64];
extern u8 oam_fair_active[64];
extern u8 oam_fair_shadow[256];
extern u8 oam_fair_used;
extern u8 oam_fair_limit;
extern u8 oam_fair_tile;
extern u8 oam_fair_attr;
extern u8 oam_fair_drawn;
// Append active pool entries using the configured common tile/attributes. The emitter stops at byte cursor 252,
// leaving slot 63 unused to avoid cursor wrap. Hide unused trailing OAM entries separately before DMA.
void OAM_FairDraw(void);
#endifkitaqfc/lib/oam_fair.h
oam_fair_impl.h — 精靈輪替實作
#include "oam_fair.h"
u8 oam_fair_phase;
u8 oam_fair_limit;
u8 oam_fair_tile;
u8 oam_fair_attr;
u8 oam_fair_drawn;
u8 oam_fair_scanned;
// Rotate the starting pool entry by 13 modulo 64, then append active sprites
// until the caller's draw limit or OAM byte cursor limit is reached. Coordinates
// describe 8x8 centers: subtract four for X and five for raw OAM Y. Include once
// and invoke it from the main loop with a four-byte-aligned used cursor.
void OAM_FairDraw(void) {
__asm {
LDA oam_fair_phase
CLC
ADC #13
AND #63
STA oam_fair_phase
TAX
LDY oam_fair_used
LDA #0
STA oam_fair_drawn
STA oam_fair_scanned
// Visit each pool entry at most once, preserving already-written OAM entries
// and sharing the configured tile/attribute values across emitted sprites.
kq_fair_loop:
LDA oam_fair_active,X
BEQ kq_fair_next
LDA oam_fair_drawn
CMP oam_fair_limit
BCS kq_fair_done
// Reserve the final four-byte slot so advancing this byte cursor cannot wrap to zero.
CPY #252
BCS kq_fair_done
// Convert the 8x8 center to raw OAM coordinates; Y also needs the hardware minus-one bias.
LDA oam_fair_y,X
SEC
SBC #5
STA oam_fair_shadow,Y
LDA oam_fair_tile
STA oam_fair_shadow+1,Y
LDA oam_fair_attr
STA oam_fair_shadow+2,Y
LDA oam_fair_x,X
SEC
SBC #4
STA oam_fair_shadow+3,Y
INY
INY
INY
INY
INC oam_fair_drawn
// Advance cyclically and stop after returning to this frame's starting entry.
kq_fair_next:
TXA
CLC
ADC #1
AND #63
TAX
CPX oam_fair_phase
BNE kq_fair_loop
// Publish the updated byte cursor for later OAM writers and the VBlank DMA path.
kq_fair_done:
STY oam_fair_used
}
}kitaqfc/lib/oam_fair_impl.h
pad.h — NES 控制器輸入
/*
* Optional declarations for the phase 8 NES pad runtime.
*
* Button bit layout in nes_pad1_cur / pressed / released:
* bit0=A bit1=B bit2=Select bit3=Start bit4=Up bit5=Down bit6=Left bit7=Right
*/
extern unsigned char nes_pad1_cur;
extern unsigned char nes_pad1_prev;
extern unsigned char nes_pad1_pressed;
extern unsigned char nes_pad1_released;
// Latch controller input with a 1-to-0 strobe and shift eight controller-1 bits
// into held/pressed/released masks. This direct path does not perform repeated
// reads for DMC interference; the final JOY2 read does not populate player-2 state.
void nes_pad_poll(void);kitaqfc/lib/pad.h
palette.h — NES 調色盤
/*
* Optional declarations for the phase 11 NES palette helper.
*/
extern unsigned char nes_palette_shadow[32];
// Copy exactly 32 palette bytes to the fixed shadow buffer without writing the PPU.
void nes_palette_copy(unsigned char* src32);
// Replace shadow palette data and upload all 32 bytes immediately. The caller
// provides a safe PPU access period; this helper does not wait for VBlank.
void nes_palette_apply_now(unsigned char* src32);
// Upload the current palette shadow directly, with timing controlled by the caller.
void nes_palette_apply_shadow_now(void);
// Update the shadow and copy all colors into the runtime queue. A queue
// failure leaves the new shadow contents in place.
// Return one if the runtime queue accepted the copied payload, zero if it was full.
// Admission does not mean the NMI consumer has already updated the PPU.
unsigned char nes_palette_queue_all(unsigned char* src32);
// Update and queue four background palette bytes. pal_index must be 0..3;
// there is no range check before writing the shadow.
unsigned char nes_palette_queue_bg4(unsigned char pal_index, unsigned char* src4);
// Update and queue four sprite palette bytes at the 0x3F10 region. The
// caller supplies pal_index 0..3; NES palette mirroring still applies.
unsigned char nes_palette_queue_sprite4(unsigned char pal_index, unsigned char* src4);kitaqfc/lib/palette.h
physics2d.h — 2D 運動與碰撞
#pragma once
// Position and velocity use caller-selected integer units with one integration
// step per call; no hidden pixel or time conversion occurs. Keep intermediate
// signed arithmetic in range. World/body storage is owned by the caller.
#include "fixed.h"
// Lightweight deterministic 2D physics for KITAQFC.
// Integer pixels per step are one possible unit convention; inv_mass is Q8.
typedef struct {
s16 x;
s16 y;
s16 vx;
s16 vy;
s16 half_x;
s16 half_y;
s16 inv_mass_q8; // 0 means static body.
s16 restitution_q8; // 0..255 (reserved for future tuning).
u8 active;
} KQBody2D;
typedef struct {
KQBody2D* bodies;
u8 body_count;
s16 gravity_x;
s16 gravity_y;
u8 solver_iterations;
s16 max_speed;
} KQWorld2D;
// Retain the caller-owned body array without initializing its elements.
// Set gravity to (0,32), four contact iterations and a per-axis speed limit of 512.
// A null world is ignored; the array must outlive subsequent world operations.
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);
// Advance active dynamic bodies, then visit each active unordered pair for
// the configured contact passes (zero means one). Static bodies still participate
// as obstacles. The world borrows its array and uses non-reentrant helper scratch.
// This is discrete integration; fast bodies can pass through thin obstacles.
void kq2d_step(KQWorld2D* world);
// For one active dynamic body, add gravity, clamp each velocity axis and then
// add velocity to position. Null inputs are ignored; no contacts are solved.
// Use a nonnegative speed limit and keep additions in signed 16-bit range.
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);
// Test strict overlap of two centered boxes; touching edges return false.
// Both pointers must be valid. Active/mass flags are ignored, and coordinate
// differences and extent sums must fit the signed 16-bit calculations.
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);
// Initialize an active unit-inverse-mass body at the supplied center and half
// extents, with zero velocity and reserved restitution set to zero. Null is ignored.
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);
// Replace the center without altering velocity, extents or activity. Null is ignored.
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);
// Replace velocity without clamping or checking activity/mass. Null is ignored.
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);
// Add gravity and clamp each velocity axis separately for an active dynamic
// body. Null, inactive and static bodies are ignored. Supply a nonnegative limit
// and avoid overflow in the additions before clamping; position is unchanged.
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);
// Scale both velocities by a signed eight-bit coefficient divided by 256.
// Despite the unsigned parameter, values 128..255 become negative coefficients;
// this is not a full-range unsigned Q8 damping helper. Null is ignored.
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);
// Delegate strict rectangle overlap to the fixed-point utility; edge-only
// contact is false. Coordinate-plus-size sums must remain representable as s16.
u8 kq2d_rect_intersect(KQRect a, KQRect b);
// Delegate the half-open point test: include left/top and exclude right/bottom.
// Coordinate-plus-size sums must remain representable as s16.
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);
// Opt-in surface solver. Velocities/threshold/kick share the caller's units.
// Normal must be unit length in Q8; coefficients are 0..255.
typedef struct {
s16 nx_q8;
s16 ny_q8;
s16 vx;
s16 vy;
s16 bounce_threshold;
s16 kick;
u8 restitution_q8;
u8 friction_q8;
} KQSurface2D;
// Truncates toward zero, including negative values; coefficient is -256..256.
s16 kq2d_scale_q8(s16 value, s16 coefficient);
// Conservative circular bound, with a shared Q8 scale for both components.
// Quantizes toward zero; very small limits relative to input may yield zero.
// Components and positive max_speed must be <= 16383 in magnitude.
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);
// Kinematic surface response; returns incoming normal speed, or zero if separating.
// Caller resolves penetration separately. Relative components must fit +/-8191.
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);
// Linear crossing time in Q8 (0..256); positive separation is outside.
// Returns 0 for initial overlap, 256 for no crossing. Gaps must fit +/-8191.
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);
// Optional byte-sized eighth-pixel channels for small custom update loops.
#define KQ2D_SUBPIXEL_BITS ((u8)3)
#define KQ2D_SUBPIXEL_ONE ((u8)8)
#define KQ2D_SUBPIXEL_MASK ((u8)7)
// Optional byte-channel identifiers for application-specific movement.
#define KQ2D_DRAG_BRAKE ((u8)1)
#define KQ2D_DRAG_STUN ((u8)2)
#define KQ2D_DRAG_COAST ((u8)3)
#define KQ2D_DRAG_THRUST ((u8)4)
#define KQ2D_DIR_NONE ((u8)0)
#define KQ2D_DIR_NEGATIVE ((u8)1)
#define KQ2D_DIR_POSITIVE ((u8)2)
/*
* Byte-sized Q5.3 channels for KITAQFC.
*
* Keep the channels as flat game-state fields in a hot loop. That avoids
* aggregate/pointer call traffic while retaining eighth-pixel integration.
*/
// Store integer pixel position separately from the 0..7 fractional remainder.
// Speed is an unsigned eighth-pixel magnitude; direction is a separate channel.
typedef u8 KQ2DPosition;
typedef u8 KQ2DFraction;
typedef u8 KQ2DSpeed;
typedef u8 KQ2DDirection;kitaqfc/lib/physics2d.h
physics3d.h — 3D AABB 物理
#pragma once
#include "core.h"
// Lightweight deterministic 3D physics for KITAQFC.
// AABB contacts, acceleration, mass-weighted bounce, and impact state flags.
// The game owns break decisions: the solver records impact speeds but never
// sets this flag or deactivates a body based on break_speed. Positions, extents,
// velocities and acceleration use consistent caller-selected per-step units.
#define KQ3D_BODY_BROKEN ((u8)0x01)
typedef struct {
s16 x;
s16 y;
s16 z;
s16 vx;
s16 vy;
s16 vz;
s16 ax;
s16 ay;
s16 az;
s16 half_x;
s16 half_y;
s16 half_z;
s16 mass_q8; // 256 means mass 1.0.
s16 inv_mass_q8; // 0 means static body.
s16 restitution_q8; // 256 means perfectly elastic.
s16 break_speed; // Reserved for game-side impact thresholds.
s16 last_impact_speed;
u8 active;
u8 flags;
} KQBody3D;
typedef struct {
KQBody3D* bodies;
u8 body_count;
s16 gravity_x;
s16 gravity_y;
s16 gravity_z;
u8 solver_iterations;
s16 max_speed;
} KQWorld3D;
// Borrow the body array without initializing it. Set gravity (0,24,0), four
// contact passes and a per-axis speed limit of 512. Null world is ignored;
// the caller retains ownership and must keep the array alive.
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count);
// Initialize an active centered box with zero velocity/acceleration,
// restitution 224, cleared impact/flags and mass set through the weight helper.
// The caller supplies valid half extents. Null body is ignored.
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8);
// Store the requested mass; nonpositive mass makes the body static.
// For positive mass compute inverse weight as max(1,32767/max(mass,64)).
// The stored mass retains the original input; this is a relative solver weight,
// not an exact Q8 reciprocal. Null body is ignored.
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8);
// Integrate active dynamic bodies and reset their impact values, then solve
// each active unordered pair for the configured passes (zero means one).
// Static bodies retain previous impact maxima until the game clears them.
// Acceleration persists; flags and break thresholds remain game-owned.
// This discrete solver uses non-reentrant helper scratch and can miss fast crossings.
void kq3d_step(KQWorld3D* world);
// Reset impact for one active dynamic body, add gravity and persistent body
// acceleration, clamp velocity per axis and advance position. Static/inactive
// bodies retain impact state. Null inputs are ignored; no contacts are solved.
// Use a nonnegative speed limit and avoid overflow before clamping.
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body);
// Test strict overlap on all three axes; face-only contact returns false.
// Valid pointers are required and flags are ignored. Center differences and
// extent sums must fit the signed 16-bit magnitude calculations.
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b);
// Sum three signed products, dividing each by 256 (toward zero) before addition.
// Coefficients are signed bytes scaled by 1/256; the 16-bit sum is not saturated.
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az);kitaqfc/lib/physics3d.h
ppu.h — PPU 顯示宣告
#ifndef PPU_H
#define PPU_H
// Link ppu.c. Bulk palette/nametable transfers require rendering to be disabled.
// Disable background and sprite rendering, preserving other PPUMASK bits.
void nes_ppu_screen_off(void);
// Set scroll to (0,0), then apply the requested PPUCTRL and PPUMASK values.
void nes_ppu_screen_on(unsigned char ctrl, unsigned char mask);
// Copy 32 bytes into $3F00..$3F1F with increment one; preserve PPUCTRL.
// Null is ignored. Hardware palette mirrors apply; source bank must stay mapped.
void nes_ppu_load_palette(unsigned char* pal32);
// Fill 960 tiles and 64 packed attributes; preserve PPUCTRL.
// Accept exactly $2000/$2400/$2800/$2C00; invalid bases are ignored.
void nes_ppu_clear_nt(unsigned short nt_base, unsigned char tile, unsigned char attr);
// Address-byte variants reset the latch and coexist with runtime.c's word seek.
void nes_ppu_seek_bytes(unsigned char hi, unsigned char lo);
// Direct transfers follow the current PPUCTRL increment; count is 0..255.
void nes_ppu_write_bytes(unsigned char hi, unsigned char lo, const unsigned char* src, unsigned char count);
void nes_ppu_fill(unsigned char hi, unsigned char lo, unsigned char value, unsigned char count);
#endifkitaqfc/lib/ppu.h
ppu_direct.h — 直接 PPU 操作
#ifndef PPU_DIRECT_H
#define PPU_DIRECT_H
#include "intrinsics.h"
/* Direct PPU access. Use only during vblank or when rendering is disabled. */
// Invoke the compiler rendering-enable helper; this header contains declarations, not C fallback implementations.
void __ppu_on(void);
// Invoke the compiler rendering-disable helper before bulk direct PPU updates.
void __ppu_off(void);
// Replace PPUMASK with the supplied byte; the caller chooses rendering, clipping and emphasis bits.
void __ppu_mask_set(u8 value);
// Replace PPUCTRL, including NMI enable, pattern-table choices and address increment mode.
void __ppu_ctrl_set(u8 value);
// Set the PPU address through the compiler helper; address writes affect the shared scroll/address latch.
void __ppu_addr(u16 ppu_addr);
// Write one PPUDATA byte using the current PPU address and increment mode.
void __ppu_data(u8 value);
// Read PPUSTATUS; the hardware clears VBlank status and resets the shared write latch.
u8 __ppu_read_status(void);
// Write a byte-counted source range directly; arrange PPU access timing and source-bank visibility.
void __vram_write(u16 ppu_addr, const u8* src, u8 len);
// Write repeated bytes directly; this is not an enqueue operation.
void __vram_fill(u16 ppu_addr, u8 value, u8 len);
#endifkitaqfc/lib/ppu_direct.h
rob.h — ROB 控制
#ifndef ROB_H
#define ROB_H
#include "intrinsics.h"
// Set PPUMASK and its shadow to 1E or 00, then wait for an NMI-counter change.
// The caller supplies image/palette brightness; rendering enable alone does not create a white screen.
void __rob_flash(u8 bright);
// Run on_frames enabled-mask waits followed by off_frames disabled-mask waits; NMI must advance.
void __rob_pulse(u8 on_frames, u8 off_frames);
// Send eight bits MSB first, using 4/2-frame pulses for one and 2/4 for zero.
// Preserve the outer bit counter and shifted pattern around each pulse helper.
void __rob_send_byte(u8 pattern);
#endifkitaqfc/lib/rob.h
runtime.h — NMI、OAM 與 PPU 傳輸用 C 輔助函式
/*
* Core NES runtime declarations.
*
* Declare frame waits, direct PPU transfers, OAM DMA and the copied-payload VRAM queue.
*/
// The four-byte record follows hardware OAM byte order: Y, tile, attributes, X.
struct NesSprite4 {
unsigned char y;
unsigned char tile;
unsigned char attr;
unsigned char x;
};
extern unsigned char nes_nmi_counter;
extern unsigned char nes_oam_shadow[256];
// This counter measures the separate 192-byte copied-payload runtime queue, not the compiler intrinsic queue.
extern unsigned char nes_vram_queue_used;
extern unsigned char nes_vram_queue_overflow;
// Wait until the NMI handler advances its counter. NMI must already be enabled
// and able to execute; this polling loop has no timeout.
void nes_wait_nmi(void);
// Wait for the current VBlank to end, then for the next one to begin. Each
// PPUSTATUS read has hardware side effects, including clearing the VBlank flag.
void nes_vblank_wait(void);
// Reset the PPU address latch with a status read, then write the high/low address bytes.
void nes_ppu_seek(unsigned short ppu_addr);
// Write len source bytes directly through PPUDATA. Call only during an appropriate
// PPU access period; the address increment mode comes from the current PPUCTRL.
void nes_ppu_stream_write(unsigned short ppu_addr, unsigned char* src, unsigned short len);
// Write value repeatedly through PPUDATA, using the current PPU address increment
// mode. This routine does not wait for VBlank or disable rendering.
void nes_ppu_stream_fill(unsigned short ppu_addr, unsigned char value, unsigned short len);
// Reset the OAM destination and DMA one 256-byte CPU page. The hardware stalls
// the CPU during transfer; page is the source address high byte.
void nes_oam_dma(unsigned char page);
// Discard pending VRAM commands and clear the overflow latch; no PPU writes occur.
void nes_vram_queue_clear(void);
// Copy a literal payload into the queue and publish its new used length last.
// Accept lengths 0..127; reject larger lengths and latch overflow without changing the queue.
// The caller must ensure queue production cannot race its NMI consumer.
unsigned char nes_vram_queue_try_write(unsigned short ppu_addr, unsigned char* src, unsigned char len);
// Queue a four-byte fill record: address high/low, length with bit 7 set, value.
// Reject lengths above 127 and latch overflow on any capacity/format failure.
unsigned char nes_vram_queue_try_fill(unsigned short ppu_addr, unsigned char value, unsigned char len);
// Consume complete records in order during a safe PPU access period. Reading
// PPUSTATUS resets the shared address latch before each address pair. The caller
// is responsible for ensuring the transfer fits its NMI/VBlank time budget.
void nes_vram_queue_nmi_flush(void);kitaqfc/lib/runtime.h
scene.h — 場景註冊、切換與更新
#ifndef SCENE_H
#define SCENE_H
#include "core.h"
typedef void (*SceneFunc)(void);
typedef __packed struct SceneDef {
SceneFunc enter;
SceneFunc update;
SceneFunc draw;
SceneFunc exit;
} SceneDef;
// One shared in-flight transfer. remaining counts source bytes not yet copied into the queue.
// An inactive stream may still have commands awaiting the NMI consumer.
struct NesSceneStreamState {
unsigned char* src;
unsigned short ppu_addr;
unsigned short remaining;
unsigned char chunk;
unsigned char active;
};
extern struct NesSceneStreamState nes_scene_stream_state;
// Attach the caller-owned scene table and clear current-scene state without invoking callbacks.
void scene_init(const SceneDef* scenes, u8 count);
// Replace the table by resetting scene state; this does not call the old scene's exit handler.
void scene_set_table(const SceneDef* scenes, u8 count);
// Ignore invalid IDs; otherwise exit the current scene and enter the requested one.
// Selecting the current ID still performs exit/enter. Callbacks run synchronously.
void scene_change(u8 scene_id);
// Clear the change flag before calling the active scene's update handler, so a
// transition made during that handler is visible afterward.
void scene_update();
// Call the active scene's draw handler if one exists; no current scene is a no-op.
void scene_draw();
// Return the stored scene ID; zero is also returned before the first transition.
u8 scene_get_current();
// Read the transition flag, which is cleared at the start of an active scene update.
u8 scene_was_changed();
// Replace the single active transfer and retain its source pointer. Keep the
// source storage and any required ROM bank readable until all bytes are queued.
void nes_scene_stream_begin(unsigned short ppu_addr, unsigned char* src, unsigned short len, unsigned char chunk);
// Prepare the 960-byte tile portion of a nametable using 32-byte queue records.
void nes_scene_stream_begin_nametable(unsigned short nt_base, unsigned char* src960);
// Prepare the 64-byte attribute table at nametable base + 0x03C0.
void nes_scene_stream_begin_attr(unsigned short nt_base, unsigned char* src64);
// Prepare a 32-byte palette transfer to PPU address 0x3F00.
void nes_scene_stream_begin_palette(unsigned char* src32);
// Queue as many chunks as available capacity allows, capped at 127 bytes each.
// Return one when queue exhaustion requires a later retry, zero when all data has
// been queued. Zero does not mean the NMI consumer has already written the PPU.
unsigned char nes_scene_stream_step(void);
#endifkitaqfc/lib/scene.h
scroll.h — 背景、視窗與分割捲動
/*
* Optional declarations for the phase 9 NES scroll helper.
*/
extern unsigned char nes_scroll_ctrl_base;
extern unsigned short nes_scroll_camera_x;
extern unsigned short nes_scroll_camera_y;
// Store PPUCTRL bits other than the two nametable-selection bits for later application.
void nes_scroll_set_base_ctrl(unsigned char ctrl);
// Store camera coordinates without touching hardware registers.
void nes_scroll_set(unsigned short camera_x, unsigned short camera_y);
// Combine bit 8 of each camera coordinate with base PPUCTRL, reset the latch
// by reading PPUSTATUS, and write low-byte X/Y scroll. This uses 256-unit
// wrapping on both axes rather than normalizing Y to a 240-pixel nametable height.
// Initialize base control to the intended PPUCTRL value, including NMI enable, before applying.
// Only coordinate bits 0..8 are used; arrange safe PPU timing in the caller.
void nes_scroll_apply(void);
// Subtract the screen anchor from the world point into unsigned camera
// coordinates. Underflow wraps; world-edge clamping belongs to the game.
void nes_camera_follow_center(unsigned short target_x, unsigned short target_y, unsigned char center_x, unsigned char center_y);kitaqfc/lib/scroll.h
sprite.h — OBJ 配置、定位、組合精靈與動畫
#ifndef SPRITE_H
#define SPRITE_H
#include "core.h"
#include "intrinsics.h"
// Keep this value within 1..64; tracking arrays and hardware OAM contain exactly 64 slots.
#ifndef SPRITE_MAX
#define SPRITE_MAX ((u8)64)
#endif
#define SPRITE_FLAG_PAL1 ((u8)0x01)
#define SPRITE_FLAG_PAL2 ((u8)0x02)
#define SPRITE_FLAG_PAL3 ((u8)0x03)
#define SPRITE_FLAG_PRIORITY ((u8)0x20)
#define SPRITE_FLAG_XFLIP ((u8)0x40)
#define SPRITE_FLAG_YFLIP ((u8)0x80)
// Signed per-part offsets are added modulo 256. This struct API has an explicit count,
// unlike the FF-terminated byte-stream API in metasprite.h.
typedef struct MetaSpritePart {
s8 dx;
s8 dy;
u8 tile;
u8 flags;
} MetaSpritePart;
// Initialize frame/ticks to valid values. Returned tile IDs advance by one regardless of hardware sprite size.
typedef struct SpriteAnim {
u8 first_tile;
u8 frame_count;
u8 frame;
u8 ticks;
u8 ticks_per_frame;
} SpriteAnim;
extern u8 kq_sprite_active[64];
extern u8 kq_sprite_used;
extern u8 kq_sprite_height;
// Reset allocation/position state and hide each OAM slot through the intrinsic.
// The software height defaults to eight; hardware sprite size is configured elsewhere.
void sprite_init(void);
// Claim and hide the first free slot, or return 0xFF if all slots are active.
u8 sprite_alloc(void);
// Release an active valid slot and hide it; invalid/repeated frees are ignored.
void sprite_free(u8 id);
// Update software coordinates and the intrinsic OAM position for a valid slot.
void sprite_set_pos(u8 id, u8 x, u8 y);
// Replace the tile byte of a valid OAM slot without changing allocation state.
void sprite_set_tile(u8 id, u8 tile);
// Replace the hardware attribute byte of a valid OAM slot.
void sprite_set_flags(u8 id, u8 flags);
// Mark the software position off screen and hide its OAM entry without freeing it.
void sprite_hide(u8 id);
// Transfer intrinsic shadow OAM immediately; this wrapper does not wait for VBlank.
void sprite_flush_oam_now(void);
// Wait for NMI before requesting OAM DMA.
void sprite_flush_oam(void);
// Return the number of active slots, including slots activated by metasprite_draw.
// Hidden allocated slots remain active until sprite_free releases them.
u8 sprite_count_used(void);
// Flag software overlap estimates above eight sprites on one scanline.
u8 sprite_warn_scanline_overflow(void);
// Estimate peak overlap across 240 lines from software Y/height values.
// This does not model pixel transparency, OAM priority or every hardware overflow quirk.
u8 sprite_max_scanline_count(void);
// Place consecutive parts, counting each newly activated slot once. Existing
// active slots are overwritten without increasing the allocation count. Return
// the number written; an invalid first slot or zero count writes nothing.
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count);
// Advance animation ticks and wrap the frame index, returning the selected tile.
// Zero ticks-per-frame freezes advancement; null state returns zero.
u8 anim_update(SpriteAnim* anim);
#endifkitaqfc/lib/sprite.h
system.h — 啟動、影格計數、等待與中斷
#ifndef SYSTEM_H
#define SYSTEM_H
#include "core.h"
#include "intrinsics.h"
// A synchronous callback invoked after the software frame count is incremented.
typedef void (*SystemCallback)(void);
extern u16 kq_system_frame;
// Reset the software frame counter and callback storage, then enable NMI.
void system_init(void);
// Wait for NMI, count the completed wait, then invoke the registered callback.
void system_wait_vblank(void);
// Replace the per-wait callback; null disables callback dispatch.
void system_set_vblank_callback(SystemCallback callback);
// Return the wrapping 16-bit count of completed waits through this wrapper.
u16 system_get_frame(void);
// Return the low byte of the software frame counter.
u8 system_get_frame8(void);
// Enable maskable CPU IRQs through the intrinsic; NMI is controlled separately.
void system_enable_interrupts(void);
// Disable maskable CPU IRQs; this does not disable the PPU's NMI source.
void system_disable_interrupts(void);
#define fc_init system_init
#define fc_wait_vblank system_wait_vblank
#define fc_set_vblank_callback system_set_vblank_callback
#define fc_frame_count system_get_frame
#define gb_init system_init
#define gb_wait_vblank system_wait_vblank
#define gb_set_vblank_callback system_set_vblank_callback
#define gb_frame_count system_get_frame
#endifkitaqfc/lib/system.h
tilemap.h — 矩形圖塊地圖操作
/*
* Optional declarations for the phase 11 tilemap helper.
*/
// The map borrows row-major tile bytes; keep width*height bytes readable in the active CPU mapping.
// solid_from is a tile-ID threshold, not an independent collision bitmap.
struct NesTilemap {
unsigned char* tiles;
unsigned char width;
unsigned char height;
unsigned char solid_from;
};
// Compute a row-major byte offset by adding the row stride ty times. This
// internal arithmetic helper does not validate coordinates.
unsigned short nes_tilemap_index(struct NesTilemap* map, unsigned char tx, unsigned char ty);
// Return a tile byte, or 0xFF when coordinates exceed map dimensions. The
// map/storage pointers must be valid; 0xFF may also be an actual stored tile.
unsigned char nes_tilemap_get(struct NesTilemap* map, unsigned char tx, unsigned char ty);
// Treat out-of-bounds/0xFF tiles as solid, then compare other tile IDs with
// the map's solid_from threshold.
unsigned char nes_tilemap_point_solid(struct NesTilemap* map, unsigned char tx, unsigned char ty);
// Convert pixels to eight-pixel tile X and narrow to a byte. Keep world X
// below 2048 when wraparound is not intended.
unsigned char nes_world_to_tile8_x(unsigned short world_x);
// Convert pixels to eight-pixel tile Y with the same byte-coordinate limit.
unsigned char nes_world_to_tile8_y(unsigned short world_y);
// Convert a world point to tile coordinates and apply the tile solidity rule.
unsigned char nes_tilemap_world_point_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y);
// Test only the four corners of a nonempty world box. Interior/edge tiles
// between the corners are not scanned, so large boxes can miss obstacles.
// Width/height must be nonzero and endpoint arithmetic must not overflow.
unsigned char nes_tilemap_world_box_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y, unsigned char width, unsigned char height);kitaqfc/lib/tilemap.h
vram.h — VRAM 佇列更新與傳輸
#ifndef VRAM_H
#define VRAM_H
#include "core.h"
#include "intrinsics.h"
// Coordinates use 32-byte nametable rows. These wrappers do not clip to the 32x30 visible tile area.
#ifndef VRAM_NT_BASE
#define VRAM_NT_BASE ((u16)0x2000)
#endif
// Clear the intrinsic queue and its overflow latch.
void vram_init(void);
// Discard queued commands and explicitly reset the overflow latch.
void vram_clear_queue(void);
// Queue one tile at the default nametable base. Return the current overflow
// status, which may include a failure from an earlier operation.
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);
// Alias the queued background-tile operation.
u8 vram_queue_tile(u8 x, u8 y, u8 tile);
// Queue one fill per row. This is not transactional: capacity exhaustion can
// leave earlier rows queued, and the loop continues attempting later rows.
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
// Queue each tightly packed source row as a pointer-based copy record. Keep
// source storage and its ROM bank accessible until queue execution finishes;
// partial queuing remains possible on overflow.
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);
// Split a byte transfer into copy records of at most 127 bytes. The runtime
// retains source pointers rather than copying payloads into the queue. Return
// the overflow latch state after all records have been attempted.
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);
// Alias the byte-copy queue helper; len remains a byte count, not a tile count.
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);
// Queue fills of at most 127 bytes each. Overflow can leave a partially queued
// transfer; no rollback is performed.
u8 vram_queue_memset(u16 dst, u8 value, u16 len);
// Invoke the queue executor directly. Its ready flag must already be set by
// commit, and the caller supplies appropriate PPU timing.
void vram_flush_now(void);
// Commit queued records for consumption and wait for the NMI path.
void vram_flush(void);
// Return the encoded queue length in bytes, not the number of commands.
u8 vram_get_queue_used(void);
// Return the remaining command-buffer capacity in bytes. A command requires
// space for its complete encoded record, including its address and metadata.
// Read before committing: NMI may consume a committed queue asynchronously.
u8 vram_get_queue_free(void);
// Return the queue's total capacity in bytes, independent of its current usage.
// This describes the command buffer, not free space in PPU VRAM.
u8 vram_get_queue_capacity(void);
// Read the overflow latch without clearing it.
u8 vram_get_overflowed(void);
#endifkitaqfc/lib/vram.h
vram_queue.h — 由 NMI 處理的 VRAM 佇列
#ifndef VRAM_QUEUE_H
#define VRAM_QUEUE_H
#include "intrinsics.h"
/* Safe frame-time VRAM queue. These names are compiler intrinsic entry points. */
// Reset pending intrinsic-queue records; this is separate from runtime.c nes_vram_queue_clear.
void __vramq_clear(void);
// Append one address/value update; use the overflow latch to detect capacity failure.
void __vramq_put(u16 ppu_addr, u8 value);
// Retain the source address for later consumption; keep its storage and bank mapping valid.
void __vramq_copy(u16 ppu_addr, const u8* src, u8 len);
// Append a repeated-byte update; the source value is stored in the record.
void __vramq_fill(u16 ppu_addr, u8 value, u8 len);
// Publish the pending records to the configured consumer. Do not mutate them while consumption can run.
void __vramq_commit(void);
// Execute a ready queue directly; committing and safe PPU timing are caller responsibilities.
void __vramq_exec(void);
// Return encoded bytes currently occupied, not transfer payload bytes or command count.
u8 __vramq_len(void);
// Read the latched capacity failure; reading does not reset it.
u8 __vramq_overflow(void);
// Clear the overflow latch explicitly after handling the failed submission.
void __vramq_clear_overflow(void);
// Return total encoded command-buffer capacity; this is independent of PPU VRAM capacity.
u8 __vramq_capacity(void);
#endifkitaqfc/lib/vram_queue.h
vrc6_sound.h — VRC6 擴充音源
#ifndef VRC6_SOUND_H
#define VRC6_SOUND_H
#include "core.h"
// Retained names for raw control codes 0..3; their numeric suffixes are not measured duty percentages.
// The KUROSAKI pulse model uses (code+1)/16 for these codes. Combine with a low volume nibble.
#define VRC6_PULSE_DUTY_12 0x00
#define VRC6_PULSE_DUTY_25 0x10
#define VRC6_PULSE_DUTY_50 0x20
#define VRC6_PULSE_DUTY_75 0x30
#define VRC6_PULSE_GATE 0x80
// Clear channel-enable/high-timer registers and output controls for all VRC6 voices.
// Requires the VRC6 register layout used by this module. No mapper setup or global frequency-control write is included.
void nes_vrc6_silence_all(void);
// Write pulse-1 control and the low 12 timer bits, then enable the channel.
void nes_vrc6_pulse1_set(u8 control, u16 period);
// Write pulse-2 control and the low 12 timer bits, then enable the channel.
void nes_vrc6_pulse2_set(u8 control, u16 period);
// Disable pulse 1 by clearing its high timer/enable register.
void nes_vrc6_pulse1_off(void);
// Disable pulse 2 by clearing its high timer/enable register.
void nes_vrc6_pulse2_off(void);
// Mask the saw accumulation rate to six bits, load a 12-bit timer and enable output.
void nes_vrc6_saw_set(u8 rate, u16 period);
// Disable the saw channel by clearing its high timer/enable register.
void nes_vrc6_saw_off(void);
#endifkitaqfc/lib/vrc6_sound.h
vrc7_sound.h — VRC7 FM 音源
#ifndef VRC7_SOUND_H
#define VRC7_SOUND_H
#include "core.h"
#define VRC7_KEY_ON 0x10
#define VRC7_SUSTAIN 0x20
// Write register selection followed immediately by data. No explicit device
// settling delay or cartridge detection is inserted by this wrapper.
// The caller must arrange device timing and serialize register/data pairs against interrupt writers.
void nes_vrc7_write(u8 reg, u8 value);
// Copy eight caller-supplied patch bytes into user-instrument registers 0..7.
void nes_vrc7_set_user_patch(const u8* patch8);
// Validate channel 0..5, then pack a 9-bit frequency, 3-bit block, key flags,
// instrument and volume nibbles into its registers. Volume is the raw hardware
// attenuation field, not a linear loudness value.
void nes_vrc7_channel_set(u8 channel, u8 instrument, u8 volume, u16 fnum, u8 block, u8 key_flags);
// Clear the channel's entire frequency-high/block/key register, not just the
// key-on bit. A later note must restore frequency and block settings.
void nes_vrc7_key_off(u8 channel);
// Key off all six voices and set instrument zero with maximum attenuation.
void nes_vrc7_silence_all(void);
#endifkitaqfc/lib/vrc7_sound.h
wire3d.h — DMG 線框
// Copyright (c) 2026 DAISUKE OBA. SPDX-License-Identifier: MIT
#ifndef KITAQFC_WIRE3D_H
#define KITAQFC_WIRE3D_H
#include "core.h"
#include "intrinsics.h"
// Choose a supported viewport before including wire3d.c. Smaller views reduce
// line work and dirty CHR transfers; all use original one-bit line graphics.
#ifndef WIRE3D_FC_WIDTH
#define WIRE3D_FC_WIDTH 64
#endif
#ifndef WIRE3D_FC_HEIGHT
#define WIRE3D_FC_HEIGHT 48
#endif
#if WIRE3D_FC_WIDTH == 64 && WIRE3D_FC_HEIGHT == 48
#define WIRE3D_FC_TILES 48
#elif WIRE3D_FC_WIDTH == 96 && WIRE3D_FC_HEIGHT == 64
#define WIRE3D_FC_TILES 96
#elif WIRE3D_FC_WIDTH == 128 && WIRE3D_FC_HEIGHT == 96
#define WIRE3D_FC_TILES 192
#else
#error Select 64x48, 96x64 or 128x96 for the wireframe viewport
#endif
#define WIRE3D_FC_VERTEX_LIMIT 24
typedef struct Wire3DFC_Vec3 { s8 x; s8 y; s8 z; } Wire3DFC_Vec3;
typedef struct Wire3DFC_Edge { u8 a; u8 b; } Wire3DFC_Edge;
extern u8 wire3d_transfer_frames;
extern u8 wire3d_uploaded_tiles;
// Own both CHR-RAM pattern tables and nametable zero. Requires writable 8 KiB
// CHR RAM and PRG RAM 0x6800..0x70BF; reserves ZP 0x00..0x0A for drawing/transfer.
// Build with --nes-chr-ram and provide cartridge PRG RAM for the stage.
// Center the viewport, clear video memory, select cyan-on-dark colors and turn
// on background rendering with NMI disabled. Do not run another PPU writer.
void Wire3DFC_Init(void);
// Clear the previous staged drawing. The displayed front image remains intact.
void Wire3DFC_BeginFrame(void);
// Draw a connected, inclusive segment. Endpoints must be -512..511. Pixels
// outside the viewport are clipped; completely outside bounding boxes return.
void Wire3DFC_DrawLine2D(s16 ax,s16 ay,s16 bx,s16 by);
// Rotate a small model-space point in Y/X/Z order. Angles wrap in 32 steps.
// Start with components in -63..63; supply three distinct writable pointers.
void Wire3DFC_RotatePoint(s16* x,s16* y,s16* z,u8 rx,u8 ry,u8 rz);
// Project camera-space coordinates using an integer reciprocal table. Require
// x/y within -127..127 and z within 32..255. Return zero without touching outputs
// on invalid input; success returns one and writes unclipped screen coordinates.
u8 Wire3DFC_ProjectPoint(s16 x,s16 y,s16 z,s16* sx,s16* sy);
// Draw when both endpoints pass the projection range. Near-plane crossings
// are rejected, not intersected with the near plane; screen pixels are clipped.
void Wire3DFC_DrawLine3D(s16 ax,s16 ay,s16 az,s16 bx,s16 by,s16 bz);
// Rotate, translate and project up to 24 vertices, then draw indexed edges.
// Invalid edge indices/depth endpoints are skipped. Model data must remain
// readable in the current PRG mapping. This draws all edges, without face culling.
void Wire3DFC_DrawModel(const Wire3DFC_Vec3* vertices,u8 vertex_count,const Wire3DFC_Edge* edges,u8 edge_count,s16 x,s16 y,s16 z,u8 rx,u8 ry,u8 rz);
// Upload changed tiles to the hidden CHR table in bounded VBlank batches and
// swap only after completion. Blocks across as many frames as needed. The two
// counters report this call's upload batches plus swap, and tile count.
void Wire3DFC_EndFrame(void);
#endifkitaqfc/lib/wire3d.h
wire3d_tables.h —
// Copyright (c) 2026 DAISUKE OBA. SPDX-License-Identifier: MIT
// Generated from round(64*sin(2*pi*i/32)) and round(64*width/z).
// Depths below 32 are rejected. Saturating 256 to 255 at the largest
// viewport/nearest depth bounds the projection error without a ninth bit.
__prg_rom const s8 w3dfc_sin[32]={
0,12,24,36,45,53,59,63,64,63,59,53,45,36,24,12,
0,-12,-24,-36,-45,-53,-59,-63,-64,-63,-59,-53,-45,-36,-24,-12,
};
#if WIRE3D_FC_WIDTH == 64
__prg_rom const u8 w3dfc_recip[256]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
128,124,120,117,114,111,108,105,102,100,98,95,93,91,89,87,
85,84,82,80,79,77,76,74,73,72,71,69,68,67,66,65,
64,63,62,61,60,59,59,58,57,56,55,55,54,53,53,52,
51,51,50,49,49,48,48,47,47,46,46,45,45,44,44,43,
43,42,42,41,41,41,40,40,39,39,39,38,38,38,37,37,
37,36,36,36,35,35,35,34,34,34,34,33,33,33,33,32,
32,32,32,31,31,31,31,30,30,30,30,29,29,29,29,29,
28,28,28,28,28,27,27,27,27,27,27,26,26,26,26,26,
26,25,25,25,25,25,25,25,24,24,24,24,24,24,24,23,
23,23,23,23,23,23,23,22,22,22,22,22,22,22,22,21,
21,21,21,21,21,21,21,21,20,20,20,20,20,20,20,20,
20,20,20,19,19,19,19,19,19,19,19,19,19,19,18,18,
18,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,
17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,
};
__prg_rom const u8 w3dfc_row_lo[48]={
0,1,2,3,4,5,6,7,64,65,66,67,68,69,70,71,
128,129,130,131,132,133,134,135,192,193,194,195,196,197,198,199,
0,1,2,3,4,5,6,7,64,65,66,67,68,69,70,71,
};
__prg_rom const u8 w3dfc_row_hi[48]={
104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
};
__prg_rom const u8 w3dfc_tile_row[48]={
0,0,0,0,0,0,0,0,8,8,8,8,8,8,8,8,
16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24,
32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40,
};
#elif WIRE3D_FC_WIDTH == 96
__prg_rom const u8 w3dfc_recip[256]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
192,186,181,176,171,166,162,158,154,150,146,143,140,137,134,131,
128,125,123,120,118,116,114,112,110,108,106,104,102,101,99,98,
96,95,93,92,90,89,88,87,85,84,83,82,81,80,79,78,
77,76,75,74,73,72,71,71,70,69,68,68,67,66,65,65,
64,63,63,62,61,61,60,60,59,59,58,57,57,56,56,55,
55,54,54,53,53,53,52,52,51,51,50,50,50,49,49,48,
48,48,47,47,47,46,46,46,45,45,45,44,44,44,43,43,
43,42,42,42,42,41,41,41,40,40,40,40,39,39,39,39,
38,38,38,38,37,37,37,37,37,36,36,36,36,36,35,35,
35,35,35,34,34,34,34,34,33,33,33,33,33,33,32,32,
32,32,32,32,31,31,31,31,31,31,30,30,30,30,30,30,
30,29,29,29,29,29,29,29,28,28,28,28,28,28,28,28,
27,27,27,27,27,27,27,27,26,26,26,26,26,26,26,26,
26,25,25,25,25,25,25,25,25,25,25,24,24,24,24,24,
};
__prg_rom const u8 w3dfc_row_lo[64]={
0,1,2,3,4,5,6,7,96,97,98,99,100,101,102,103,
192,193,194,195,196,197,198,199,32,33,34,35,36,37,38,39,
128,129,130,131,132,133,134,135,224,225,226,227,228,229,230,231,
64,65,66,67,68,69,70,71,160,161,162,163,164,165,166,167,
};
__prg_rom const u8 w3dfc_row_hi[64]={
104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
104,104,104,104,104,104,104,104,105,105,105,105,105,105,105,105,
105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
};
__prg_rom const u8 w3dfc_tile_row[64]={
0,0,0,0,0,0,0,0,12,12,12,12,12,12,12,12,
24,24,24,24,24,24,24,24,36,36,36,36,36,36,36,36,
48,48,48,48,48,48,48,48,60,60,60,60,60,60,60,60,
72,72,72,72,72,72,72,72,84,84,84,84,84,84,84,84,
};
#elif WIRE3D_FC_WIDTH == 128
__prg_rom const u8 w3dfc_recip[256]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
255,248,241,234,228,221,216,210,205,200,195,191,186,182,178,174,
171,167,164,161,158,155,152,149,146,144,141,139,137,134,132,130,
128,126,124,122,120,119,117,115,114,112,111,109,108,106,105,104,
102,101,100,99,98,96,95,94,93,92,91,90,89,88,87,86,
85,84,84,83,82,81,80,80,79,78,77,77,76,75,74,74,
73,72,72,71,71,70,69,69,68,68,67,67,66,66,65,65,
64,64,63,63,62,62,61,61,60,60,59,59,59,58,58,57,
57,56,56,56,55,55,55,54,54,54,53,53,53,52,52,52,
51,51,51,50,50,50,49,49,49,48,48,48,48,47,47,47,
47,46,46,46,46,45,45,45,45,44,44,44,44,43,43,43,
43,42,42,42,42,42,41,41,41,41,41,40,40,40,40,40,
39,39,39,39,39,38,38,38,38,38,38,37,37,37,37,37,
37,36,36,36,36,36,36,35,35,35,35,35,35,35,34,34,
34,34,34,34,34,33,33,33,33,33,33,33,33,32,32,32,
};
__prg_rom const u8 w3dfc_row_lo[96]={
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
};
__prg_rom const u8 w3dfc_row_hi[96]={
104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
};
__prg_rom const u8 w3dfc_tile_row[96]={
0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,
32,32,32,32,32,32,32,32,48,48,48,48,48,48,48,48,
64,64,64,64,64,64,64,64,80,80,80,80,80,80,80,80,
96,96,96,96,96,96,96,96,112,112,112,112,112,112,112,112,
128,128,128,128,128,128,128,128,144,144,144,144,144,144,144,144,
160,160,160,160,160,160,160,160,176,176,176,176,176,176,176,176,
};
#endifkitaqfc/lib/wire3d_tables.h
zapper.h — 光線槍輸入介面
#ifndef ZAPPER_H
#define ZAPPER_H
#include "intrinsics.h"
// Return raw 4016 & 18, retaining trigger and active-low light bits.
u8 __zapper_raw1(void);
// Return raw 4017 & 18 for the second port.
u8 __zapper_raw2(void);
// Return port-1 trigger bit 4 normalized to 0 or 1.
u8 __zapper_trigger1(void);
// Return port-2 trigger bit 4 normalized to 0 or 1.
u8 __zapper_trigger2(void);
// Invert port-1 bit 3 and normalize: one means light detected.
u8 __zapper_light1(void);
// Invert port-2 bit 3 and normalize: one means light detected.
u8 __zapper_light2(void);
// Default to the port-2 normalized trigger reader.
u8 __zapper_trigger(void);
// Default to the port-2 normalized light reader.
u8 __zapper_light(void);
#endifkitaqfc/lib/zapper.h
zx0.h —
#pragma once
#include "core.h"
// Copyright (c) 2026 DAISUKE OBA. MIT License.
// ZX0-compatible forward v2 streams; format designed by Einar Saukas.
#define ZX0_OK 0
#define ZX0_BAD_ARGUMENT 1
#define ZX0_TRUNCATED 2
#define ZX0_BAD_STREAM 3
#define ZX0_OUTPUT_FULL 4
#define ZX0_DISPLAY_ACTIVE 5
// Shared last-call status. These foreground routines are not reentrant.
extern u8 zx0_error;
// Return decoded bytes, or zero on error (possibly after partial writes).
// Source and output must not overlap or cross their current CPU bank windows.
// Capacity and packed_size are byte counts. No prefix/backward/v1 streams.
u16 zx0_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);
// Decode a KQA1 raw/RLE/ZX0 asset produced with --format=auto.
// Empty raw assets return zero with zx0_error==ZX0_OK.
u16 asset_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);
// Decode into caller-owned RAM, then transfer to CHR RAM or nametable memory.
// Rendering must be off. Preserve PPUCTRL; set scroll before enabling rendering.
// The workspace must hold the whole output. No palette upload or CHR ROM writes.
u16 zx0_decompress_vram(u16 ppu_addr,void* workspace,u16 capacity,const void* src,u16 packed_size);kitaqfc/lib/zx0.h






