mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-25 02:57:24 +00:00
merge master
This commit is contained in:
commit
79b0337ee8
20 changed files with 924 additions and 384 deletions
9
static/gameboy.html
vendored
9
static/gameboy.html
vendored
|
|
@ -37,7 +37,8 @@
|
|||
<div id="glass-gameboy-text">GAME BOY</div>
|
||||
<div id="glass-color-text">C</div>
|
||||
<div id="screen">
|
||||
<video id="game-screen" autoplay=true poster="https://orig00.deviantart.net/cdcd/f/2017/276/a/a/october_2nd___gameboy_poltergeist_by_wanyo-dbpdmnd.gif">
|
||||
<!--<video id="game-screen" autoplay=true poster="https://orig00.deviantart.net/cdcd/f/2017/276/a/a/october_2nd___gameboy_poltergeist_by_wanyo-dbpdmnd.gif">-->
|
||||
<video id="game-screen" autoplay=true>
|
||||
</video>
|
||||
|
||||
<div id="menu-screen">
|
||||
|
|
@ -88,9 +89,9 @@
|
|||
<br />
|
||||
Game: <br />
|
||||
Use Up, Down, Left, Right to Move <br />
|
||||
Z to jump (A) <br />
|
||||
X to sprint (B) <br />
|
||||
C is start (in game) <br />
|
||||
Z (A butotn) <br />
|
||||
X (B button) <br />
|
||||
C is start (or pause in some games) <br />
|
||||
V is select game <br />
|
||||
Q is super quit <br />
|
||||
S to save <br />
|
||||
|
|
|
|||
6
static/index_ws.html
vendored
6
static/index_ws.html
vendored
|
|
@ -13,7 +13,7 @@ textarea {
|
|||
<button id="play" onclick="window.startGame()">Play</button>
|
||||
<button id="play" onclick="pc.close()">Stop</button>
|
||||
<button id="play" onclick="window.hihi()">Magic</button><br/><br/>
|
||||
Your current room: <b><label id="currentRoomID" style="color:white"></b> <br />
|
||||
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">
|
||||
|
|
@ -35,8 +35,8 @@ Play as player(1,2): <select id="playerIndex">
|
|||
|
||||
Player 1
|
||||
Use Up, Down, Left, Right to Move <br />
|
||||
Z to jump (A) <br />
|
||||
X to sprint (B) <br />
|
||||
Z to (A) <br />
|
||||
X to (B) <br />
|
||||
S to save <br />
|
||||
L to load <br />
|
||||
<!--Fullscreen media for better gaming experience<br /-->
|
||||
|
|
|
|||
1
static/js/const.js
vendored
1
static/js/const.js
vendored
|
|
@ -99,4 +99,5 @@ KEY_BIT = ["a", "b", "select", "start", "up", "down", "left", "right"];
|
|||
|
||||
|
||||
INPUT_FPS = 100;
|
||||
PINGPONGPS = 5;
|
||||
INPUT_STATE_PACKET = 5;
|
||||
|
|
|
|||
32
static/js/gameboy_controller.js
vendored
32
static/js/gameboy_controller.js
vendored
|
|
@ -3,23 +3,17 @@
|
|||
function showMenuScreen() {
|
||||
log("Clean up connection / frame");
|
||||
// clean up before / after menu
|
||||
try {
|
||||
inputChannel.close();
|
||||
} catch (err) {
|
||||
log(`> [Warning] input channel: ${err}`);
|
||||
}
|
||||
//try {
|
||||
//inputChannel.gameboyIndeoclose();
|
||||
//} catch (err) {
|
||||
//log(`> [Warning] peer connection: ${err}`);
|
||||
//}
|
||||
|
||||
try {
|
||||
pc.close();
|
||||
} catch (err) {
|
||||
log(`> [Warning] peer connection: ${err}`);
|
||||
}
|
||||
|
||||
try {
|
||||
conn.close();
|
||||
} catch (err) {
|
||||
log(`> [Warning] Websocket connection: ${err}`);
|
||||
}
|
||||
//try {
|
||||
//conn.close();
|
||||
//} catch (err) {
|
||||
//log(`> [Warning] Websocket connection: ${err}`);
|
||||
//}
|
||||
|
||||
$("#game-screen").hide();
|
||||
if (!DEBUG) {
|
||||
|
|
@ -69,7 +63,6 @@ function chooseGame(idx, force=false) {
|
|||
function setState(e, bo) {
|
||||
if (e.keyCode in KEY_MAP) {
|
||||
keyState[KEY_MAP[e.keyCode]] = bo;
|
||||
stateUnchange = false;
|
||||
unchangePacket = INPUT_STATE_PACKET;
|
||||
}
|
||||
}
|
||||
|
|
@ -90,7 +83,7 @@ document.body.onkeyup = function (e) {
|
|||
}
|
||||
} else if (screenState === "game") {
|
||||
setState(e, false);
|
||||
|
||||
|
||||
switch (KEY_MAP[e.keyCode]) {
|
||||
case "save":
|
||||
conn.send(JSON.stringify({"id": "save", "data": ""}));
|
||||
|
|
@ -155,7 +148,7 @@ document.body.onkeydown = function (e) {
|
|||
|
||||
function sendInput() {
|
||||
// prepare key
|
||||
if (stateUnchange || unchangePacket > 0) {
|
||||
if (unchangePacket > 0) {
|
||||
st = "";
|
||||
KEY_BIT.slice().reverse().forEach(elem => {
|
||||
st += keyState[elem] ? 1 : 0;
|
||||
|
|
@ -168,7 +161,6 @@ function sendInput() {
|
|||
a[0] = ss;
|
||||
inputChannel.send(a);
|
||||
|
||||
stateUnchange = false;
|
||||
unchangePacket--;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
3
static/js/global.js
vendored
3
static/js/global.js
vendored
|
|
@ -32,7 +32,6 @@ keyState = {
|
|||
quit: false
|
||||
}
|
||||
|
||||
stateUnchange = true;
|
||||
unchangePacket = INPUT_STATE_PACKET;
|
||||
inputTimer = null;
|
||||
|
||||
|
|
@ -53,4 +52,4 @@ function log(msg) {
|
|||
document.getElementById('div').innerHTML += msg + '<br>'
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
168
static/js/ws.js
vendored
168
static/js/ws.js
vendored
|
|
@ -1,69 +1,80 @@
|
|||
var pc;
|
||||
var curPacketID = "";
|
||||
var curSessionID = "";
|
||||
// web socket
|
||||
|
||||
function startGame() {
|
||||
log("Starting game screen");
|
||||
conn = new WebSocket(`ws://${location.host}/ws`);
|
||||
|
||||
// clear
|
||||
endInput();
|
||||
document.getElementById('div').innerHTML = "";
|
||||
if (!DEBUG) {
|
||||
$("#menu-screen").fadeOut(400, function() {
|
||||
$("#game-screen").show();
|
||||
});
|
||||
// Clear old roomID
|
||||
conn.onopen = () => {
|
||||
log("WebSocket is opened. Send ping");
|
||||
log("Send ping pong frequently")
|
||||
// pingpongTimer = setInterval(sendPing, 1000 / PINGPONGPS)
|
||||
|
||||
startWebRTC();
|
||||
}
|
||||
|
||||
conn.onerror = error => {
|
||||
log(`Websocket error: ${error}`);
|
||||
}
|
||||
|
||||
conn.onclose = () => {
|
||||
log("Websocket closed");
|
||||
}
|
||||
|
||||
conn.onmessage = e => {
|
||||
d = JSON.parse(e.data);
|
||||
switch (d["id"]) {
|
||||
case "sdp":
|
||||
log("Got remote sdp");
|
||||
pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(d["data"]))));
|
||||
//conn.send(JSON.stringify({"id": "sdpdon", "packet_id": d["packet_id"]}));
|
||||
break;
|
||||
case "requestOffer":
|
||||
curPacketID = d["packet_id"];
|
||||
log("Received request offer ", curPacketID)
|
||||
startWebRTC();
|
||||
//pc.createOffer({offerToReceiveVideo: true, offerToReceiveAudio: false}).then(d => {
|
||||
//pc.setLocalDescription(d).catch(log);
|
||||
//})
|
||||
|
||||
//case "sdpremote":
|
||||
//log("Got remote sdp");
|
||||
//pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(d["data"]))));
|
||||
//conn.send(JSON.stringify({"id": "remotestart", "data": GAME_LIST[gameIdx].nes, "room_id": roomID.value, "player_index": parseInt(playerIndex.value, 10)}));inputTimer
|
||||
//break;
|
||||
case "heartbeat":
|
||||
console.log("Ping: ", Date.now() - d["data"])
|
||||
// TODO: Calc time
|
||||
break;
|
||||
case "start":
|
||||
log("Got start");
|
||||
roomID.value = ""
|
||||
currentRoomID.innerText = d["room_id"]
|
||||
break;
|
||||
case "save":
|
||||
log(`Got save response: ${d["data"]}`);
|
||||
break;
|
||||
case "load":
|
||||
log(`Got load response: ${d["data"]}`);
|
||||
break;
|
||||
}
|
||||
// end clear
|
||||
}
|
||||
|
||||
conn = new WebSocket(`ws://${location.host}/ws`);
|
||||
|
||||
// Clear old roomID
|
||||
conn.onopen = () => {
|
||||
log("WebSocket is opened. Send ping");
|
||||
conn.send(JSON.stringify({"id": "ping", "data": GAME_LIST[gameIdx].nes, "room_id": roomID.value, "player_index": parseInt(playerIndex.value, 10)}));
|
||||
}
|
||||
|
||||
conn.onerror = error => {
|
||||
log(`Websocket error: ${error}`);
|
||||
}
|
||||
|
||||
conn.onclose = () => {
|
||||
log("Websocket closed");
|
||||
}
|
||||
|
||||
conn.onmessage = e => {
|
||||
d = JSON.parse(e.data);
|
||||
switch (d["id"]) {
|
||||
case "pong":
|
||||
log("Recv pong. Start webrtc");
|
||||
startWebRTC();
|
||||
break;
|
||||
case "sdp":
|
||||
log("Got remote sdp");
|
||||
pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(d["data"]))));
|
||||
break;
|
||||
case "start":
|
||||
log("Got start");
|
||||
roomID.value = ""
|
||||
currentRoomID.innerText = d["room_id"]
|
||||
break;
|
||||
case "save":
|
||||
log(`Got save response: ${d["data"]}`);
|
||||
break;
|
||||
case "load":
|
||||
log(`Got load response: ${d["data"]}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
function sendPing() {
|
||||
// TODO: format the package with time
|
||||
conn.send(JSON.stringify({"id": "heartbeat", "data": Date.now().toString()}));
|
||||
}
|
||||
|
||||
function startWebRTC() {
|
||||
// webrtc
|
||||
pc = new RTCPeerConnection({iceServers: [{urls: 'stun:stun.l.google.com:19302'}]})
|
||||
// input channel
|
||||
inputChannel = pc.createDataChannel('foo')
|
||||
|
||||
// input channel, ordered + reliable
|
||||
inputChannel = pc.createDataChannel('a', {
|
||||
ordered: true,
|
||||
});
|
||||
inputChannel.onclose = () => log('inputChannel has closed');
|
||||
inputChannel.onopen = () => log('inputChannel has opened');
|
||||
inputChannel.onmessage = e => {
|
||||
console.log(e);
|
||||
log(`Message '${e.data}'`);
|
||||
}
|
||||
|
||||
window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||
var context = new AudioContext();
|
||||
|
|
@ -123,14 +134,11 @@ function startGame() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pc.oniceconnectionstatechange = e => {
|
||||
log(`iceConnectionState: ${pc.iceConnectionState}`);
|
||||
|
||||
if (pc.iceConnectionState === "connected") {
|
||||
conn.send(JSON.stringify({"id": "start", "data": ""}));
|
||||
startInput();
|
||||
screenState = "game";
|
||||
//conn.send(JSON.stringify({"id": "start", "data": ""}));
|
||||
}
|
||||
else if (pc.iceConnectionState === "disconnected") {
|
||||
endInput();
|
||||
|
|
@ -165,20 +173,38 @@ function startGame() {
|
|||
session = btoa(JSON.stringify(pc.localDescription));
|
||||
localSessionDescription = session;
|
||||
log("Send SDP to remote peer");
|
||||
conn.send(JSON.stringify({"id": "sdp", "data": session}));
|
||||
// TODO: Fix curPacketID
|
||||
conn.send(JSON.stringify({"id": "initwebrtc", "data": session, "packet_id": curPacketID}));
|
||||
} else {
|
||||
console.log(JSON.stringify(event.candidate));
|
||||
}
|
||||
}
|
||||
|
||||
function startWebRTC() {
|
||||
// receiver only tracks
|
||||
pc.addTransceiver('video', {'direction': 'recvonly'});
|
||||
pc.addTransceiver('audio', {'direction': 'recvonly'});
|
||||
// receiver only tracks
|
||||
pc.addTransceiver('video', {'direction': 'recvonly'});
|
||||
|
||||
// create SDP
|
||||
pc.createOffer({offerToReceiveVideo: true, offerToReceiveAudio: false}).then(d => {
|
||||
pc.setLocalDescription(d).catch(log);
|
||||
})
|
||||
|
||||
// create SDP
|
||||
pc.createOffer({offerToReceiveVideo: true, offerToReceiveAudio: true}).then(d => {
|
||||
pc.setLocalDescription(d).catch(log);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function startGame() {
|
||||
log("Starting game screen");
|
||||
screenState = "game";
|
||||
|
||||
conn.send(JSON.stringify({"id": "start", "data": GAME_LIST[gameIdx].nes, "room_id": roomID.value, "player_index": parseInt(playerIndex.value, 10)}));
|
||||
|
||||
// clear menu screen
|
||||
endInput();
|
||||
document.getElementById('div').innerHTML = "";
|
||||
if (!DEBUG) {
|
||||
$("#menu-screen").fadeOut(400, function() {
|
||||
$("#game-screen").show();
|
||||
});
|
||||
}
|
||||
// end clear
|
||||
|
||||
// startInput();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue