我有一哥们“烧鸡”,大名白赞记。

光听名字就感觉挺大气是吧,其实和我一样就是个不起眼的普通90后。

虽说这小子年纪轻轻,人却比较怀旧,尤其痴迷红白机之类的复古游戏(当然我也喜欢)。

很奇怪的是到现在好像有两个月没见着这小子了,没成想前两天在菜市场门口给撞上了。

搁以前只要一打照面这小子铁定三句话不离游戏,不过这回好像有点不一样了。


我一瞅他购物袋里那一片绿油油就大概知道怎么回事了。

果不其然,这小子一上来就和我吐槽最近过得有多惨,然后又怀念上以前那小日子有多美。

以前划水摸鱼、带薪拉屎,想怎么玩就怎么玩,别提多得劲了,可如今日薄西山、今非昔比,好日子是一去不复返啊!

自从换了新东家,不但工作忙得脚后跟直打后脑勺,而且上下班通勤时间都比原先拉长了好多。

这小子一顿扒拉扒拉,直言少壮不努力,老大徒伤悲,这整得都没空玩游戏了。

我去,这小嘴儿巴巴的,我愣是插不上话!

得,江山易改,这本性难移啊,我一瞅这小子还这副德性,硬是把想劝慰的话又给咽了回去。


好么,接着听这小子闲聊扒拉,结果他告诉我,还好有时还能偷懒玩一会在线红白机游戏。

“只要打开浏览器就行,不用安装任何软件,随时随地方便非常。”

“哦,是么,还能这么玩?呵呵...”,我得配合尬笑一下,做出我非常好奇的样子接着听他吹。

我心想他说的这个在线红白机游戏我知道,就是通过 Web 网页呈现,并且可以和正常模拟器一样地玩游戏。

这个我是见过,没啥新鲜,瞧这小子眉飞色舞那得瑟样......


不知道是不是我当时的表情演技有点过劲儿,他顿了一下,冷不丁地问了我一句:“这玩意挺好挺方便,你有空也玩两把哈!只是不知道这玩意是啥原理,怎么给整出来的,挺牛叉滴!”

俗话说,言者无心,听者有意!

过后三言两语我打发了这小子,事后在回家的路上我就琢磨了,是哈,这玩意是怎么做到只要打开网页就能玩红白机游戏的呢?


JSNES

带着疑问,我打开了电脑开始在网上搜索,心里正猜测这个红白机在线玩功能是不是基于 JS 的,还是说有其他高深的知识在里面。

果然很快我找到了 Github 上的一个项目:JSNES

https://github.com/bfirsh/jsnes


作者 bfirsh 大神还有一个个人主页:

https://jsnes.org/


我们打开看看,简洁的全黑页面显得格外有内涵(花里胡哨你又说有艺术范),表格中简单罗列了几个用于演示的游戏。


随便点开一个游戏,比如 Concentration Room ,页面跳转并开始加载游戏。


不一会儿游戏加载完毕,我们就可以开始玩了。


在此期间点击右上角的 Controls 按钮可以调整修改自己惯用的按键。


很神奇对吧,操作也不复杂,很明显它就是基于 JavaScript 的一个 NES 模拟器。

那么这玩意怎么实现的呢?


关于 JSNES 的介绍倒是很简单,然而介绍页上面涉及到的诸如如何安装等等的 JS 理论知识却着实难倒了我,毕竟我只能算是半个野生程序员,稍微复杂一点的知识我就抓瞎了。

嗯,既然是 JS 写的,那么肯定是跑在浏览器上,我猜应该和服务端关系不大。

OK,那我们就来大胆一试吧!


测试 JSNES

怎么试?

我的思路很简单,就是将项目代码放到 Web 服务器上,然后用浏览器打开跑一跑看看,希望有门。


好,首先将 bfirsh/jsnes 源代码下载下来(文末统一下载)吧。


接着打开压缩包,找到文件夹 example ,将它释放出来备用。


这个 example 文件夹内有四个文件。

  • InterglacticTransmissing.nes - 演示游戏 ROM 文件
  • nes-embed.html - 网页文件
  • nes-embed.js - 自定义脚本文件
  • README.md - 说明文件


关于这四个文件,我们实际只用到前三个。

注意,除这三个文件之外呢,我们从 nes-embed.html 文件中可以看到,还需要引用 jsnes.min.js 文件。

<script type="text/javascript" src="https://unpkg.com/jsnes/dist/jsnes.min.js"></script>
 

这个文件就是 JSNES 实现的关键,我已经将它打包放到下载中了。


