"use strict"; const connection = new signalR.HubConnectionBuilder() .withUrl("/pong/hub") .withAutomaticReconnect() .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) .build(); function getElement(id) { return document.getElementById(id) ?? console.error(`Element #${id} not found!`) } const connectionStatus = getElement("connection"); const createroom = getElement("createlobby"); const roomidinput = getElement("roomid"); const joinroom = getElement("joinroom"); const joinroomdiv = getElement("joinroomdiv"); const usernameinput = getElement("username"); const setusername = getElement("setusername"); const leaveroom = getElement("leavelobby"); const usernameerror = getElement("usernameerror"); const connectedroomid = getElement("connectedroomid"); connection.onclose(function (err) { if (err) { connectionStatus.textContent = "Unexpected error!"; return console.error(`Connection aborted: ${err.message}`); } console.info("Disconnected!"); connectionStatus.textContent = "Closed!"; }); connection.onreconnecting(function (err) { if (err) { connectionStatus.textContent = "Reconnecting!"; return console.error(`Connection reconnecting: ${err.message}`); } console.info("Reconnecting!"); connectionStatus.textContent = "Reconnecting!"; }); connection.onreconnected(function (connectionId) { console.info(`Connected as ${connectionId}!`); connectionStatus.textContent = "Connected!"; }); function show(elem) { elem.classList.remove("d-none"); } function hide(elem) { elem.classList.add("d-none"); } function roomJoined(roomId) { roomidinput.value = roomId; connectedroomid.textContent = roomId; console.info(`Joined room [${roomId}]`); hide(createroom); hide(joinroomdiv); show(leaveroom); } createroom.addEventListener("click", function (event) { connection.invoke("CreateRoom").then(roomJoined).catch(function (err) { return console.error(err.toString()); }); event.preventDefault(); }); connection.on("GameStateChanged", function (state) { console.info(`Game is now in state ${state}`); }); connection.on("UsernameChanged", function (username) { console.info(`Username is now ${username}`); usernameinput.value = username; usernameinput.classList.remove("is-invalid"); usernameinput.classList.add("is-valid"); }); joinroom.addEventListener("click", function (event) { connection.invoke("JoinRoom", roomidinput.value).then(roomJoined).catch(function (err) { return console.error(err.toString()); }); event.preventDefault(); }); function hubExceptionMessage(msg) { const needle = "HubException: "; let idx = msg.lastIndexOf(needle); if (idx < 0) return msg; return msg.substr(idx + needle.length); } usernameinput.addEventListener("input", function (event) { usernameinput.classList.remove("is-valid"); }); setusername.addEventListener("click", function (event) { connection.invoke("RequestUsernameChange", usernameinput.value).catch(function (err) { usernameerror.textContent = hubExceptionMessage(err.message); usernameinput.classList.add("is-invalid"); return console.error(err.toString()); }); event.preventDefault(); }); leaveroom.addEventListener("click", function (event) { connection.invoke("LeaveRoom").then(function () { roomidinput.value = ""; show(createroom); show(joinroomdiv); hide(leaveroom); }).catch(function (err) { return console.error(err.toString()); }); event.preventDefault(); }); function movePaddle(direction) { connection.invoke("MovePaddle", direction).catch(function (err) { return console.error(err.toString()); }); } // Create the application helper and add its render target to the page let app = new PIXI.Application({ width: 1000, height: 500 }); getElement("canvas-container").appendChild(app.view); let graphics = new PIXI.Graphics(); app.stage.addChild(graphics); function renderPaddle(graphics, state, xMid) { var xLeft = xMid - 5; graphics.beginFill(0x00FFFF); graphics.drawRect(xLeft, state.Height - 25, 10, 50); graphics.endFill(); } function renderBall(graphics, state) { graphics.beginFill(0xFF00FF); graphics.drawCircle(state.Pos.X, state.Pos.Y, 4); graphics.endFill(); } function renderGameState(graphics, state) { graphics.clear(); renderPaddle(graphics, state.Paddle1, 50); renderPaddle(graphics, state.Paddle2, 1000 - 50); renderBall(graphics, state.BallState); } connection.on("ReceiveGameState", function (state) { renderGameState(graphics, state); }); const keyEvent = (function () { var upPressed = false; var downPressed = false; var direction = 0; function setDirection(dir) { if (direction != dir) { direction = dir; movePaddle(direction); } } function moveUpdated() { if (upPressed == downPressed) setDirection(0); else if (upPressed) setDirection(-1); else if (downPressed) setDirection(1); else console.error("unknown move!"); } function handler(event) { var pressed = event.type == "keydown"; // W Key is 87, Up arrow is 87 // S Key is 83, Down arrow is 40 switch (event.keyCode) { case 87: case 38: upPressed = pressed; break; case 83: case 40: downPressed = pressed; break; default: return; } if (event.repeat) return; if (event.target.tagName == 'INPUT') return; // dont use key if on input event.preventDefault(); moveUpdated(); } return handler; })(); document.addEventListener("keydown", keyEvent); document.addEventListener("keyup", keyEvent); connection.start().then(function () { console.info(`Connected!`); connectionStatus.textContent = "Connected!"; }).catch(function (err) { connectionStatus.textContent = "Connection failed!"; return console.error(err.toString()); });