emulator/fc/js/nes-embed.js

365 lines
11 KiB
JavaScript

var SCREEN_WIDTH = 256;
var SCREEN_HEIGHT = 240;
var FRAMEBUFFER_SIZE = SCREEN_WIDTH*SCREEN_HEIGHT;
var canvas_ctx, image;
var framebuffer_u8, framebuffer_u32;
var AUDIO_BUFFERING = 512;
var SAMPLE_COUNT = 4*1024;
var SAMPLE_MASK = SAMPLE_COUNT - 1;
var audio_samples_L = new Float32Array(SAMPLE_COUNT);
var audio_samples_R = new Float32Array(SAMPLE_COUNT);
var audio_write_cursor = 0, audio_read_cursor = 0;
// require(['network.js'], function (foo) {
// network = foo
// });
function getParameter (t) {
var e = window.location.search,
i = new RegExp(t + "=([^&?]*)", "ig");
return e.match(i) ? e.match(i)[0].substr(t.length + 1) : null
}
var netmode = getParameter("roomId")?true:false;
var worker = new Worker('./js/jsnes.min.js');
worker.postMessage({
f:"netmode",
data:netmode
});
var KEY_MAP = {
ST: 13,
SE: 9,
A: 65,
B: 83,
Y: 50,
X: 49,
AB: [65, 83],
UP: 38,
DOWN: 40,
LEFT: 37,
RIGHT: 39,
L_D: [37, 40],
L_U: [37, 38],
R_D: [39, 40],
R_U: [39, 38]
};
var player = 1;
window.vm = {
oldDire: null,
keyEvent: function(t, e, i) {
var r = KEY_MAP[t];
Array.isArray(r) ? (vm.simulateKeyPress(r[0], e), vm.simulateKeyPress(r[1], e)) : vm.simulateKeyPress(r, e)
},
initCtrl: function() {
var s;
vm.initGameDireCtrl(function(t, e) {
var i = -1 == t ? s : ["DOWN", "L_D", "LEFT", "L_U", "UP", "R_U", "RIGHT", "R_D"][t],
r = -1 == t;
s && (s != i || r) && vm.keyEvent(s, "keyup", e), s = i, !r && vm.keyEvent(i, "keydown", e)
}), vm.initGameKeyCtrl(), $(".ctrl-wrap").on("click contextmenu touchstart touchmove touchend touchcancel tap", function(t) {
return t.stopPropagation(), t.preventDefault(), !1
})
},
initGameDireCtrl: function(u) {
var d = this,
t = $(".dire-wrap"),
p = $(".dc-centre"),
e = $(".dire-ctrl"),
l = $(".dc-dire"),
i = e.offset(),
n = i.top,
a = i.left,
f = p.width() / 2,
m = e.width() / 2,
r = function() {
p.css({
transform: "translate3d(83px,83px,0)"
}), p.css("opacity", "1"), l.css("opacity", "0")
},
y = function(t, e) {
var i = t[e];
if (!i) return {
x: 160,
y: 500
};
var r = i.pageX - a,
s = i.pageY - n;
return 600 < s ? y(t, e + 1) : {
x: r,
y: s
}
};
r(), t.on("touchstart touchmove", function(t) {
var e, i, r = y(t.touches, 0),
s = r.x,
n = r.y,
a = Math.atan2(n - m, s - m) / (Math.PI / 180);
if (l.css("transform", "rotate(" + a + "deg)"), d.onCtrlDire(a, u), (e = m - s, i = m - n, Math.sqrt(e * e + i * i)) <= 86) {
var o = s - f,
h = n - f;
p.css("transform", "translate3d(" + o + "px," + h + "px,0)")
} else {
var c = a * Math.PI / 180;
o = m + 86 * Math.cos(c) - f, h = m + 86 * Math.sin(c) - f;
p.css("transform", "translate3d(" + o + "px," + h + "px,0)")
}
"touchstart" === t.type && (p.css("opacity", "0.8"), l.css("opacity", "0.6"))
}).on("touchend", function() {
r(), u(-1, 0), d.oldDire = -1
})
},
initGameKeyCtrl: function() {
var s = this;
$(".key-btn").bind("touchstart touchend", function(t) {
var e = $(t.target),
i = e.attr("data-key"),
r = "touchstart" === t.type;
s.keyEvent(i, r ? "keydown" : "keyup", 0), e[r ? "addClass" : "removeClass"]("btn-on")
})
},
onCtrlDire: function(t, e) {
this.onCtrlDire;
var i ;//= Math.round((t + 180) / 45) % 8;
var abst = Math.abs(t);
if((abst>=40&&abst<=50)||(abst>=130&&abst<=140)){
i = Math.round((t + 180) / 45) % 8;
}
else{
i = Math.round((t + 180) / 90) % 4*2;
}
this.oldDire != i && (e(i, t), this.oldDire = i)
},
simulateKeyPress: function(t, e) {
if(!netmode){
worker.postMessage({ f:"keypad",
data:{keyCode:t,action:e}
});
}
else{
var data = {
m:NetEnum.JUMP,
v:{
keyCode:t,
keyaction:e,
player:player
},
}
NetWorkManage.sendFrameEvent(data);
}
}
};
window.onload = function(){
var gameId = getParameter("id")
// var path = "http://h5games-al.kingsome.cn/emulator-static/roms/" + gameId + ".nes"
var path = "http://192.168.100.232:7008/roms/" + gameId + ".nes"
nes_load_url("screen", path)
vm.initCtrl()
if(netmode){
var roomId = getParameter("roomId")
NetWorkManage.initengine();
NetWorkManage.cbOnLogin = function(res){
if(res.status==0){
console.log(res)
NetWorkManage.cbOnLogin = null;
if(roomId =="0"){
NetWorkManage.engine.createRoom('testroom',2,"");
}
else{
player = 2;
NetWorkManage.engine.joinRoom(roomId,"");
}
}
}
NetWorkManage.cbOnJoinRoom = function(res){
NetWorkManage.gameStart();
};
var updateframe =function(){
if(NetWorkManage.frames.length >0 ){
var fr = NetWorkManage.frames.shift();
if(fr.isnet == true){
NetWorkHandle.processFrame(fr);
}
worker.postMessage({ f:"updateframe"});
if(fr.frameIndex<NetWorkManage.frameIndex){
updateframe();
}
}
}
setInterval(function() {
updateframe();
},1000/60)
}
}
var script_processor=null
var audio_ctx = null
function initAudioEvent() {
script_processor && (script_processor.disconnect(audio_ctx.destination), script_processor.onaudioprocess = null, script_processor = null)
audio_ctx && audio_ctx.close().catch(handleError)
window.AudioContext = window.webkitAudioContext || window.AudioContext
audio_ctx = new window.AudioContext ();
script_processor = audio_ctx.createScriptProcessor(4096, 0, 2);
script_processor.onaudioprocess = audio_callback;
script_processor.connect(audio_ctx.destination);
$(".key-btn").unbind("touchstart", initAudioEvent)
}
// function onAnimationFrame(){
// window.requestAnimationFrame(onAnimationFrame);
// // image.data.set(framebuffer_u8);
// // canvas_ctx.putImageData(image, 0, 0);
// nes.frame();
// }
function audio_remain(){
return (audio_write_cursor - audio_read_cursor) & SAMPLE_MASK;
}
function audio_callback(e){
// var i = e.outputBuffer.getChannelData(0),
// s = e.outputBuffer.getChannelData(1),
// r = i.length;
// t.buffer.size() < 2 * r && t.onBufferUnderrun && t.onBufferUnderrun(t.buffer.size(), 2 * r);
// try {
// var n = t.buffer.deqN(2 * r)
// } catch(e) {
// for (var h = (t.buffer.size(), 0); h < r; h++) i[h] = 0,
// s[h] = 0;
// return
// }
// for (var a = 0; a < r; a++) i[a] = n[2 * a],
// s[a] = n[2 * a + 1]
var dst = e.outputBuffer;
var len = dst.length;
var dst_l = dst.getChannelData(0);
var dst_r = dst.getChannelData(1);
for(var i = 0; i < len; i++){
var src_idx = (audio_read_cursor + i) & SAMPLE_MASK;
dst_l[i] = audio_samples_L[src_idx];
dst_r[i] = audio_samples_R[src_idx];
}
audio_read_cursor = (audio_read_cursor + len) & SAMPLE_MASK;
}
// 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;
// }
// }
function nes_init(canvas_id){
var canvas = document.getElementById(canvas_id);
canvas_ctx = canvas.getContext("2d");
image = canvas_ctx.getImageData(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
canvas_ctx.fillStyle = "black";
canvas_ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
// Allocate framebuffer array.
var buffer = new ArrayBuffer(image.data.length);
worker.postMessage({
f:"setBuffer",
data:image.data.length
});
framebuffer_u8 = new Uint8ClampedArray(buffer);
framebuffer_u32 = new Uint32Array(buffer);
$(".key-btn").bind("touchstart", initAudioEvent)
// Setup audio.
// var aaa = window.webkitAudioContext || window.AudioContext
// var audio_ctx = new aaa();
// var script_processor = audio_ctx.createScriptProcessor(4096, 0, 2);
// script_processor.onaudioprocess = audio_callback;
// script_processor.connect(audio_ctx.destination);
}
var bodgeInterval
function nes_boot(rom_data){
worker.postMessage({
f:"nesloadROM",
data:rom_data
});
}
// function nes_load_data(canvas_id, rom_data){
// nes_init(canvas_id);
// nes_boot(rom_data);
// }
function nes_load_url(canvas_id, path){
nes_init(canvas_id);
var req = new XMLHttpRequest();
req.open("GET", path);
req.overrideMimeType("text/plain; charset=x-user-defined");
req.onerror = () => console.log(`Error loading ${path}: ${req.statusText}`);
req.onload = function() {
if (this.status === 200) {
nes_boot(this.responseText);
} else if (this.status === 0) {
// Aborted, so ignore error
} else {
req.onerror();
}
};
req.send();
}
worker.onmessage = function(event){
if(event.data.f == "frame"){
// framebuffer_u8 = event.data.data
image.data.set(event.data.data.framebuffer_u8);
canvas_ctx.putImageData(image, 0, 0);
audio_samples_L=event.data.data.audio_samples_L
audio_samples_R=event.data.data.audio_samples_R
audio_read_cursor=event.data.data.audio_read_cursor
}
}
// document.addEventListener('keydown', (event) => {keyboard(nes.buttonDown, event)});
// document.addEventListener('keyup', (event) => {keyboard(nes.buttonUp, event)});