好,接下来我们需要修改一些代码,原先的演示示例存在很多 BUG ,以我现有的水平还不能将它们都搞定。

不过还好我修复了几个比较主要的地方,比如异步加载游戏时不显示的问题。


在页面文件 nes-embed.html 中有如下代码。

<script>window.onload = function(){nes_load_url("nes-canvas", "InterglacticTransmissing.nes");}</script>
 

这行代码的意思是在当前页面加载完成后再加载 nes 游戏并渲染到 canvas 上。

可是代码似乎还是有缺陷,涉及到使用原始代码来实现 AJAX 的异步提交,在使用 window.onload 时就不灵了,老是失败,游戏画面怎么也不显示。


此外还有修改按键功能的问题。

老外的按键习惯与我们有很大的不同,因此我们需要打开nes-embed.js 文件,将其中的按键修改为我们平时喜欢的使用方式。

设定按键的代码段如下:

function keyboard(callback, event){
    var player = 1;
    switch(event.keyCode){
        case 38: // UP
            callback(player, jsnes.Controller.BUTTON_UP); break;
        case 40: // Down
            callback(player, jsnes.Controller.BUTTON_DOWN); break;
        case 37: // Left
            callback(player, jsnes.Controller.BUTTON_LEFT); break;
        case 39: // Right
            callback(player, jsnes.Controller.BUTTON_RIGHT); break;
        case 65: // 'a' - qwerty, dvorak
        case 81: // 'q' - azerty
            callback(player, jsnes.Controller.BUTTON_A); break;
        case 83: // 's' - qwerty, azerty
        case 79: // 'o' - dvorak
            callback(player, jsnes.Controller.BUTTON_B); break;
        case 9: // Tab
            callback(player, jsnes.Controller.BUTTON_SELECT); break;
        case 13: // Return
            callback(player, jsnes.Controller.BUTTON_START); break;
        default: break;
    }
}
 


case 后面用于判断按键的数字是该按键的 ASCII 码,可以到官方查询。

https://www.ascii-code.com/
 

比如我们想将 设定为 WSAD ,那么我们先要找到这几个按键的 ASCII 码,分别是十进制的 87836568 ,然后将它们写到代码中就可以了。


比如修正后的按键 ,应该是这样写。

case 87: // UP
    callback(player, jsnes.Controller.BUTTON_UP); break;
 


类似的 AB 按钮也是一样操作,找相应 ASCII 码并修改为你喜欢的按钮。

具体我们可以参考 ASCII 码表来定位所要调用的按键。


最后我们需要找一个 Web 服务程序,什么 Apache 啊、Nginx 啊、IIS 啊,总之只要是 Web 服务器就行。

并且不需要具备任何动态脚本解释功能,原因很简单嘛,JS 在浏览器上就能跑。

不过说到的这些 Web 服务引擎总感觉有点重、不亲民啊,难道我还要特意去整这些玩意才能玩到游戏吗?


不知道算不算巧合,我在前不久使用 VBRichClient 做了一个简单的 Web 服务程序 VBRichClient4WebServer.exe

本来也没多想,这玩意功能超级简单用处不大,当玩具一样,没成想却在这儿就给派上用场了。

是的,有的小伙伴应该明白了,完全可以直接用我写的这个程序嘛,不用再费劲扒拉地去专门设定一个 Web 服务器了。


用法十分简单,绿色软件,双击打开就能用了(已打包到文末下载中)。

指定好根目录、 IP 地址和端口号,点击开启服务就能跑了。


最终经过我一番折腾,将它成功改造成了我想要的样子。

为了给小伙伴们更加真实的体验,同时我也将它放到了博客页面上,大家试玩一下看看。

如果你看不到以下内容,那么请点击原文链接或阅读原文,跳转到 www.sysadm.cc 上查看吧。


截图:


在线演示(点击下面的按钮试试~):

在线演示(点击上面的按钮试试~)**


复杂一些的 JSNES 项目

不知道前面的例子各位小伙伴感觉如何?

我估计会有人吐槽,还是有 BUG ,不能换游戏,不能调画面,不能改按键,不能......

哎,总之那只是个简单的不能再简单的示例程序,更加复杂的功能肯定是没有的啊!

想要拥有这些高级而复杂的功能,要么你会写代码给加上去,要么只能寄希望于大神恩赐了。


不过还好,我这儿找到一位大神 dafeiyu ,他有个项目实现了比较复杂一些的在线游戏功能。

https://gitee.com/feiyu22/jsnes


当然了,和前面 bfirsh 类似,并不是将源代码拉过来就能用的,还是要进行一番改造。

