继续分享个没用的技术,现在ios上不越狱好像找不到能用的gba模拟器,最近偶然在GitHub上发现一个大牛用JavaScript写的gba模拟器,居然可以流畅运行大多数gba游戏,像口袋妖怪,塞尔达啥的,只是只能用电脑键盘操作,存档功能也没法用,于是克隆了一份代码简单修改了下,把keydown和keyup事件改成了手机上的touchstart和touchend,覆盖了window.event,改成自定义的keycode,这样就可以在手机上用button模拟gba键盘了,存档部分也做了简单的修改,使其能导入和导出存档,还是先上效果图。

这个项目在GitHub上的地址为GBA.js (endrift.github.io),粗略的看了下,原作者用JavaScript模拟了一个gba掌机cpu和内存,在上面运行thumb指令集,thumb指令集也是ARM指令集的一种,所有的显存操作,键盘事件的监听都由虚拟的cpu执行,看了下默认的时钟是16毫秒,也就是每16毫秒刷新一下屏幕显示和声音以及键盘的监听。

this.throttle = 16; // This is rough, but the 2/3ms difference gives us a good overhead

var self = this;
    window.queueFrame = function (f) {
        self.queue = window.setTimeout(f, self.throttle);
    };

可以看到原作者介绍这个cpu帧率16ms就足够了,要是硬件足够好可以调整到2或者3毫秒。

下面这段代码就是键盘的监听,模拟gba键盘的按下和弹起,可以看到这个this.currentDown就是gba键盘键值,虚拟的cpu会不断地监听它的变化,然后执行相应的指令。

function GameBoyAdvanceKeypad() {this.KEYCODE_LEFT = 37;this.KEYCODE_UP = 38;this.KEYCODE_RIGHT = 39;this.KEYCODE_DOWN = 40;this.KEYCODE_START = 13;this.KEYCODE_SELECT = 220;this.KEYCODE_A = 90;this.KEYCODE_B = 88;this.KEYCODE_L = 65;this.KEYCODE_R = 83;this.GAMEPAD_LEFT = 14;this.GAMEPAD_UP = 12;this.GAMEPAD_RIGHT = 15;this.GAMEPAD_DOWN = 13;this.GAMEPAD_START = 9;this.GAMEPAD_SELECT = 8;this.GAMEPAD_A = 1;this.GAMEPAD_B = 0;this.GAMEPAD_L = 4;this.GAMEPAD_R = 5;this.GAMEPAD_THRESHOLD = 0.2;this.A = 0;this.B = 1;this.SELECT = 2;this.START = 3;this.RIGHT = 4;this.LEFT = 5;this.UP = 6;this.DOWN = 7;this.R = 8;this.L = 9;this.currentDown = 0x03FF;this.eatInput = false;this.gamepads = [];this.keyboardHandler = function(e) {var toggle = 0;switch (e.keyCode) {case this.KEYCODE_START:toggle = this.START;break;case this.KEYCODE_SELECT:toggle = this.SELECT;break;case this.KEYCODE_A:toggle = this.A;break;case this.KEYCODE_B:toggle = this.B;break;case this.KEYCODE_L:toggle = this.L;break;case this.KEYCODE_R:toggle = this.R;break;case this.KEYCODE_UP:toggle = this.UP;break;case this.KEYCODE_RIGHT:toggle = this.RIGHT;break;case this.KEYCODE_DOWN:toggle = this.DOWN;break;case this.KEYCODE_LEFT:toggle = this.LEFT;break;default:return;}toggle = 1 << toggle;if (e.type == "keydown") {this.currentDown &= ~toggle;} else {this.currentDown |= toggle;}if (this.eatInput) {window.event.preventDefault();}
};}GameBoyAdvanceKeypad.prototype.gamepadHandler = function(gamepad) {var value = 0;if (gamepad.buttons[this.GAMEPAD_LEFT] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.LEFT;}if (gamepad.buttons[this.GAMEPAD_UP] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.UP;}if (gamepad.buttons[this.GAMEPAD_RIGHT] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.RIGHT;}if (gamepad.buttons[this.GAMEPAD_DOWN] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.DOWN;}if (gamepad.buttons[this.GAMEPAD_START] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.START;}if (gamepad.buttons[this.GAMEPAD_SELECT] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.SELECT;}if (gamepad.buttons[this.GAMEPAD_A] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.A;}if (gamepad.buttons[this.GAMEPAD_B] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.B;}if (gamepad.buttons[this.GAMEPAD_L] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.L;}if (gamepad.buttons[this.GAMEPAD_R] > this.GAMEPAD_THRESHOLD) {value |= 1 << this.R;}this.currentDown = ~value & 0x3FF;
};GameBoyAdvanceKeypad.prototype.gamepadConnectHandler = function(gamepad) {this.gamepads.push(gamepad);
};GameBoyAdvanceKeypad.prototype.gamepadDisconnectHandler = function(gamepad) {this.gamepads = self.gamepads.filter(function(other) { return other != gamepad });
};GameBoyAdvanceKeypad.prototype.pollGamepads = function() {var navigatorList = [];if (navigator.webkitGetGamepads) {navigatorList = navigator.webkitGetGamepads();} else if (navigator.getGamepads) {navigatorList = navigator.getGamepads();}// Let's all give a shout out to Chrome for making us get the gamepads EVERY FRAMEif (navigatorList.length) {this.gamepads = [];}for (var i = 0; i < navigatorList.length; ++i) {if (navigatorList[i]) {this.gamepads.push(navigatorList[i]);}}if (this.gamepads.length > 0) {this.gamepadHandler(this.gamepads[0]);}};GameBoyAdvanceKeypad.prototype.registerHandlers = function() {//window.addEventListener("keydown", this.keyboardHandler.bind(this), true);//window.addEventListener("keyup", this.keyboardHandler.bind(this), true);//window.addEventListener("gamepadconnected", this.gamepadConnectHandler.bind(this), true);//window.addEventListener("mozgamepadconnected", this.gamepadConnectHandler.bind(this), true);//window.addEventListener("webkitgamepadconnected", this.gamepadConnectHandler.bind(this), true);//window.addEventListener("gamepaddisconnected", this.gamepadDisconnectHandler.bind(this), true);//window.addEventListener("mozgamepaddisconnected", this.gamepadDisconnectHandler.bind(this), true);//window.addEventListener("webkitgamepaddisconnected", this.gamepadDisconnectHandler.bind(this), true);
};

