mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-24 02:27:32 +00:00
Merge branch 'touch'
This commit is contained in:
commit
498c2a5e26
6 changed files with 624 additions and 187 deletions
137
static/css/joystick.css
vendored
Normal file
137
static/css/joystick.css
vendored
Normal file
|
|
@ -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;
|
||||
}
|
||||
142
static/index_ws.html
vendored
142
static/index_ws.html
vendored
|
|
@ -1,80 +1,102 @@
|
|||
<html>
|
||||
|
||||
<style>
|
||||
textarea {
|
||||
width: 60%;
|
||||
height: 50px;
|
||||
}
|
||||
</style>
|
||||
<head>
|
||||
<!-- <meta name="viewport" content="width=device-width, user-scalable=no" /> -->
|
||||
<meta name="viewport" content="user-scalable=no" />
|
||||
<link href="//netdna.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/static/css/joystick.css" rel="stylesheet">
|
||||
<style>
|
||||
textarea {
|
||||
width: 60%;
|
||||
height: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<select id="gameOp">
|
||||
</select>
|
||||
</head>
|
||||
|
||||
<button id="play" onclick="window.startGame()">Play</button>
|
||||
<button id="play" onclick="pc.close()">Stop</button>
|
||||
Your current room: <b><label id="currentRoomID" style="color:blue"></b> <br />
|
||||
<body>
|
||||
|
||||
|
||||
<select id="gameOp">
|
||||
</select>
|
||||
|
||||
<button id="play" onclick="window.startGame()">Play</button>
|
||||
<button id="play" onclick="pc.close()">Stop</button>
|
||||
Your current room: <b><label id="currentRoomID" style="color:blue"></b> <br />
|
||||
You can join a remote game by roomID.<br />
|
||||
Room ID: <input type="text" id="roomID">
|
||||
Play as player(1,2): <select id="playerIndex">
|
||||
Room ID: <input type="text" id="roomID">
|
||||
Play as player(1,2): <select id="playerIndex">
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</select>
|
||||
|
||||
<br/><br/>
|
||||
<br /><br />
|
||||
|
||||
<body scroll="no" style="overflow: hidden">
|
||||
<div id="remoteVideos">
|
||||
<video id="game-screen" autoplay=true width=400 height=300 poster="https://orig00.deviantart.net/cdcd/f/2017/276/a/a/october_2nd___gameboy_poltergeist_by_wanyo-dbpdmnd.gif">
|
||||
</div> <br />
|
||||
<div id="remoteVideos">
|
||||
<video id="game-screen" autoplay=true width=400 height=300
|
||||
poster="https://orig00.deviantart.net/cdcd/f/2017/276/a/a/october_2nd___gameboy_poltergeist_by_wanyo-dbpdmnd.gif">
|
||||
</div> <br />
|
||||
|
||||
<h3>Instruction</h3>
|
||||
<div>
|
||||
C is start button. Use it to start game<br />
|
||||
V is select button <br />
|
||||
<h3>Instruction</h3>
|
||||
<div>
|
||||
C is start button. Use it to start game<br />
|
||||
V is select button <br />
|
||||
|
||||
Player 1
|
||||
Use Up, Down, Left, Right to Move <br />
|
||||
Z to (A) <br />
|
||||
X to (B) <br />
|
||||
S to save <br />
|
||||
L to load <br />
|
||||
<!--Fullscreen media for better gaming experience<br /-->
|
||||
</div><br>
|
||||
Player 1
|
||||
Use Up, Down, Left, Right to Move <br />
|
||||
Z to (A) <br />
|
||||
X to (B) <br />
|
||||
S to save <br />
|
||||
L to load <br />
|
||||
<!--Fullscreen media for better gaming experience<br /-->
|
||||
</div><br>
|
||||
|
||||
<h3>Log:</h3>
|
||||
<pre id="div"></pre>
|
||||
<h3>Log:</h3>
|
||||
<pre id="div"></pre>
|
||||
|
||||
<div>
|
||||
🎮<u><i>Refresh to retry when checking is too long</i></u>
|
||||
</div>
|
||||
<div>
|
||||
🎮<u><i>Refresh to retry when checking is too long</i></u>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
DEBUG = true;
|
||||
</script>
|
||||
|
||||
<!-- https://rawgit.com/Rillke/opus.js-sample/master/index.xhtml -->
|
||||
<script src="/static/js/libopus.js"></script>
|
||||
<script src="/static/js/opus.js"></script>
|
||||
<!-- virtual controller -->
|
||||
<div id="dpad" class="dpad">
|
||||
<span class="face up"></span>
|
||||
<span class="face down"></span>
|
||||
<span class="face left"></span>
|
||||
<span class="face right"></span>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||
<script src="/static/js/const.js"></script>
|
||||
<script src="/static/js/global.js"></script>
|
||||
<script src="/static/js/gameboy_controller.js"></script>
|
||||
<script src="/static/js/ws.js"></script>
|
||||
<div class="abxy">
|
||||
<span value="a" class="button a"></span>
|
||||
<span value="b" class="button b"></span>
|
||||
<span value="start" class="button x"></span>
|
||||
<span value="select" class="button y"></span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<!--GAME_LIST.forEach(e => {-->
|
||||
<!--ee = document.createElement("option");-->
|
||||
<!--ee.value = e.nes;-->
|
||||
<!--ee.innerHTML = e.name;-->
|
||||
<!--gameOp.append(ee);-->
|
||||
<!--});-->
|
||||
<script>
|
||||
DEBUG = true;
|
||||
</script>
|
||||
|
||||
$("#gameOp").on("change", function() {
|
||||
gameIdx = gameOp.selectedIndex;
|
||||
});
|
||||
<!-- https://rawgit.com/Rillke/opus.js-sample/master/index.xhtml -->
|
||||
<script src="/static/js/libopus.js"></script>
|
||||
<script src="/static/js/opus.js"></script>
|
||||
|
||||
gameIdx = 1;
|
||||
</script>
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||
<script src="/static/js/const.js"></script>
|
||||
<script src="/static/js/global.js"></script>
|
||||
<script src="/static/js/gameboy_controller.js"></script>
|
||||
<script src="/static/js/ws.js"></script>
|
||||
|
||||
</html>
|
||||
<script>
|
||||
$("#gameOp").on("change", function () {
|
||||
gameIdx = gameOp.selectedIndex;
|
||||
});
|
||||
|
||||
gameIdx = 1;
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
19
static/js/const.js
vendored
19
static/js/const.js
vendored
|
|
@ -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
|
||||
|
|
|
|||
501
static/js/gameboy_controller.js
vendored
501
static/js/gameboy_controller.js
vendored
|
|
@ -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,429 @@ 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.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";
|
||||
return browserName;
|
||||
}
|
||||
|
||||
|
||||
// only capture the last plugged joystick
|
||||
window.addEventListener("gamepadconnected", (e) => {
|
||||
gamepad = e.gamepad;
|
||||
log(`Gamepad connected at index ${gamepad.index}: ${gamepad.id}. ${gamepad.buttons.length} buttons, ${gamepad.axes.length} axes.`);
|
||||
|
||||
padIdx = gamepad.index;
|
||||
|
||||
// Ref: https://github.com/giongto35/cloud-game/issues/14
|
||||
// get mapping first (default KeyMap2)
|
||||
os = getOS();
|
||||
browser = getBrowser();
|
||||
|
||||
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" };
|
||||
} 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);
|
||||
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");
|
||||
}
|
||||
|
||||
doButton(bo, axis);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
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("touchstart", handleButtonDown);
|
||||
$(".abxy .button").on("touchend", handleButtonUp);
|
||||
6
static/js/global.js
vendored
6
static/js/global.js
vendored
|
|
@ -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;
|
||||
|
|
|
|||
6
static/js/ws.js
vendored
6
static/js/ws.js
vendored
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue