From ee50a53c9a1204fc8d45617db124f38cbb3c6de7 Mon Sep 17 00:00:00 2001 From: uxer Date: Mon, 29 Apr 2019 10:44:22 +0700 Subject: [PATCH 1/4] WIP --- static/js/const.js | 19 -- static/js/gameboy_controller.js | 369 +++++++++++++++++++++++--------- static/js/global.js | 6 +- static/js/ws.js | 6 +- 4 files changed, 273 insertions(+), 127 deletions(-) diff --git a/static/js/const.js b/static/js/const.js index 11f49ae0..528544c5 100644 --- a/static/js/const.js +++ b/static/js/const.js @@ -63,25 +63,6 @@ GAME_LIST = [ -// Keyboard stuffs -KEY_MAP = { - 37: "left", - 38: "up", - 39: "right", - 40: "down", - - 90: "a", // z - 88: "b", // x - 67: "start", // c - 86: "select", // v - - // non-game - 81: "quit", // q - 83: "save", // s - 76: "load", // l - 70: "full", // f -} - /* const ( ButtonA = iota diff --git a/static/js/gameboy_controller.js b/static/js/gameboy_controller.js index ce12dee2..2395bc02 100644 --- a/static/js/gameboy_controller.js +++ b/static/js/gameboy_controller.js @@ -1,19 +1,6 @@ - // menu screen function showMenuScreen() { log("Clean up connection / frame"); - // clean up before / after menu - //try { - //inputChannel.gameboyIndeoclose(); - //} catch (err) { - //log(`> [Warning] peer connection: ${err}`); - //} - - //try { - //conn.close(); - //} catch (err) { - //log(`> [Warning] Websocket connection: ${err}`); - //} $("#game-screen").hide(); if (!DEBUG) { @@ -34,7 +21,7 @@ function showMenuScreen() { // game menu -function chooseGame(idx, force=false) { +function chooseGame(idx, force = false) { if (idx < 0 || (idx == gameIdx && !force) || idx >= GAME_LIST.length) return false; $("#menu-screen #box-art").fadeOut(400, function () { @@ -60,119 +47,297 @@ function chooseGame(idx, force=false) { log(`> [Pick] game ${gameIdx + 1}/${GAME_LIST.length} - ${GAME_LIST[gameIdx].name}`); } -function setState(e, bo) { - if (e.keyCode in KEY_MAP) { - keyState[KEY_MAP[e.keyCode]] = bo; - unchangePacket = INPUT_STATE_PACKET; - } -} -document.body.onkeyup = function (e) { - if (screenState === "menu") { - switch (KEY_MAP[e.keyCode]) { - case "left": - chooseGame(gameIdx - 1); - break; - - case "right": - chooseGame(gameIdx + 1); - break; - - case "select": - startGame(); - } - } else if (screenState === "game") { - setState(e, false); - - switch (KEY_MAP[e.keyCode]) { - case "save": - conn.send(JSON.stringify({"id": "save", "data": ""})); - break; - case "load": - conn.send(JSON.stringify({"id": "load", "data": ""})); - break; - case "full": - // Fullscreen - screen = document.getElementById("game-screen"); - - console.log(screen.height, window.innerHeight); - if (screen.height === window.innerHeight) { - closeFullscreen(); - } else { - openFullscreen(screen); - } - break; - } - } - - // global reset - if (KEY_MAP[e.keyCode] === "quit") { - endInput(); - showMenuScreen(); - } - -} +// global func function openFullscreen(elem) { - if (elem.requestFullscreen) { - elem.requestFullscreen(); - } else if (elem.mozRequestFullScreen) { /* Firefox */ - elem.mozRequestFullScreen(); - } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */ - elem.webkitRequestFullscreen(); - } else if (elem.msRequestFullscreen) { /* IE/Edge */ - elem.msRequestFullscreen(); - } + if (elem.requestFullscreen) { + elem.requestFullscreen(); + } else if (elem.mozRequestFullScreen) { /* Firefox */ + elem.mozRequestFullScreen(); + } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */ + elem.webkitRequestFullscreen(); + } else if (elem.msRequestFullscreen) { /* IE/Edge */ + elem.msRequestFullscreen(); + } } -/* Close fullscreen */ function closeFullscreen() { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if (document.mozCancelFullScreen) { /* Firefox */ - document.mozCancelFullScreen(); - } else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */ - document.webkitExitFullscreen(); - } else if (document.msExitFullscreen) { /* IE/Edge */ - document.msExitFullscreen(); - } + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.mozCancelFullScreen) { /* Firefox */ + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */ + document.webkitExitFullscreen(); + } else if (document.msExitFullscreen) { /* IE/Edge */ + document.msExitFullscreen(); + } } -document.body.onkeydown = function (e) { - if (screenState === "game") { - // game keys - setState(e, true); - } -}; - -function sendInput() { +function sendInputData() { // prepare key if (unchangePacket > 0) { - st = ""; + bits = ""; KEY_BIT.slice().reverse().forEach(elem => { - st += keyState[elem] ? 1 : 0; + bits += keyState[elem] ? 1 : 0; }); - ss = parseInt(st, 2); - console.log(`Key state string: ${st} ==> ${ss}`); + data = parseInt(bits, 2); + console.log(`Key state string: ${bits} ==> ${data}`); // send - a = new Uint8Array(1); - a[0] = ss; - inputChannel.send(a); + arrBuf = new Uint8Array(1); + arrBuf[0] = data; + inputChannel.send(arrBuf); unchangePacket--; } } -function startInput() { +function startInputTimer() { if (inputTimer == null) { - inputTimer = setInterval(sendInput, 1000 / INPUT_FPS) + inputTimer = setInterval(sendInputData, 1000 / INPUT_FPS) } } -function endInput() { +function stopInputTimer() { clearInterval(inputTimer); inputTimer = null; } + + +function setState(name, bo) { + if (name in keyState) { + keyState[name] = bo; + unchangePacket = INPUT_STATE_PACKET; + } +} + +function doButton(bo, name) { + if (bo == true) { + doButtonDown(name); + } else if (bo == false) { + doButtonUp(name); + } +} + +function doButtonDown(name) { + if (screenState === "game") { + // game keys + setState(name, true); + } +} + + +function doButtonUp(name) { + if (screenState === "menu") { + switch (name) { + case "left": + chooseGame(gameIdx - 1); + break; + + case "right": + chooseGame(gameIdx + 1); + break; + + case "select": + startGame(); + } + } else if (screenState === "game") { + setState(name, false); + + switch (name) { + case "save": + conn.send(JSON.stringify({ "id": "save", "data": "" })); + break; + case "load": + conn.send(JSON.stringify({ "id": "load", "data": "" })); + break; + case "full": + // Fullscreen + screen = document.getElementById("game-screen"); + + console.log(screen.height, window.innerHeight); + if (screen.height === window.innerHeight) { + closeFullscreen(); + } else { + openFullscreen(screen); + } + break; + } + } + + // global reset + if (name === "quit") { + stopInputTimer(); + showMenuScreen(); + } +} + +// KEYBOARD + +KEYBOARD_MAP = { + 37: "left", + 38: "up", + 39: "right", + 40: "down", + + 90: "a", // z + 88: "b", // x + 67: "start", // c + 86: "select", // v + + // non-game + 81: "quit", // q + 83: "save", // s + 76: "load", // l + 70: "full", // f +} + +document.body.onkeyup = function (e) { + if (e.keyCode in KEYBOARD_MAP) { + doButtonUp(KEYBOARD_MAP[e.keyCode]); + } +} + +document.body.onkeydown = function (e) { + if (e.keyCode in KEYBOARD_MAP) { + doButtonDown(KEYBOARD_MAP[e.keyCode]); + } +}; + + +// JOYSTICK + +/* + cross == a <--> a + circle == b <--> b + square == x <--> start + triangle == y <--> select + share <--> load + option <--> save + L2 == LT <--> full + R2 == RT <--> quit + dpad <--> up down left right + axis 0, 1 <--> second dpad +*/ +var padState, gamepadTimer; + +function getOS() { + // linux? ios? + var OSName = "unknown"; + if (navigator.appVersion.indexOf("Win")!=-1) OSName="win"; + else if (navigator.appVersion.indexOf("Mac")!=-1) OSName="mac"; + else if (navigator.appVersion.indexOf("Android")!=-1) OSName="android"; + return OSName; +} + +function getBrowser() { + var browserName = "unknown"; + if (navigator.appVersion.indexOf("Firefox")!=-1) browserName="firefox"; + if (navigator.appVersion.indexOf("Chrome")!=-1) browserName="chrome"; + if (navigator.appVersion.indexOf("Edge")!=-1) browserName="edge"; + if (navigator.appVersion.indexOf("Version/")!=-1) browserName="safari"; + if (navigator.appVersion.indexOf("UCBrowser")!=-1) browserName="uc"; + return browserName; +} + + +// only capture the last plugged joystick +window.addEventListener("gamepadconnected", (e) => { + gamepad = e.gamepad; + console.log(`Gamepad connected at index ${gamepad.index}: ${gamepad.id}. ${gamepad.buttons.length} buttons, ${gamepad.axes.length} axes.`); + console.log(gamepad); + + padIdx = gamepad.index; + + // Ref: https://github.com/giongto35/cloud-game/issues/14 + // get mapping first (default KeyMap2) + os = getOS(); + browser = getBrowser(); + + if (os == "android") { + // default of android is KeyMap1 + padMap = {2: "a", 0: "b", 3: "start", 4: "select", 10: "load", 11: "save", 8: "full", 9: "quit", 12: "up", 13: "down", 14: "left", 15: "right"}; + } else { + // default of other OS is KeyMap2 + padMap = {0: "a", 1: "b", 2: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 12: "up", 13: "down", 14: "left", 15: "right"}; + } + + if (os == "android" && (browser == "firefox" || browser == "uc")) { //KeyMap2 + padMap = {0: "a", 1: "b", 2: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 12: "up", 13: "down", 14: "left", 15: "right"}; + } + + if (os == "win" && browser == "firefox") { //KeyMap3 + padMap = {1: "a", 2: "b", 0: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit"}; + } + + if (os == "mac" && browser == "safari") { //KeyMap4 + padMap = {1: "a", 2: "b", 0: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 14: "up", 15: "down", 16: "left", 17: "right"}; + } + + if (os == "mac" && browser == "firefox") { //KeyMap5 + padMap = {1: "a", 2: "b", 0: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 14: "up", 15: "down", 16: "left", 17: "right"}; + } + + // reset state + padState = { + left: false, + right: false, + up: false, + down: false, + }; + Object.keys(padMap).forEach(k => { + padState[k] = false; + }); + + + // looper, too intense? + if (gamepadTimer) { + clearInterval(gamepadTimer); + } + + function checkAxis(bo, axis) { + if (bo != padState[axis]) { + padState[axis] = bo; + doButton(bo, axis); + } + } + + gamepadTimer = setInterval(function() { + gamepad = navigator.getGamepads()[padIdx]; + if (gamepad) { + // axis pad + corX = gamepad.axes[0]; // -1 -> 1, left -> right + corY = gamepad.axes[1]; // -1 -> 1, up -> down + checkAxis(corX <= -0.5, "left"); + checkAxis(corX >= 0.5, "right"); + checkAxis(corY <= -0.5, "up"); + checkAxis(corY >= 0.5, "down"); + + // normal button + Object.keys(padMap).forEach(k => { + if (navigator.webkitGetGamepads) { + curPressed = (gamepad.buttons[k] == 1); + } else { + curPressed = (gamepad.buttons[k].value > 0 || gamepad.buttons[k].pressed == true); + } + + if (padState[k] != curPressed) { + padState[k] = curPressed; + doButton(curPressed, padMap[k]); + } + }); + } + + }, 10); // miliseconds per hit + +}); + +window.addEventListener("gamepaddisconnected", (event) => { + clearInterval(gamepadTimer); + console.log("A gamepad disconnected:"); + console.log(event.gamepad); +}); + diff --git a/static/js/global.js b/static/js/global.js index 0ddec381..f52f7c5e 100644 --- a/static/js/global.js +++ b/static/js/global.js @@ -25,11 +25,11 @@ keyState = { right: false, // game meta keys - save: false, - load: false, + // save: false, + // load: false, // unofficial - quit: false + // quit: false } unchangePacket = INPUT_STATE_PACKET; diff --git a/static/js/ws.js b/static/js/ws.js index 5a790dac..89d91b3c 100644 --- a/static/js/ws.js +++ b/static/js/ws.js @@ -171,7 +171,7 @@ function startWebRTC() { //conn.send(JSON.stringify({"id": "start", "data": ""})); } else if (pc.iceConnectionState === "disconnected") { - endInput(); + stopInputTimer(); } } @@ -214,7 +214,7 @@ function startGame() { conn.send(JSON.stringify({"id": "start", "data": gamelist[gameIdx].file, "room_id": roomID.value, "player_index": parseInt(playerIndex.value, 10)})); // clear menu screen - endInput(); + stopInputTimer(); document.getElementById('div').innerHTML = ""; if (!DEBUG) { $("#menu-screen").fadeOut(400, function() { @@ -222,5 +222,5 @@ function startGame() { }); } // end clear - startInput(); + startInputTimer(); } From 921e624dc3d50ff34493d5ce07f739987d437bff Mon Sep 17 00:00:00 2001 From: uxer Date: Mon, 29 Apr 2019 19:38:51 +0700 Subject: [PATCH 2/4] add multi layout gamepad --- static/js/gameboy_controller.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/static/js/gameboy_controller.js b/static/js/gameboy_controller.js index 2395bc02..818ba6d7 100644 --- a/static/js/gameboy_controller.js +++ b/static/js/gameboy_controller.js @@ -229,17 +229,17 @@ function getOS() { var OSName = "unknown"; if (navigator.appVersion.indexOf("Win")!=-1) OSName="win"; else if (navigator.appVersion.indexOf("Mac")!=-1) OSName="mac"; - else if (navigator.appVersion.indexOf("Android")!=-1) OSName="android"; + else if (navigator.userAgent.indexOf("Android")!=-1) OSName="android"; return OSName; } function getBrowser() { var browserName = "unknown"; - if (navigator.appVersion.indexOf("Firefox")!=-1) browserName="firefox"; - if (navigator.appVersion.indexOf("Chrome")!=-1) browserName="chrome"; - if (navigator.appVersion.indexOf("Edge")!=-1) browserName="edge"; - if (navigator.appVersion.indexOf("Version/")!=-1) browserName="safari"; - if (navigator.appVersion.indexOf("UCBrowser")!=-1) browserName="uc"; + if (navigator.userAgent.indexOf("Firefox")!=-1) browserName="firefox"; + if (navigator.userAgent.indexOf("Chrome")!=-1) browserName="chrome"; + if (navigator.userAgent.indexOf("Edge")!=-1) browserName="edge"; + if (navigator.userAgent.indexOf("Version/")!=-1) browserName="safari"; + if (navigator.userAgent.indexOf("UCBrowser")!=-1) browserName="uc"; return browserName; } @@ -247,8 +247,7 @@ function getBrowser() { // only capture the last plugged joystick window.addEventListener("gamepadconnected", (e) => { gamepad = e.gamepad; - console.log(`Gamepad connected at index ${gamepad.index}: ${gamepad.id}. ${gamepad.buttons.length} buttons, ${gamepad.axes.length} axes.`); - console.log(gamepad); + log(`Gamepad connected at index ${gamepad.index}: ${gamepad.id}. ${gamepad.buttons.length} buttons, ${gamepad.axes.length} axes.`); padIdx = gamepad.index; @@ -256,6 +255,9 @@ window.addEventListener("gamepadconnected", (e) => { // get mapping first (default KeyMap2) os = getOS(); browser = getBrowser(); + + console.log(os); + console.log(browser); if (os == "android") { // default of android is KeyMap1 @@ -337,7 +339,6 @@ window.addEventListener("gamepadconnected", (e) => { window.addEventListener("gamepaddisconnected", (event) => { clearInterval(gamepadTimer); - console.log("A gamepad disconnected:"); - console.log(event.gamepad); + log(`Gamepad disconnected at index ${e.gamepad.index}`); }); From f816a7af906ebf9ff83584617ebc0fd12a046174 Mon Sep 17 00:00:00 2001 From: uxer Date: Tue, 30 Apr 2019 08:11:41 +0700 Subject: [PATCH 3/4] WIP --- static/css/joystick.css | 137 ++++++++++++++++ static/index_ws.html | 266 +++++++++++++++++++++++++------- static/js/gameboy_controller.js | 161 +++++++++++++++++-- 3 files changed, 487 insertions(+), 77 deletions(-) create mode 100644 static/css/joystick.css diff --git a/static/css/joystick.css b/static/css/joystick.css new file mode 100644 index 00000000..aba327c9 --- /dev/null +++ b/static/css/joystick.css @@ -0,0 +1,137 @@ + + .abxy { + position: absolute; + width: 161px; + height: 160px; + top: 125px; + left: 451px + } + + .abxy .button { + position: absolute; + width: 54px; + height: 54px; + } + + .abxy .button.a { + width: 53px; + height: 53px; + } + + .abxy .button.y { + width: 55px; + height: 54px; + } + + .abxy .button.pressed { + background-position: 0 -55px; + margin-top: 6px; + opacity: 1; + } + + .abxy .button.pressed.a { + background-position: 0 -54px; + } + + .abxy .button.pressed.y { + background-position: 0 -56px; + } + + .abxy .a { + background: url(https://gamepadviewer.com/xbox-assets-old/a.png); + top: 108px; + left: 55px; + } + + .abxy .b { + background: url(https://gamepadviewer.com/xbox-assets-old/b.png); + top: 54px; + right: 0px; + } + + .abxy .x { + background: url(https://gamepadviewer.com/xbox-assets-old/x.png); + top: 54px; + } + + .abxy .y { + background: url(https://gamepadviewer.com/xbox-assets-old/y.png); + left: 54px; + } + + + .dpad { + background: url(https://gamepadviewer.com/xbox-assets-old/bg.png); + background-position: -174px -273px; + border-radius: 100%; + position: absolute; + width: 112px; + height: 112px; + top: 300px; + left: 451px; + } + + .dpad .face { + position: absolute; + font-size: 30px; + line-height: 0; + color: white; + opacity: 0; + font-family: 'FontAwesome'; + } + + .dpad .face.pressed { + opacity: 1; + } + + .dpad .face.up { + left: 42px; + top: 20px; + } + + .dpad .face.up:after { + content: "\f062"; + } + + .dpad .face.down { + left: 42px; + bottom: 20px; + } + + .dpad .face.down:after { + content: "\f063"; + } + + .dpad .face.left { + top: 56px; + left: 3px; + } + + .dpad .face.left:after { + content: "\f060"; + } + + .dpad .face.right { + top: 56px; + right: 3px; + } + + .dpad .face.right:after { + content: "\f061"; + } + + + .dpad .joystick { + background-color: blue; + border-radius: 100%; + opacity: 0.5; + cursor: pointer; + height: 50%; + user-select: none; + width: 50%; + position: absolute; + top: 50%; + left: 50%; + margin-top: -28px; + margin-left: -28px; + } \ No newline at end of file diff --git a/static/index_ws.html b/static/index_ws.html index 49f10499..6b68a677 100644 --- a/static/index_ws.html +++ b/static/index_ws.html @@ -1,80 +1,226 @@ - + + + + + + - + - - -Your current room:
+ + + + + + + + Your current room:
You can join a remote game by roomID.
-Room ID: -Play as player(1,2): + Play as player(1,2): + -

+

- -
-

+
+

-

Instruction

-
- C is start button. Use it to start game
- V is select button
+

Instruction

+
+ C is start button. Use it to start game
+ V is select button
- Player 1 - Use Up, Down, Left, Right to Move
- Z to (A)
- X to (B)
- S to save
- L to load
- -

+ Player 1 + Use Up, Down, Left, Right to Move
+ Z to (A)
+ X to (B)
+ S to save
+ L to load
+ +

-

Log:

-

+  

Log:

+

 
-
- 🎮Refresh to retry when checking is too long -
+
+ 🎮Refresh to retry when checking is too long +
- - - - + +
+ + + + +
- - - - - +
+ + + + +
- - $("#gameOp").on("change", function() { - gameIdx = gameOp.selectedIndex; - }); + + + - gameIdx = 1; - + + + + + - + + + + + \ No newline at end of file diff --git a/static/js/gameboy_controller.js b/static/js/gameboy_controller.js index 818ba6d7..5cded038 100644 --- a/static/js/gameboy_controller.js +++ b/static/js/gameboy_controller.js @@ -227,19 +227,19 @@ var padState, gamepadTimer; function getOS() { // linux? ios? var OSName = "unknown"; - if (navigator.appVersion.indexOf("Win")!=-1) OSName="win"; - else if (navigator.appVersion.indexOf("Mac")!=-1) OSName="mac"; - else if (navigator.userAgent.indexOf("Android")!=-1) OSName="android"; + if (navigator.appVersion.indexOf("Win") != -1) OSName = "win"; + else if (navigator.appVersion.indexOf("Mac") != -1) OSName = "mac"; + else if (navigator.userAgent.indexOf("Android") != -1) OSName = "android"; return OSName; } function getBrowser() { var browserName = "unknown"; - if (navigator.userAgent.indexOf("Firefox")!=-1) browserName="firefox"; - if (navigator.userAgent.indexOf("Chrome")!=-1) browserName="chrome"; - if (navigator.userAgent.indexOf("Edge")!=-1) browserName="edge"; - if (navigator.userAgent.indexOf("Version/")!=-1) browserName="safari"; - if (navigator.userAgent.indexOf("UCBrowser")!=-1) browserName="uc"; + if (navigator.userAgent.indexOf("Firefox") != -1) browserName = "firefox"; + if (navigator.userAgent.indexOf("Chrome") != -1) browserName = "chrome"; + if (navigator.userAgent.indexOf("Edge") != -1) browserName = "edge"; + if (navigator.userAgent.indexOf("Version/") != -1) browserName = "safari"; + if (navigator.userAgent.indexOf("UCBrowser") != -1) browserName = "uc"; return browserName; } @@ -258,29 +258,29 @@ window.addEventListener("gamepadconnected", (e) => { console.log(os); console.log(browser); - + if (os == "android") { // default of android is KeyMap1 - padMap = {2: "a", 0: "b", 3: "start", 4: "select", 10: "load", 11: "save", 8: "full", 9: "quit", 12: "up", 13: "down", 14: "left", 15: "right"}; + padMap = { 2: "a", 0: "b", 3: "start", 4: "select", 10: "load", 11: "save", 8: "full", 9: "quit", 12: "up", 13: "down", 14: "left", 15: "right" }; } else { // default of other OS is KeyMap2 - padMap = {0: "a", 1: "b", 2: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 12: "up", 13: "down", 14: "left", 15: "right"}; + padMap = { 0: "a", 1: "b", 2: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 12: "up", 13: "down", 14: "left", 15: "right" }; } if (os == "android" && (browser == "firefox" || browser == "uc")) { //KeyMap2 - padMap = {0: "a", 1: "b", 2: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 12: "up", 13: "down", 14: "left", 15: "right"}; + padMap = { 0: "a", 1: "b", 2: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 12: "up", 13: "down", 14: "left", 15: "right" }; } if (os == "win" && browser == "firefox") { //KeyMap3 - padMap = {1: "a", 2: "b", 0: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit"}; + padMap = { 1: "a", 2: "b", 0: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit" }; } if (os == "mac" && browser == "safari") { //KeyMap4 - padMap = {1: "a", 2: "b", 0: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 14: "up", 15: "down", 16: "left", 17: "right"}; + padMap = { 1: "a", 2: "b", 0: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 14: "up", 15: "down", 16: "left", 17: "right" }; } if (os == "mac" && browser == "firefox") { //KeyMap5 - padMap = {1: "a", 2: "b", 0: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 14: "up", 15: "down", 16: "left", 17: "right"}; + padMap = { 1: "a", 2: "b", 0: "start", 3: "select", 8: "load", 9: "save", 6: "full", 7: "quit", 14: "up", 15: "down", 16: "left", 17: "right" }; } // reset state @@ -307,7 +307,7 @@ window.addEventListener("gamepadconnected", (e) => { } } - gamepadTimer = setInterval(function() { + gamepadTimer = setInterval(function () { gamepad = navigator.getGamepads()[padIdx]; if (gamepad) { // axis pad @@ -334,7 +334,7 @@ window.addEventListener("gamepadconnected", (e) => { } }, 10); // miliseconds per hit - + }); window.addEventListener("gamepaddisconnected", (event) => { @@ -342,3 +342,130 @@ window.addEventListener("gamepaddisconnected", (event) => { log(`Gamepad disconnected at index ${e.gamepad.index}`); }); + + +// VIRTUAL JOYSTICK +// Ref: https://jsfiddle.net/aa0et7tr/5/ +createJoystick($('.dpad')); +var dpadState = {}; +var touchIdx = null; + +function resetDPad() { + dpadState = { + up: false, + down: false, + left: false, + right: false, + }; + + $(".dpad .face").removeClass("pressed"); +} + +function checkDPadAxis(bo, axis) { + if (bo != dpadState[axis]) { + dpadState[axis] = bo; + + if (dpadState[axis]) { + $(`.dpad .${axis}`).addClass("pressed"); + } else { + $(`.dpad .${axis}`).removeClass("pressed"); + } + } +} + +function createJoystick(parent) { + const maxDiff = 50; + + stick = document.createElement('div'); + stick.classList.add('joystick'); + + // TODO: REMOVE MOUSE + parent.on('mousedown', handleMouseDown); + $(document).on('mousemove', handleMouseMove); + $(document).on('mouseup', handleMouseUp); + + parent.on('touchstart', handleMouseDown); + parent.on('touchmove', handleMouseMove); + parent.on('touchend', handleMouseUp); + + let dragStart = null; + let currentPos = { x: 0, y: 0 }; + + function handleMouseDown(event) { + event.preventDefault(); + stick.style.transition = '0s'; + if (event.changedTouches) { + touchIdx = event.changedTouches[0].identifier; + dragStart = { + x: event.changedTouches[0].clientX, + y: event.changedTouches[0].clientY, + }; + resetDPad(); + return; + } + dragStart = { + x: event.clientX, + y: event.clientY, + }; + + } + + function handleMouseMove(event) { + event.preventDefault(); + if (dragStart === null) return; + if (event.changedTouches) { + event.clientX = event.changedTouches[touchIdx].clientX; + event.clientY = event.changedTouches[touchIdx].clientY; + } + const xDiff = event.clientX - dragStart.x; + const yDiff = event.clientY - dragStart.y; + const angle = Math.atan2(yDiff, xDiff); + const distance = Math.min(maxDiff, Math.hypot(xDiff, yDiff)); + const xNew = distance * Math.cos(angle); + const yNew = distance * Math.sin(angle); + stick.style.transform = `translate3d(${xNew}px, ${yNew}px, 0px)`; + currentPos = { x: xNew, y: yNew }; + + const xRatio = xNew / maxDiff; + const yRatio = yNew / maxDiff; + checkDPadAxis(xRatio <= -0.5, "left"); + checkDPadAxis(xRatio >= 0.5, "right"); + checkDPadAxis(yRatio <= -0.5, "up"); + checkDPadAxis(yRatio >= 0.5, "down"); + } + + function handleMouseUp(event) { + event.preventDefault(); + if (dragStart === null) return; + stick.style.transition = '.2s'; + stick.style.transform = `translate3d(0px, 0px, 0px)`; + dragStart = null; + currentPos = { x: 0, y: 0 }; + resetDPad(); + + $(".abxy .button").removeClass("pressed"); + } + + parent.append(stick); + return { + getPosition: () => currentPos, + }; + +} + + +function handleButtonDown(event) { + $(this).addClass("pressed"); +} + +function handleButtonUp(event) { + $(this).removeClass("pressed"); +} + + +// TODO: REMOVE MOUSE +$(".abxy .button").on("mousedown", handleButtonDown); +$(".abxy .button").on("mouseup", handleButtonUp); + +$(".abxy .button").on("touchstart", handleButtonDown); +$(".abxy .button").on("touchend", handleButtonUp); \ No newline at end of file From ee4de5cd32d3a06b9b27b02cc1ffe24cac70604c Mon Sep 17 00:00:00 2001 From: uxer Date: Tue, 30 Apr 2019 08:35:17 +0700 Subject: [PATCH 4/4] funtional touch --- static/index_ws.html | 132 +------------------------------- static/js/gameboy_controller.js | 14 ++-- 2 files changed, 13 insertions(+), 133 deletions(-) diff --git a/static/index_ws.html b/static/index_ws.html index 6b68a677..3b61ebf7 100644 --- a/static/index_ws.html +++ b/static/index_ws.html @@ -68,10 +68,10 @@
- - - - + + + +
diff --git a/static/js/gameboy_controller.js b/static/js/gameboy_controller.js index 5cded038..2da273bb 100644 --- a/static/js/gameboy_controller.js +++ b/static/js/gameboy_controller.js @@ -370,6 +370,8 @@ function checkDPadAxis(bo, axis) { } else { $(`.dpad .${axis}`).removeClass("pressed"); } + + doButton(bo, axis); } } @@ -380,9 +382,9 @@ function createJoystick(parent) { stick.classList.add('joystick'); // TODO: REMOVE MOUSE - parent.on('mousedown', handleMouseDown); - $(document).on('mousemove', handleMouseMove); - $(document).on('mouseup', handleMouseUp); + // parent.on('mousedown', handleMouseDown); + // $(document).on('mousemove', handleMouseMove); + // $(document).on('mouseup', handleMouseUp); parent.on('touchstart', handleMouseDown); parent.on('touchmove', handleMouseMove); @@ -456,16 +458,18 @@ function createJoystick(parent) { function handleButtonDown(event) { $(this).addClass("pressed"); + doButtonDown($(this).attr("value")); } function handleButtonUp(event) { $(this).removeClass("pressed"); + doButtonUp($(this).attr("value")); } // TODO: REMOVE MOUSE -$(".abxy .button").on("mousedown", handleButtonDown); -$(".abxy .button").on("mouseup", handleButtonUp); +// $(".abxy .button").on("mousedown", handleButtonDown); +// $(".abxy .button").on("mouseup", handleButtonUp); $(".abxy .button").on("touchstart", handleButtonDown); $(".abxy .button").on("touchend", handleButtonUp); \ No newline at end of file