因为我要把这个模拟器移植到手机端,所以注释掉了所有的键盘监听事件,然后把window.event这个参数构造成了自定义的对象,把按键改成了button,然后就可以这样调用<button ontouchstart="gba.keypad.keyboardHandler({keyCode:65,type:'keydown'})"  ontouchend="gba.keypad.keyboardHandler({keyCode:65,type:'keyup'})">L</button>,这个就是L按键,其他的类似。

然后就是存档的导入,我们可以在mmu.js找到这个方法,如下:

this.save.replaceData(save);,这个方法就可以把读取到的存档数据加载到内存中,但是直接运行会发现报错,this.save为null,继续跟踪会发现这个this.save对象是先加载完游戏镜像文件之后才会创建的,如下:

这样我们只需要把读取存档的操作修改为加载游戏镜像之后 就可以了。

最后来一张GitHub上的版本截图

看完原版代码,不得不佩服原作者的知识水平,一定是硬件和软件都精通的人写的,尤其是那些cpu指令集的模拟,突然想起之前看新闻说国外有人用JavaScript写了个虚拟机跑linux系统,之前还当作笑话,现在看来也不是没有可能,等找到相关代码研究下会继续和大家分享。

javascript gba游戏模拟器相关推荐

  1. gba模拟器ios_苹果手机iphone安装GBA游戏模拟器教程

    GBA游戏模拟器是体验儿童时代经典掌机游戏的必备武器,iPhone6/6 Plus.iPhone5s/5.iPhone4s等已经升级到iOS8系统的苹果手机也能完美使用,iOS7就更不在下了.下面跟下 ...

  2. 模拟器不全屏_iOS 14实测GBA游戏模拟器下载

    玩捷径 - 带你玩转iPhone捷径 hello大家好,我是小唐.因公众号目前的推送机制已改变,可能有时候会看不到小唐新写的作文. 建议大家点击公众号资料页面右上角「...」,把公众号设为星标(置顶) ...

  3. android 安卓GBA GBC NDS FC SFC 街机游戏模拟器源码

    提供:  GBC游戏模拟源码  GBA游戏模拟源码  MAME街机模拟器源码  nds模拟器源码  NES模拟器源码  psp模拟器源码  sfc snes9x模拟器源码  sfc Snes游戏模拟器 ...

  4. linux强大的游戏模拟器--GBA

    Linux强大的游戏模拟器,模拟的效果以及CPU的占用都非常低,主要是用来玩GBA和FC的游戏,玩GBA游戏比Linux版VBA强的不是一点半点,Linux版VBA可以说就是一个半成品,不说功能方面, ...

  5. 随身的娱乐!PPC游戏模拟器详细介绍[转贴]

    原文:http://it.21cn.com/digital/PDA/2004/07/23/1669347_1.shtml 虽然我们常说不要游戏人生,但是在人生中玩游戏却会带给我们很大的乐趣.无论是早期 ...

  6. 3ds运行linux,全能游戏模拟器 RetroArch 1.7.0发布,附Ubuntu中PPA安装

    RetroArch在几天前已经释出了1.7.0版本. RetroArch是一款功能强大的全能游戏模拟器,在多个平台都有对应的软件,深受游戏爱好者的喜爱,例如PS1.GBA.FC等,它使您能够通过其友好 ...

  7. java版gbc模拟器怎么用,GBA/GBC模拟器VisualBoyAdvance图文使用教程

    特别说明,本模拟器完全兼容GBC系列游戏,GBC游戏也可以按照下面的流程打开. 下载地址: GBA/GBC模拟器VisualBoyAdvance 1.将下载到的模拟器解压缩,你会看到一个roms文件夹 ...

  8. higan(bsnes)游戏模拟器的编译和试玩

    higan 是一款开源的游戏模拟器实现,这里直接引用英文介绍: higan (formerly bsnes) is a Nintendo multi-system emulator that bega ...

  9. java手机游戏模拟器下载_Java手机游戏模拟器

    Java手机游戏模拟器主要针对诺基亚S60系列(屏幕176*220)手机以及其他大屏手机(小屏游戏也可运行,但不能全屏显示),是一款非常简单而且实用的JAVA游戏模拟器,可以正常运行绝大部分JAVA手 ...

  10. bios模拟器_比游戏模拟器罕见一百倍!99%的人没见过!真实用!

    很多小伙伴平时自己或者朋友的电脑可能会遇到问题,比较严重的情况下,可能就需要重装系统了!但是在重装系统前一半是需要对BIOS进行设置的,不少人就卡到这了!对BIOS的各项功能不了解,怕设置出错!这怎么 ...