万幸的是,dafeiyu 已经做了很多工作,项目的安装也变得比较简单,只要将几个文件夹复制下来就行了。

具体怎么做,我们接着往下看!


首先,将项目打包下载。


将压缩包中的三个文件夹( libromssrc )解压出来。

  • lib - 库文件
  • roms - 游戏文件
  • src - 在线游戏源码及脚本


其中我们主要需要修改 src 文件夹内的主网页文件 index.html ,最多再改一改界面脚本 ui.js ,其他的文件基本上不需要大动。


和前一小节一样,最后还是要找个 Web 服务器,让它跑一跑看看。

建议用我写的 VBRichClient4WebServer.exe 程序,绿色环保双击直接就能用,已将其打包到文末下载中。


虽说这个代码基本能用,但小毛病实在太多了,我精力和水平有限,改了一些地方,比如放大缩小功能等等。

我将最终改好的演示示例放在这儿,大家试玩一下。


截图:


在线演示(下面界面实际操作一下试试~):

在线演示(下面界面实际操作一下试试~):


总体来讲 dafeiyu 的代码基本的功能都有了,但还是无法和某些网站上的功能相比,例如支持双人、保存加载记录以及作弊码等等。

这些高级功能是如何实现的,有兴趣的话大家可以自行研究,如果以后我有新的突破那到时候再分享给大家吧。


容器化运行 JSNES

如果你不方便或实在懒得搭建 Web 服务,甚至连我写的 VBRichClient4WebServer 程序都不想用,那么也没啥,就问你有没有 Docker

好,你有 Docker ,那么恭喜你,JSNES 还可以做为容器跑服务的。

网上写得太复杂了,我将其大大简化了,只要你有现成的 Docker 就行。


首先我们先将镜像拉下来,如果网络不好拉不下来也别着急,我在文末下载中把镜像也打包进去了。

注意标签哈,不是 lastest ,而是 1.0.0 哦!

docker pull wangz2019/jsnes:1.0.0
 


接下来就可以直接运行镜像了。

对外暴露端口随便你指定,只要将 8081 改成你想要的就行。

docker run --rm -p 8081:80 --name jsnes -d wangz2019/jsnes:1.0.0
 


然后打开浏览器,在地址栏内输入以下网址,你自己看效果,我就不截图了。

http://服务器IP:8081/
 

哈哈,有没有成功打开?

好,要想关掉它也很简单,像下面这么干。

docker kill jsnes
 


整个过程简单粗暴,使用起来非常方便,只不过缺点就是里面的内容你不好改啊,这种仅适合体验。


写在最后

通过我自己的各种折腾测试,最后将凑合可用的程序给整理好打包,就放在这儿分享给小伙伴们吧!

声明:下载付费可以理解为付费阅读文章内容,如果你不想付费也完全没问题,但是无论付费与否,请尊重作者的辛苦劳动,谢谢理解和支持!


打包集中付费下载:

  • jsnes-bfirsh.7z - bfirsh 网管小贾修改版
  • jsnes-dafeiyu.7z - dafeiyu 网管小贾修改版
  • jsnes-master-bfirsh.zip - bfirsh 源码
  • jsnes-master-dafeiyu.zip - dafeiyu 源码
  • [Docker镜像]wangz2019_jsnes1.0.0.7z - 离线Docker镜像文件


基本用法:

1、运行 VBRichClient4WebServer.exe 程序。

2、将网管小贾修改版解压后释放到 VBRichClient4WebServer.exe 所在目录。

3、打开浏览器, bfirsh 版访问 http://ip:8888/nes-embed.htmldafeiyu 版访问 http://ip:8888/src/index.html


下载链接:https://pan.baidu.com/s/1sDzcmVxSnP5sqXNKAs7dxw

提取码:

输入阅读密码,解锁隐藏内容...



★扫码关注公众号, 发送【000986】获取阅读密码


动图演示用法


需要向小伙伴们说一下,我打包的这些程序并非完美版本,仍然还有修改增加功能的余地,请有余力的小伙伴自行调整吧。

另外需要注意的是,程序并不是支持所有的 ROM 游戏,原因有待研究。

关于 JsNes 如果我的文章有什么错误,或者你有好的想法和建议,欢迎留言评论。

最后,请各位排好队,点赞、关注、分享转发。

对了,谁有葱借我点,刚菜场忘记买了,回家又要被骂了......


将技术融入生活,打造有趣之故事。

网管小贾 / sysadm.cc



暂无评论

登录并提交评论

© 2020-present 网管小贾 | 微信公众号 @网管小贾
许可协议:CC-BY-NC 4.0 | 转载文章请注明作者出处及相关链接