用 Typescript 写了个 NES 模拟器 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
esw
V2EX    分享创造

用 Typescript 写了个 NES 模拟器

  •  4
     
  •   esw 2020-04-06 13:48:21 +08:00 8264 次点击
    这是一个创建于 2083 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假期无聊想着搞一个 NES 模拟器玩玩,目标在浏览器中运行,断断续续搞了一个月之后基本五脏俱全了,声音和图像都没啥大问题

    github 地址:tsnes

    在线演示地址:tsnes-demo

    当初做模拟器的时候网上也找不到完整的入门教程,所以干脆就自己抽空慢慢更新教程了:NES 模拟器开发教程

    模拟器效果图:

    重装机兵 p1

    Mario1 p2

    我的 18 款 MBP i7 CPU,在 Chrome 中运行 CPU 占用大概 70%,所以理论上 i5 应该也可以全速模拟。

    另外由于音频和绘图也会占用不少 CPU,所以如果采用 Web worker 将模拟器的线程分离出去,理论上在手机中应该也能全速模拟

    由于我是以库的形式进行开发的,所以没有花心思美化页面(~~主要还是懒~~)

    55 条回复    2020-04-11 12:20:23 +08:00
    zhuawadao
        1
    zhuawadao  
       2020-04-06 13:57:30 +08:00
    别让楼主灰心,支持一下~
    Mohanson
        2
    Mohanson  
       2020-04-06 13:59:58 +08:00   1
    lzdyes
        3
    lzdyes  
       2020-04-06 14:20:05 +08:00
    厉害了!
    yuuko
        4
    yuuko  
       2020-04-06 14:24:32 +08:00
    厉害了
    anUglyDog
        5
    anUglyDog  
       2020-04-06 14:39:33 +08:00
    anUglyDog
        6
    anUglyDog  
       2020-04-06 14:40:49 +08:00
    你这做好看点可以引流啊,太有情怀了
    idealhs
        7
    idealhs  
       2020-04-06 14:47:00 +08:00
    挺好奇,为什么如此低性能的一个机器,浏览器的模拟器跑起来这么吃资源啊
    GPLer
        8
    GPLer  
       2020-04-06 14:50:56 +08:00
    @idealhs 模拟本身就有性能损失,更不用说用的是脚本语言,执行效率本身就不高,原始的机器性能虽然低,但好歹利用率高,性能浪费的少。
    LukeChien
        9
    LukeChien  
       2020-04-06 15:09:45 +08:00 via Android
    好像见过 WebAssembly 做的,那个性能会好一些,楼主同样
    zj
        10
    zj  
       2020-04-06 15:25:43 +08:00
    这个要支持下。
    across
        11
    across  
       2020-04-06 15:25:46 +08:00
    看了文档还没写到显示部分,是用 webgl 画?
    across
        12
    across  
       2020-04-06 15:27:58 +08:00
    @across 看了下 ppu 代码是纯手动画的啊,怪不得
    renmu
        13
    renmu  
       2020-04-06 15:37:49 +08:00 via Android
    我不当勇士了,我要回家修战车
    esw
        14
    esw  
    OP
       2020-4-06 15:47:56 +08:00
    @zhuawadao 谢谢!
    esw
        15
    esw  
    OP
       2020-04-06 15:51:30 +08:00
    @idealhs NES PPU 时钟 5MHZ 以上,也就是说模拟的时候每秒要执行 500w 以上次运算,而且每次运算需要很多逻辑来完成,再加上 JS 性能损耗,所以比较费 CPU
    esw
        16
    esw  
    OP
       2020-04-06 15:53:11 +08:00
    @across 目前是 PPU 生成 RGB 点阵数据直接扔给 canvas 画图和缩放,只不过都在一个线程完成了
    firefox12
        17
    firefox12  
       2020-04-06 15:57:39 +08:00
    很牛逼 我想问是不是要把 cpu ppu 系统本身全模拟出来 再做?
    esw
        18
    esw  
    OP
       2020-04-06 16:03:21 +08:00
    @firefox12 我是找一些简单的或者自己写的测试程序,然后一点一点开发,不需要一下子全模拟好,在不熟悉所有硬件行为的情况下也不现实
    firefox12
        19
    firefox12  
       2020-04-06 16:08:20 +08:00
    @esw 但是 没有模拟 cpu 和 ppu 你怎么让卡带里的内容跑起来? 我的看法 是读卡带文件 ,然后让模拟 cpu 开始运行里面的二进制,然后让结果显示出来吧。
    zwxharry
        20
    zwxharry  
       2020-04-06 16:13:30 +08:00
    重装机兵回忆杀,红狼,尼娜
    esw
        21
    esw  
    OP
       2020-04-06 16:24:02 +08:00
    @firefox12 对,首先开发 CPU,使用 http://nickmass.com/images/nestest.nes 来开发,它有 log 可以对照: http://www.qmtpro.com/~nes/misc/nestest.log ,这样就可以一条指令一条指令地开发,同时用 log 来检测错误,最终整个文件正常运行完就说明 CPU 大部分工作开发完了,然后使用同样的方法,一点一点开发 PPU
    Arrowing
        22
    Arrowing  
       2020-04-06 17:10:24 +08:00
    重装机兵好评,upupup
    Warder
        23
    Warder  
       2020-04-06 17:22:01 +08:00
    很强,一个月就做好了啊
    mengkun
        24
    mengkun  
       2020-04-06 18:15:26 +08:00
    太强了……
    hive
        25
    hive  
       2020-04-06 19:46:00 +08:00
    收下我的膝盖
    superliwei
        26
    superliwei  
       2020-04-06 20:05:57 +08:00
    很强。。。
    esw
        27
    esw  
    OP
       2020-04-06 22:14:49 +08:00
    @Warder 不算完全做好,nes mapper 太多了,简直就是无底洞,目前只完成了一些常用 mapper
    esw
        28
    esw  
    OP
       2020-04-06 22:15:21 +08:00
    @Mohanson 学习了!
    Mohanson
        29
    Mohanson  
       2020-04-06 22:21:59 +08:00
    @esw 哈哈, 我还写过雅达利街机的模拟器: https://github.com/mohanson/space-invaders, 这些游戏机因为没有操作系统所以模拟起来比较容易, 到 PS 时代后的机器就不好模拟了, 去年想过做 switch emu, 调研了一下就立马放弃了.
    Meltdown
        30
    Meltdown  
       2020-04-06 22:23:50 +08:00 via Android
    膜拜
    zhw2590582
        31
    zhw2590582  
       2020-04-06 22:34:08 +08:00
    可以大概说说怎么个原理吗
    luny
        32
    luny  
       2020-04-06 23:45:37 +08:00
    学习了!
    Archeb
        33
    Archeb  
       2020-04-07 08:02:09 +08:00 via iPhone
    楼主!
    happy8109
        34
    happy8109  
       2020-04-07 09:37:09 +08:00
    实现个实时存盘吧
    esw
        35
    esw  
    OP
       2020-04-07 09:47:28 +08:00
    @Mohanson 是啊,资料太少,其他主机基本都没有 nesdev 这样全的网站了
    esw
        36
    esw  
    OP
       2020-04-07 09:48:19 +08:00
    @zhw2590582 其实就是软件模拟 NES 里面芯片的逻辑,然后电信号变成函数调用
    esw
       37
    esw  
    OP
       2020-04-07 09:48:54 +08:00
    @happy8109 存盘已经实现了,现在每 3 秒保存在 localstorage 里面
    esw
        38
    esw  
    OP
       2020-04-07 09:49:40 +08:00
    @happy8109 刚看错了,才反应过来你说的是实时存档,这个确实还没搞
    augustheart
        39
    augustheart  
       2020-04-07 10:35:49 +08:00
    @esw gba 啊,唯一一台主机发售前就让人给模拟了的游戏机……
    UnknownR
        40
    UnknownR  
       2020-04-07 10:55:50 +08:00
    卧槽,star 一个学习一下
    eivs
        41
    eivs  
       2020-04-07 11:32:55 +08:00
    这个感觉更流程一些

    https://github.com/bfirsh/jsnes
    wanguorui123
        42
    wanguorui123  
       2020-04-07 14:16:26 +08:00
    666
    baxtergu
        43
    baxtergu  
       2020-04-07 16:50:46 +08:00
    在 github 发现了这个仓库看了下代码,一开始以为是对 jsnes 的 ts 实现,后来发现好像不是。不过楼主厉害 一个月能做成这样,666
    sivacohan
        44
    sivacohan  
    PRO
       2020-04-07 16:54:16 +08:00
    @Mohanson 我支持了一个小额赞助~
    yun77op
        45
    yun77op  
       2020-04-07 17:07:43 +08:00
    厉害,可以尝试下用 assemblyscript 把 ts 转成 WebAssembly
    Mohanson
        46
    Mohanson  
       2020-04-07 17:13:38 +08:00
    @sivacohan 天啦噜, 这是我收到过最大的一笔赞助费! 谢谢老板(认真
    exceptionplayer1
        47
    exceptionplayer1  
       2020-04-07 17:37:06 +08:00
    真厉害,大佬
    lneoi
        48
    lneoi  
       2020-04-07 17:56:27 +08:00
    厉害厉害
    boks
        49
    boks  
       2020-04-07 18:04:23 +08:00
    牛逼,我最近刚好也想搞这个。
    lights
        50
    lights  
       2020-04-07 18:10:13 +08:00
    重装机兵在国内真的好有名啊
    esw
        51
    esw  
    OP
       2020-04-07 19:37:35 +08:00
    @eivs jsnes 之前看过源码,不过 es5 看得脑阔疼
    esw
        52
    esw  
    OP
       2020-04-07 19:37:54 +08:00
    @yun77op js 的动态特性不一定能转把?
    nazhenhuiyi294
        53
    nazhenhuiyi294  
       2020-04-08 09:55:18 +08:00
    有点流批
    uestcfei
        54
    uestcfei  
       2020-04-09 11:26:08 +08:00
    这个是没有支持所有的 nes 格式的吗?我下载的有一些 nes 的游戏,运行提示:Unsupported mapper: 150,file 看了一下,没啥区别啊。和好奇这个 nes 文件的格式。
    esw
        55
    esw  
    OP
       2020-04-11 12:20:23 +08:00   2
    @uestcfei 没有,nes 有几百种 mapper,大部分 mapper 逻辑都是不同的,所以要全支持的话相当于要实现上百颗芯片的逻辑,这是非常耗时耗力的,所以目前只支持了任天堂官方几个常用的 mapper 和重装机兵的 mapper:mapper 0-4,mapper 74
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     836 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 39ms UTC 20:50 PVG 04:50 LAX 12:50 JFK 15:50
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86