365 lines
11 KiB
JavaScript
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)});
|