如何写一个NES模拟器(一)

本文详细解析了NES文件格式结构,重点介绍了如何读取和理解VROM中的点阵格式字模数据,以及如何通过编程绘制这些字模图形,为游戏画面的还原提供技术指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.认识NES文件格式

偏移0-3  字符串“NES^Z”用来识别.NES 文件
偏移4 16kB ROM 的数目
偏移5  8kB VROM 的数目

(摘自《任天堂产品系统文件》)

NES文件的前16个字节是文件头,前4个字节是NES^Z,文件标识。第5个字节是16K ROM的数量,第6个字节是8K VROM的数目。

ROM文件格式具体是这样:16字节(文件头)+16K x N(程序主体) + 8K x N(VROM),这就是一个完整的NES格式的ROM文件。其中8K VROM是点阵格式的字模文件,就是游戏中画面的最小元素,如果你了解点阵格式的话,你知道A的点阵大约是

00010000 一个字节
00202000 一个字节
03000300 一个字节
20000020 一个字节
11111110 一个字节
20000020 一个字节
30000030 一个字节

如果只是黑白点阵格式,图中的23,只能是1,因为2进制只有0和1,且每行一个字节,那么8个字节可以表示一个字母。任天堂使用2个点阵来表示一个点阵,其中前一个点阵(8字节)表示颜色的bit0位,后一个点阵(8字节)表示颜色的bit1位。

那么上图就是把2个点阵叠加在一起。

       知道了这些内容后,我们写一个读取VROM的程序。

先读取rom文件到buf中,这里我把文件指针直接移动到了字模处

liCurrentPosition.LowPart = neshreader->romnum * 16 * 1024;

SetFilePointerEx(hFile, liCurrentPosition,&liCurrentPosition,FILE_BEGIN);

ReadFile(hFile,(LPVOID)buf,8 * 1024,&readsize,NULL);

 

然后就是画单个字模图形函数。

根据上图来绘制单个字模。

void Draw_Tile(int x,int y,unsigned char * p,unsigned char index,unsigned char high2bit,char flip,int type)

{

int i,j,c = 0,d;

unsigned char a,b,a1,b1;

//绘制图案

for (j =0;j < 8;j++)

{

//存储8*8图案一共需要16个字节,

a1 = *p; //指向上图的地址0

b1 = *(p+8); //指向上图的地址8 

for (i = 0;i < 8; i++)

{
//从左至由绘制点
a = (a1 >> (7 - i) << 1 ) & 2; //a值=a1右移后再左移一位

b = (b1 >> (7 - i)) & 1;

//颜色索引,a和b组成低2位 (a or b)

d = (unsigned char)(a | b);
//如果低2位是1,2,3分别绘制不同的颜色
if(d == 1 ){

    draw_window_point(x * 8 + i,y * 8 + j,RGB(0,0,255),(UINT *)color,256);

}else if(d == 2){

    draw_window_point(x * 8 + i,y * 8 + j,RGB(0,255,255),(UINT *)color,256);

}else if(d == 3){

    draw_window_point(x * 8 +  i,y * 8 +  j,RGB(255,255,255),(UINT *)color,256);

        }

    }

    p++;

    }

}
--------------------

绘制所有图形

void drawchr(void * buf)

{

int i,j,x,y,c = 0,d;

unsigned char a,b,a1,b1;

//分配内存地址

pScreenMem =(unsigned char *) malloc(256*128*4);
//创建dib位图

CreateScreen(m_hWnd);
//得到图案表首地址
unsigned char * p = (unsigned char * )buf;
//绘制16行
for (y = 0; y < 16;y++){
//每行绘制32个块
    for(x = 0; x < 32; x++){

        Draw_Tile(x,y,p,0,0,0,0);

        p += 16;

        }

}
    //得到窗口句柄
    HDC hDc = ::GetDC(m_hWnd);
    //开始显示图形
    LoadFrame(color,hDc);

}
--------------------- 

附图一张,接下来我们就可以绘制整个命名表了,接着就是精灵的绘制,我们还要模拟CPU,并在vblank中不断的绘制图形,形成游戏画面了。Demo程序地址如下

链接:https://pan.baidu.com/s/1WdZx3T7HifTW75bcRYqhNQ 
提取码:q8oq 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值