最新文章

  1. “醒事”就在一瞬间 --- 一个真实的故事 (文PPT)
  2. 2019第十届蓝桥杯比赛总结(B组c/c++)
  3. 2020 年 4 月全国程序员工资新鲜出炉,我拖后腿了!
  4. 浅谈RDMA流控设计
  5. 《Too Much Heaven》
  6. 301.inc.php,DeDeCMS默认首页及WWW域的301跳转
  7. 985材料研究生转行自动化,收割一众大厂,拿到54w的工作
  8. context:component-scan标签的use-default-filters属性的作用以及原理分析
  9. Spring 一二事(1)
  10. 散列表的开放定址法以及再散列法(C语言)
  11. 【软件工程】系统流程图——期末快速复习用
  12. C#学习 - XML Serialization
  13. 基于虹软人证核验 2.0 Android SDK开发集成入门
  14. 视频播放器(AVPlayer)
  15. iphone12绿色好看 iphone12系列哪个颜色好看
  16. linux安装过程进入终端,怎么安装国产Linux中标麒麟操作系统?安装全过程分享...
  17. 半双工通信和全双工通信的区别
  18. [转帖]房博士教你购房(一)
  19. 多路复用,讲的很明白
  20. C++ QT开发人机象棋(大纲)

热门文章

  1. IEEE论文格式要求(翻译)
  2. 达内 python培训视频教程
  3. Dev-cpp5.4.0安装及下载
  4. 接口测试用例设计思路_最全测试用例设计方法~思路分析
  5. FusionChartsFree在JSP中的用法
  6. 关于时频分析的一些感想
  7. 《编程珠玑》——读书笔记1
  8. 打印机出现另存为xps_打印机打印文件显示另存为xps格式的文件 - 卡饭网
  9. linux万兆网卡驱动下载,Intel英特尔PCIe万兆网卡驱动5.11.3版For Linux(2021年3月5日发布)...
  10. 2017年3月4月无人机航空摄影总结