From 2b6230658875de87ab1cff4308aaf4f4aaea59d5 Mon Sep 17 00:00:00 2001 From: Vaibhav-kesarwani Date: Mon, 5 Aug 2024 09:15:13 +0530 Subject: [PATCH] Added Multiplayer_Shooting_Game --- Games/Multiplayer_Shooting_Game/.gitignore | 2 + Games/Multiplayer_Shooting_Game/.prettierrc | 13 + Games/Multiplayer_Shooting_Game/backend.js | 169 ++++ .../package-lock.json | 795 ++++++++++++++++++ Games/Multiplayer_Shooting_Game/package.json | 6 + .../public/img/webb-dark.png | Bin 0 -> 12150 bytes .../public/index.html | 106 +++ .../public/js/classes/Enemy.js | 22 + .../public/js/classes/Particle.js | 30 + .../public/js/classes/Player.js | 23 + .../public/js/classes/Projectile.js | 26 + .../public/js/eventListeners.js | 35 + .../public/js/frontend.js | 262 ++++++ Games/Multiplayer_Shooting_Game/readme.md | 3 + README.md | 2 +- assets/images/Multiplayer_Shooting_Game.jpeg | Bin 0 -> 44092 bytes assets/js/gamesData.json | 5 + 17 files changed, 1498 insertions(+), 1 deletion(-) create mode 100644 Games/Multiplayer_Shooting_Game/.gitignore create mode 100644 Games/Multiplayer_Shooting_Game/.prettierrc create mode 100644 Games/Multiplayer_Shooting_Game/backend.js create mode 100644 Games/Multiplayer_Shooting_Game/package-lock.json create mode 100644 Games/Multiplayer_Shooting_Game/package.json create mode 100644 Games/Multiplayer_Shooting_Game/public/img/webb-dark.png create mode 100644 Games/Multiplayer_Shooting_Game/public/index.html create mode 100644 Games/Multiplayer_Shooting_Game/public/js/classes/Enemy.js create mode 100644 Games/Multiplayer_Shooting_Game/public/js/classes/Particle.js create mode 100644 Games/Multiplayer_Shooting_Game/public/js/classes/Player.js create mode 100644 Games/Multiplayer_Shooting_Game/public/js/classes/Projectile.js create mode 100644 Games/Multiplayer_Shooting_Game/public/js/eventListeners.js create mode 100644 Games/Multiplayer_Shooting_Game/public/js/frontend.js create mode 100644 Games/Multiplayer_Shooting_Game/readme.md create mode 100644 assets/images/Multiplayer_Shooting_Game.jpeg diff --git a/Games/Multiplayer_Shooting_Game/.gitignore b/Games/Multiplayer_Shooting_Game/.gitignore new file mode 100644 index 0000000000..07bc295a77 --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/.gitignore @@ -0,0 +1,2 @@ +.ds_store +node_modules \ No newline at end of file diff --git a/Games/Multiplayer_Shooting_Game/.prettierrc b/Games/Multiplayer_Shooting_Game/.prettierrc new file mode 100644 index 0000000000..553d3bfbd4 --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/.prettierrc @@ -0,0 +1,13 @@ +{ + "singleQuote": true, + "semi": false, + "trailingComma": "none", + "overrides": [ + { + "files": "*.html", + "options": { + "parser": "html" + } + } + ] +} \ No newline at end of file diff --git a/Games/Multiplayer_Shooting_Game/backend.js b/Games/Multiplayer_Shooting_Game/backend.js new file mode 100644 index 0000000000..6b944c62f3 --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/backend.js @@ -0,0 +1,169 @@ +const express = require('express') +const app = express() + +// socket.io setup +const http = require('http') +const server = http.createServer(app) +const { Server } = require('socket.io') +const io = new Server(server, { pingInterval: 2000, pingTimeout: 5000 }) + +const port = 3000 + +app.use(express.static('public')) + +app.get('/', (req, res) => { + res.sendFile(__dirname + '/index.html') +}) + +const backEndPlayers = {} +const backEndProjectiles = {} + +const SPEED = 5 +const RADIUS = 10 +const PROJECTILE_RADIUS = 5 +let projectileId = 0 + +io.on('connection', (socket) => { + console.log('a user connected') + + io.emit('updatePlayers', backEndPlayers) + + socket.on('shoot', ({ x, y, angle }) => { + projectileId++ + + const velocity = { + x: Math.cos(angle) * 5, + y: Math.sin(angle) * 5 + } + + backEndProjectiles[projectileId] = { + x, + y, + velocity, + playerId: socket.id + } + + console.log(backEndProjectiles) + }) + + socket.on('initGame', ({ username, width, height }) => { + backEndPlayers[socket.id] = { + x: 1024 * Math.random(), + y: 576 * Math.random(), + color: `hsl(${360 * Math.random()}, 100%, 50%)`, + sequenceNumber: 0, + score: 0, + username + } + + // where we init our canvas + backEndPlayers[socket.id].canvas = { + width, + height + } + + backEndPlayers[socket.id].radius = RADIUS + }) + + socket.on('disconnect', (reason) => { + console.log(reason) + delete backEndPlayers[socket.id] + io.emit('updatePlayers', backEndPlayers) + }) + + socket.on('keydown', ({ keycode, sequenceNumber }) => { + const backEndPlayer = backEndPlayers[socket.id] + + if (!backEndPlayers[socket.id]) return + + backEndPlayers[socket.id].sequenceNumber = sequenceNumber + switch (keycode) { + case 'KeyW': + backEndPlayers[socket.id].y -= SPEED + break + + case 'KeyA': + backEndPlayers[socket.id].x -= SPEED + break + + case 'KeyS': + backEndPlayers[socket.id].y += SPEED + break + + case 'KeyD': + backEndPlayers[socket.id].x += SPEED + break + } + + const playerSides = { + left: backEndPlayer.x - backEndPlayer.radius, + right: backEndPlayer.x + backEndPlayer.radius, + top: backEndPlayer.y - backEndPlayer.radius, + bottom: backEndPlayer.y + backEndPlayer.radius + } + + if (playerSides.left < 0) backEndPlayers[socket.id].x = backEndPlayer.radius + + if (playerSides.right > 1024) + backEndPlayers[socket.id].x = 1024 - backEndPlayer.radius + + if (playerSides.top < 0) backEndPlayers[socket.id].y = backEndPlayer.radius + + if (playerSides.bottom > 576) + backEndPlayers[socket.id].y = 576 - backEndPlayer.radius + }) +}) + +// backend ticker +setInterval(() => { + // update projectile positions + for (const id in backEndProjectiles) { + backEndProjectiles[id].x += backEndProjectiles[id].velocity.x + backEndProjectiles[id].y += backEndProjectiles[id].velocity.y + + const PROJECTILE_RADIUS = 5 + if ( + backEndProjectiles[id].x - PROJECTILE_RADIUS >= + backEndPlayers[backEndProjectiles[id].playerId]?.canvas?.width || + backEndProjectiles[id].x + PROJECTILE_RADIUS <= 0 || + backEndProjectiles[id].y - PROJECTILE_RADIUS >= + backEndPlayers[backEndProjectiles[id].playerId]?.canvas?.height || + backEndProjectiles[id].y + PROJECTILE_RADIUS <= 0 + ) { + delete backEndProjectiles[id] + continue + } + + for (const playerId in backEndPlayers) { + const backEndPlayer = backEndPlayers[playerId] + + const DISTANCE = Math.hypot( + backEndProjectiles[id].x - backEndPlayer.x, + backEndProjectiles[id].y - backEndPlayer.y + ) + + // collision detection + if ( + DISTANCE < PROJECTILE_RADIUS + backEndPlayer.radius && + backEndProjectiles[id].playerId !== playerId + ) { + if (backEndPlayers[backEndProjectiles[id].playerId]) + backEndPlayers[backEndProjectiles[id].playerId].score++ + + console.log(backEndPlayers[backEndProjectiles[id].playerId]) + delete backEndProjectiles[id] + delete backEndPlayers[playerId] + break + } + } + } + + io.emit('updateProjectiles', backEndProjectiles) + io.emit('updatePlayers', backEndPlayers) +}, 15) + +server.listen(port, () => { + console.log(`Example app listening on port ${port}`) +}) + +console.log('server did load') diff --git a/Games/Multiplayer_Shooting_Game/package-lock.json b/Games/Multiplayer_Shooting_Game/package-lock.json new file mode 100644 index 0000000000..b1d264b51b --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/package-lock.json @@ -0,0 +1,795 @@ +{ + "name": "multiplayer-game-starter-main", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "express": "4.18.2", + "socket.io": "4.6.1" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "18.16.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.1.tgz", + "integrity": "sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz", + "integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz", + "integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/socket.io": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.1.tgz", + "integrity": "sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.4.1", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", + "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/Games/Multiplayer_Shooting_Game/package.json b/Games/Multiplayer_Shooting_Game/package.json new file mode 100644 index 0000000000..ad6c4119b3 --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "express": "4.18.2", + "socket.io": "4.6.1" + } +} diff --git a/Games/Multiplayer_Shooting_Game/public/img/webb-dark.png b/Games/Multiplayer_Shooting_Game/public/img/webb-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..c175914fccd16231033725251732c6bb29dc3818 GIT binary patch literal 12150 zcmXYX2~-o;`*y;<1{4L<0HRe~5O61n?6t8~27gW!6oDXCTqs)>G#ChiprQe5D^@cs zO=UWY5Jg497C;0GvdFNBEGkPFHn#yA1^ySm?;JU3j!Eu&@AE#(d*}Rah;3}J*nmQz z82`BA`#ls2HGS?!PZPXS6#R4s{Bqj8>*wv@_o79MH*DBwW3zPk|6n6yV>2_epLTjX zJ2TeWuUoNlrH+n{tDF1x+kf!&+aD0f*>beJfI@Mk{`kGe&nI7wc8>}Fb}l#@Y=0)? z;-ymK*GO#%;$KoMj0f&^msKD4*efr|H@QY#5|r>55LJk>#cNQ@s9PI+NMFMFvO=)IKw zi27)@@O;g+OeLjfa%`8%U*kZ^j77isw#}Mbv~N~%cPj6>?Md;bL{y(CyP5P?!iNTy zT!--2*pqV6%EwQHCoJe+eg5X&FVU{l$`_ScZDzG^uUF+~SnV@@`=T=6s`k65ZAm1< zb9;TE#zGx}+-JW30 zHu_SNbh}foQGJmwckR{|gO!g4 z7gKf``pfmZW;N16QrE5M!zdkzI?8RS>*Q*RJ+**whd-%b2D=}r^$Z5X= zpRedw$#Z*eM_32P&FH(A2bX*rnkn$vvHb5f=8JOuC~fqo0<8^8XOl-MPyH{ho7wC2 z#dvJNLz>@#YYX+SXpM_6TZ$KQo(J!H@}e^D+|A7w?`VZ3JO*1b(3`NClgau{_sO;p zhkh%g!M`ZUz5}AvhN|l_`yAem8h4$;mD>!J9T#q%O-(lZHO2LzL!Wt0W1)ui(Bmv` zWnOl06T5GyL&Hyeu+%U(tY&k{@PZTLlnopP<>I=lS1EHRaq-mC7aH>9EfgBP)HQpx z-{$X>k8a0}TRR!MvpCG^SQ~>6wAmkQJ+S>d^SIhR$yvN(mlo%~ZXV(V%>GisqEX{8`l$z@i zlyz5F{p$mbU3P7++9bhM`QP35I%<`>T* zwky?!P7jy=Ze?&O=-^~&3)S9)qdj2x)9U{g?9(1~FEts=6?^YUi^6vg>XsN}JKwij zd0kR&Zual5{$ccFa~(qN@O8YhCctxJaE9V_M%vCq5{liiDkE^;WO*s0g#*ZFYS3G*K(kyz`$J?umX3OUo z7o_;-`EZPDVw(8lO{Ti5RS3*Iq* z?xnEm&x70$i+keam_#<`blNfTwlQP7l5VQE$84S70gLQkpB6ifihK6153cCiIRBl) z#pJ&ecGaG=c&d@d$cwXXr<Eth|0T?>8B4!irO*zLk8oiJj`=mO=GU0-69oqH3n3C{hjz~aF~r# z@Ucs`-Kg@~l-2h*bbq5%jjt*%*QHml8lQA`ccuQf%gJ86w?acHKNor?c#*ZK(qN_d ztF2K)rFIyR(QzT^&OiL~p=bV30woDqyKhnEjifE^8k~L9H<#sKchw$0cU#*p!#Vu; ze+xCA?08ec@8c?w4yT82lJ=D87^g>`ln*|w(&T8Hxxeywy{o;G5~X`~ql>TRlV50d z3qIPr9|X-L{Y^FdG(s}Be^~m|d}p1e&L+c0URj~~CD_Ed3;NTY zyO~-&>K7YrZx_!RSZ0`qgt1qNqqP4>@ii`~%8Q#l>#P4*^Ql05-|N<`>55pLL(lK( zTXs?J8L!D5PORTfb<1`cTGZ5#aD%e!`1jxcGUj1YCdjr5+_al=jZ%=2P0jVsz9#oc z*Lj(5oG?hAYK?!5Kbf+nM~C4~Sah9G?gi z5S04D7VI_+s_O4o&6n5qFF;#|@fDoQ&sI0Yp*en#8p4{t(70Bmp}TTGpiBibQPj*H|iMf9m5$- zSowo6JL4igq4nqvY?9E4Em49qe_YMv|Ar{aw+DhRy+bbzINPeVmQx@yybZTI`4+=N z1s#~?E2ukVRC`px)O~~~@>?jUHT)R|CN9Pe{R5Y;;Di>y?P*axm}bu%*zrB&67P-% z>T!64>!+x{mN3b~0^-CY7;PkQk(@;y5)eFJw5*y%4)O^_nA;dmy|%X#3;FD=ynSyJ z-i8 zL@jp!@1iNUu@Hq$8#R_?($P7BQ$MeGx)u>CnlKA(XM2Fk^NJ7ImyS?lfx)c*ND0$?+V-rOy4Uj-g!cGeJM-7;JeVyBue_x>>5f9;9cboT zggN0JhsME@@x)%tM@NhM$tk@R%W!;!wM^AEQ{RtoFyKyy0$k6FW0Da@S@Ano&J5$T zm5>YVJsnx@|LzhZe7wk1Uc=%WXZ2#JJDQ)fh{}rQ8RFH&i>Sq2nC6qIBR@#23H*j` zV-2Y14Uc#&Ml`9cbu3*Le@X2qzR`W}(83c90MbA6-Rv2^hw2Xvd*6C(vywoXTWRX$r=TB3XRu50d;~ zE|agr39G(>CejffCcnP$PZ>)|`3dYYnZ_b#rd~l-t*1ci`&L*4&28@o%a$8o*{^qCcx@azJ%RjU}@noyeN?c1~rkj*aC@4%4!8Y0v`ovA*B zmUVYvMI#7vJCmgO%i#jY#Q+N#pkwJ1c!t|3ZdVT5f$#5us2}YGn{D_+*M2m!5@9}V z(~MfwmR++iC|Lwtthg7mFt%5kbPQ~(8~JDxLm2y8Qj1$LpT!q7a`!WsHzI>jsJ7Yd zCXDK)cVa2gpVA2Y1m!b*P+)ao`tGnBqVByco8=L1h(bKU4UcD%@oy8`CMNJ3?O430 zlGbGdr6#89qmT)&1zR4WLNELvCFU9O5@QPwJjnv&>qD- z22>~_d=UMqHOZezj->(;9>%+ZTCuHb*`XG1Z0<|8L#s8Osc>HuZa(9T8(2T z{2DbUkMyfn*6%~Z6FaeqrcX7wHxPA5>J_3SAYmnwZ*x+G^AG0t`X9AJnBoQ5@Kiz! zEoKftKt_OwgmzfUsBlno3 z20+MfPWI8)<%7v-`>!GjD)@Rs)BlcdVUbkTPbjpEoyI5XYWPI;Fn)Ki1QM|*GA0o0 zBLMqjxSjY<*_S4Y#W(KSm3e01A%ygFU~mcC_!@FK1=a{8a5Fydq%>4&sXTZI3eb4E zIUq>B$4XtZ@tBxSenv;$roq{ zF5Wp_n}{%d08=wwVQ3eVT&%*UX6FM!<4Xhtw-r%j$WmDR4?w1(dEk$+j~@?hxE4zF z2JmWWAHk=I5|O85Tr)^xrMrF%F_1Ne56x|20-%+;-EZEt#}HrVrM;hKkzX_?2a0t^ zr(y_(X-01^rWrntQ-kv1f_pHVpZOdLs9dHYIA!x+7SN~kpn7_MCJX2>Lp?Q$FG^Dh zh>m41u);2^3+Uk|$|Q@wcVdBdC!lZ$m85x3q>&DYaJmvvuTf6mKWa=i)%+ZG`3@xd zAHtmZOMBVMhfMyi&}=x1@=KEW2(U%lLPWYuk`4+zl!-uAeSD$>ll)yvciGPnMzhF% zin-1(eNGms-%G+18=8M@VhBrMG-eFn3Uq+M1WYs6i{NO#Fciklx&p8VbzE_wj75%_ zvB(W)S}@Js57~fVUtwl__hDVrzT;@-cO8iO;$BuB84n5 zGO0hH4oU!u?ckfHRQM8LGph4nfs>2oxenw0Mt&J%-*I4@`+*BAZEiqA3?X9}U;Pqm zk3`E3g|U|!=0PqoO$>koU^`ZiIkADH1*&ishh88cEZNFaXwNc4P5XwAg>tZTT@3*W zhf>2)SAAd#Z?|Cnt&FvRI&3VJ8h_c`Xc$6-7rtqD!F#B*=LPmwy$zTs0G8XW7@Q5G zJ0vu}+GowvQ1@&H&&;pl@0^Kj(KpU3Dt6ssrSwf;p0j-dax^o6XDN8lZkne_2sV<+W>nfpA8?uGpeA{{RlIL?|L*Kydr@f z(0VKmZP>DObWyfcFlQ9&bOpr6SU#as5B6lma<&PdSTKfjAHhLVsG9;B4)E`G7WsS> z?*xKKDF?f{hMnQ$Vmm^g!`9flkNEn3X}H#^q8MVa>JUoH?&lL4hb29y|6zS6gSQ56 z1|3!hiRPMaGn4!|$|w)&PRfg0dB9k?9+>Vtnm%But|b6Z1#qZtGC>Elc6uk;0Gx|9 zlMm|pn?*)tQZGZIM`nI+5jFVVBTHChrwSj61i0gri$^Kr$JeI|P+H?Yv}~1f(6T@i z2xHjm7-C7sD1PG`8h}AJ>=?lp%A2v}Y+X)f2*UJ7gw5_O`ybHp%BOlAR{%ryC^C|vM%o8~_0;?}wF(GZB{XMaW% zeq2C&3pttHP`61(%P}PcxQN&tvm+3dZ1yF9O){Z`u<{ujfKOwRvmq1V8C`9BCxg`8 zfA5~(@umC~Hy7G^z_ZSDTRj^dVxxa9jIevKKeX$Vy2rCZzJkJv`gA>#h&CL>6J);H zN(t0`iF>X#_1um>vRBJ(mgxQv@ek+Rh{i(sW+Bn9;{i1@5~9* z8{2bodeNq0)HaCJR<82P7dP%mhUYvlMj=E;+_ZRV~byZ zFwtYLte>hn!Q5msSsc80e%XCEBMEM#Oiperp>W)eCQP5B6vq&blh031ElbmmBr;_| zF~rz`cl7R*#m?j=j<3-uz7SDI5%`J;y#2a>=r&_M<&UjSR$^Vcf{LCPXnIT(O_+1G zOrL>+W(?mr3)?W?NTMding3Qr=WG#OgtHFH8-KY5hf3lqFvm<;#_#ZyhieDc?g4Ck zrmQ^)F5>8lbkOlLNGN5rnkry5j?c{KvV-nHh}T`t)-&1@c#$W)Gzsbs*RlW!%8rT% z7Y*V=;Ej&$fqzDcyCrwD1;kJE(*HVn0;0d~Q{=04Ji;Yrr!#p;s+K^axFFQwE|8lh zrZeeD7fBGsVMGmzNi`H?E=L2KF_!L-=AsW*qX~ijgY+1prkFu4H@f%rHNM1|Py5Mh zq}BLNaYop~-@#Jp-I{_y)n$01@&X+>^E~&9e1%lKuJ$op08G;ET4(;_e*Cs!8k5wN zD&DG0#j+GApb!f908OtL!-Jx%rq??2_09l{^2Aoo3Tw+zbB8{BYa~Gzm~_+$2>iS( zM4l3CQHzHw9-jim=XuJ$==Y2jbnfViV+}l$1S1KeD zG09z@eGz8LKrv-9*>(a{OvYQvBTUPraFFvRJr!u7LO4R%{1Fn_qGhL(;0RD>4(xag zm3WOXP=^KAWd2JflHiYYD-EMNSKutC`wbI*CoRyP50L0zCcl)xZFdNd26SLm8(sF) zV*b}AcS52XC;wHJTdsLKZn_cJgmK@|1E}&w6zV>6`T`s@?o1}0i6ItjiX>(_tIeJH z@mX~&zNiTURZi?jdup+fyFcso;cJ;Bz*UAVBx+y+vO0okhHy(iqFBtHaCmRd0~?CMz*ZMjG?Tp`gbd@o+@qz@Cz+%YD>vb^ z$7qlKB89WuTChgP@oF8)=+ovxNc5mdRDALc-s;(hvm_0Wm9x5zkGc*Z!dM)$`RUO? zE`*?+q-7tj%@A6gld&xBYC!?#Wn0mPPOMm7u06%HVv*AzASOTO^1#ss=ppJ06%^J# z+(_blq#TY3j)qEEN#+s<3deUgL>G{g7AK+s^GcrwiI()^8NK5_jp7VBTojTTe5t+J z!WIN2E6>JeAE_FgO~G=h;xE|k9uyE4L;N9C9F_`|&Fh`mL!6=mj$LCJgh#B`&{zY!JViGsvfNkg!X zq#MNO9S zSd^B0@E+u%Gpdiy_+MMh;Cr+9q}zXBR|Yj${QbKhe#x#1ZFxQ4|0OnIc_fkm-Tylk zveJnB1X}(%le{M5awHA5gDT4gt@;gZn9nF~D~ACUn^0mm-N>Z1>QYgOZ8QPAQ51wY z3r`pyX;~8WDfcow6+E*GEz@M1RDP0r&rX5eb^0BJCwlu&XiS0>wm!@<6Pm7bCWqGo z@XJ!#raY)eT6Svl1FiXlX>lssHpJKjx%I2!2GDK+g7B2!d%`DPF zn9)3=`sVfN%+R@zoO1m2Kld=dpm2D>zNxCku`d8Y5AE)G zhLvmgskX2B+{v538F^Nmi9{h9Sb-H&VhN})ON)>G!Zfs_TUA9zdk^g>F?`Z&+p(GS z08CMS5AMwe^N%y#L$AV^On!nAu%^h{SE@KUC$NpNZI}g*=yF2KK=127R+WiR>2GjG z9_*$D+Qs4FSDTU{(AnD6Me#5~3JV zO)>>G9KbhxnD=!_tX+i2gBX2ol?Plsb{`&B{pSkY}Lp!Yd; z;w4t}9_qf$HA;zPt&O>0P2)#e)_o^coK1qW3Y_^sgESL0N8_CzX-b98 zH+t;x@%foDFLyv1k2^mBceD}e<`ykxkN`!%ArzIsSzg~{=1p=N(37K1_j|aX3~1xK zrN6ZL+o23pQ39p#|5wMo~;=&mA8bcC%dKU z{wki~b6rtA_GM%Tmq*fF1O&NUDtyKyjirh;|9ni&p|Wezhg9q8n*U%3H4o0*TChx# zNlT5H6PlWUH?_%=-ct3<1d|Vp2^A_m9g8{yfi^w5U=JjkWm96kwX6@=jN{eZPfE-% zX#@hkq5wF*V2UJ@Pk`w??J}H|&m!AP;NB(-Sj_@Z=Ll}1XXTmb4hqwumpV&mIiftc zJqq+q%Q1a4ZvJwHTwTON()pf0&)En z_qhRtB)6r36JFJiFm<=1afcD%k|BHq%uSmyM*v%J5MJPzN~?p9ptKwyuh-z3$jh=I z0bx2H>ONbGrJ9U6aNL@(+a{y>~zl^BX83?N}pN8~AIE4ZsiQhw3 zXI_D1Mt2#;4V}q5Uj=)bu~}=u1U_cX@dI=l^dUlm-9?4=0!Lhi3mQOPLzQ%->S_#FBH!pE4GO5m>h#bu6D~3E8yvL0sY!hXDpl+zx8*&k zXi~4Edr5`WPC$HX8T{6&lq5KwF5k#bOFV9wSvU;3wLL25QepkrFmC%bHI~@$0*g0O zI)Efzs%k<9D!q6iD;~T4pB|T4;bd zQgF2r82Bepsqat;I_}KW(ilCS02DHkNBg12_A3}6yF?Mu8UR&O8Igs<4OkUmYVy=L z1HfXUp^!`XSAv&>g&{Y%M5Nzs=`fQKpA47W%a!_k~`H2`-*IiOKjIoX^F zZX3nZuJpB@D(%A;YOqM4E}q}E9(Z2sLAWjpS~r1{8^I`4syLm0{;L|~;a<$qrVpV(_XHbrb<$!pTJxaL}g$Umjca zMFSG~FPrP%*+p$i?28)}Kqx@AegnEvi`jHG9X(o_08B<;@X_w&_nrSn z6#aTkIQvRO{Nq{3P5T?nULO82wu8IYq z&fP$*jp(A@iDWDrj-hv-frn^v8SL1HgZYw02R31@#DcU(C!20E(1yZckn%dP;`p>G zYeflM)aQ6N8Sq$l^e7(Mr^-MSM-Vk=^GjTy>C?Whd!T@3%m&aANGxOpmuIl;J`_u= zizZmfi=^t36sWYg@sG72XZPV#;~hO*VltN1*oUvr1G&e(66%g~T!iL>fV9BAX#BJX z2My0)8G=&i=VV^;x)q2JVCqRGaJUFCM8n@m?-`bH8-Ty$A89G(KvtAu zFw|2*B7TOL0z^sxzM&UU8$ni8C0F37*YRWB&4L!D=?}p>^OM4U94eXZ$~3fC*?Kr; z8{?-N$&nR@?k>4*ZfNl`E&j?!BPc+d@$ez+<|!S-citGnyH25TN5=;HRP?X(fI!A= zF0I_@cYWZRk~(?%BE9(TFtz#|-KAWrPF(k_-7bn48^D9SMjG6%FzRE7XJdGljl6e; zZx9XpsBptkED??|xl^YbKUanq*e?yi06y!1ma!1^2OWC1fH;dNe%rhz8+J^F(WYI> z{Lq%JLT7R+!+8w%U1)@sjrZYTTJ;>b7+GTsvD`G;nWR;KD;BnZcs_=ARWEu$2c)1Q zv98)~nwwX42)$@)GPJ+Jl*xbI{3{AR&KS*S2=5{a@Bqaqz9Ji*HQlG*hX-2)XacM`5SgA;RrwkJCT@OSlQRe>pqI2z7AG z@zh3p3MR0SCR+Z_by$Y&ljY#{!V6qEf|VHGIWca2PL^^7a@hf9iI1DDg4>}05dJpY z&v#Y~%nh;8-!9Z(J8Rdx8pma{EEahS5rzP3k7z{lfc;NfigL9^7xWxGI{j~$dS(m? zX!r<-M3bFDp?A|*T6I_ixJ#MwK^>-sINq@;Bo0NvDX?Q(n8E-=!^3wXzB6TK4dFN9eY*Qp3pAMI)`iz(6Fs|)Bod%`%H>x- ze1)cG()t=-h)}pU6HF!?(V1u>8rkN;Ni!J&W0QC{PMTXi26uFeMbCVtLal@2+M|~# zvGoZcXc*D0G>z{}n1PwF?Wk7ARvnNrWL@8u+@r!*P&^AgL389(G$~#jJAkCrRtSjf zmX*%riHbrraOo;U(1x)n#hyn^7qESvG;h@9KOX~wC8H4o z_j!jhlBoNmiHHnx4B?=z2f5Fqi8a5kUxnsViU;rq%q$gN1#Xi5yE}}>SXG9D!vw2# z*%d_$%s{0Fpnw$D=a^#=lN=NfqB7V=21lsy+w;z7ol1^g_1oz*acOgt@Vzrh0Ss`2 zNxt9E)y{=V=dmY#Sc(Qd-Iz!HqNog0D@?Xte{JLs)XSOF163_mW`1`Vw0Y&cTFmZL z(U0zET#`1x`pG#?eF*!MBSLW7^#fFz4f|N5U{QO9!1aFzh%Hm{aqtYlui>b51Yqh- zXeLO?K9(0WM&JK{2J+L5CGYQL4&sbW8L+N|Rxt)j3mebG~NgY@USgr$vxjR-T`A>VC<)i3ji;(9d<(3Hx=A3vTJsy<>m6i!SyFTk{*%@ z1>F94%USUn5BV#I@Jj!92Mn?hAy5eshzt`UwdGa9mspL@6z*ko6;6@=^iTB|4yG6q zs#N&vlR37GIz^6Qprntjm2*>$xRq$xDXDNxee>AvCJa3Wxv1y3!3az*8w$0qdrv%R z{xSr)oPis|(M)jd{#nX=o;v~D^EIgS*3v1!s{tNH{VMye?!sZZVy)^+p>an7h;SFc z<3-)qzIjZDvde0(H}JOhcoyu!+lv;;xZ4p4VvGx%L0Wxn}P zpl2B9UXVlTL!~Z%!$Z55e!ZVVKDQEp5t*Iw9X4S0y?TMlva@}Z(PU7fHJB3r!!3Z* z`tU;4ecPrcp#~bK+N9TzLmGJSt~X*4EmC3T1l~0*Wquulhc|8fofnT%QdZ`8e#Wt&q$3P+y*+rAsoQI03_M9u*a&hNSb(Wp z4K!WldoIA)IhwecyCDgLC$63*$2SMz6U9jtSizj5_;LvnA%k<`HkJk#9N&Tf72}U{ ziDA8b7tjh3pvSUd3(!G4BHptQQJ4lXkRoT2;1h^+4w8R)?P7!b9?EF2kqv{%;_F|K z6~c}~QsGk6!S_;0`fFS!ATnyqt8yu^3L|juUYiW3Io-&g>x3yLd2-&Z0sIE&OoaKb zKvSM!K+qB4&vS}A|9Tf@Q3N|~b>=^de*WWCcSxi+4?M;sRcKXV5nw}10AFi?!H8lE zH%s2|9P=H(eV8P;`~@mK;n6UcY>cJM*V91QuQx-ps}sroI + + + + +
+
+
Leaderboard
+
+
+ + + +
+
+
+ +
+
+ +
+
+
+ +
+ + + + + + + + + + + diff --git a/Games/Multiplayer_Shooting_Game/public/js/classes/Enemy.js b/Games/Multiplayer_Shooting_Game/public/js/classes/Enemy.js new file mode 100644 index 0000000000..a17c0e7ade --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/public/js/classes/Enemy.js @@ -0,0 +1,22 @@ +class Enemy { + constructor(x, y, radius, color, velocity) { + this.x = x + this.y = y + this.radius = radius + this.color = color + this.velocity = velocity + } + + draw() { + c.beginPath() + c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false) + c.fillStyle = this.color + c.fill() + } + + update() { + this.draw() + this.x = this.x + this.velocity.x + this.y = this.y + this.velocity.y + } +} diff --git a/Games/Multiplayer_Shooting_Game/public/js/classes/Particle.js b/Games/Multiplayer_Shooting_Game/public/js/classes/Particle.js new file mode 100644 index 0000000000..05df89b8f9 --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/public/js/classes/Particle.js @@ -0,0 +1,30 @@ +const friction = 0.99 +class Particle { + constructor(x, y, radius, color, velocity) { + this.x = x + this.y = y + this.radius = radius + this.color = color + this.velocity = velocity + this.alpha = 1 + } + + draw() { + c.save() + c.globalAlpha = this.alpha + c.beginPath() + c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false) + c.fillStyle = this.color + c.fill() + c.restore() + } + + update() { + this.draw() + this.velocity.x *= friction + this.velocity.y *= friction + this.x = this.x + this.velocity.x + this.y = this.y + this.velocity.y + this.alpha -= 0.01 + } +} diff --git a/Games/Multiplayer_Shooting_Game/public/js/classes/Player.js b/Games/Multiplayer_Shooting_Game/public/js/classes/Player.js new file mode 100644 index 0000000000..43fc4236aa --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/public/js/classes/Player.js @@ -0,0 +1,23 @@ +class Player { + constructor({ x, y, radius, color, username }) { + this.x = x + this.y = y + this.radius = radius + this.color = color + this.username = username + } + + draw() { + c.font = '12px sans-serif' + c.fillStyle = 'white' + c.fillText(this.username, this.x - 10, this.y + 20) + c.save() + c.shadowColor = this.color + c.shadowBlur = 20 + c.beginPath() + c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false) + c.fillStyle = this.color + c.fill() + c.restore() + } +} diff --git a/Games/Multiplayer_Shooting_Game/public/js/classes/Projectile.js b/Games/Multiplayer_Shooting_Game/public/js/classes/Projectile.js new file mode 100644 index 0000000000..f65e3f00de --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/public/js/classes/Projectile.js @@ -0,0 +1,26 @@ +class Projectile { + constructor({ x, y, radius, color = 'white', velocity }) { + this.x = x + this.y = y + this.radius = radius + this.color = color + this.velocity = velocity + } + + draw() { + c.save() + c.shadowColor = this.color + c.shadowBlur = 20 + c.beginPath() + c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false) + c.fillStyle = this.color + c.fill() + c.restore() + } + + update() { + this.draw() + this.x = this.x + this.velocity.x + this.y = this.y + this.velocity.y + } +} diff --git a/Games/Multiplayer_Shooting_Game/public/js/eventListeners.js b/Games/Multiplayer_Shooting_Game/public/js/eventListeners.js new file mode 100644 index 0000000000..bb1b57920b --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/public/js/eventListeners.js @@ -0,0 +1,35 @@ +addEventListener('click', (event) => { + const canvas = document.querySelector('canvas') + const { top, left } = canvas.getBoundingClientRect() + const playerPosition = { + x: frontEndPlayers[socket.id].x, + y: frontEndPlayers[socket.id].y + } + + const angle = Math.atan2( + event.clientY - top - playerPosition.y, + event.clientX - left - playerPosition.x + ) + + // const velocity = { + // x: Math.cos(angle) * 5, + // y: Math.sin(angle) * 5 + // } + + socket.emit('shoot', { + x: playerPosition.x, + y: playerPosition.y, + angle + }) + // frontEndProjectiles.push( + // new Projectile({ + // x: playerPosition.x, + // y: playerPosition.y, + // radius: 5, + // color: 'white', + // velocity + // }) + // ) + + console.log(frontEndProjectiles) +}) diff --git a/Games/Multiplayer_Shooting_Game/public/js/frontend.js b/Games/Multiplayer_Shooting_Game/public/js/frontend.js new file mode 100644 index 0000000000..d3140bf7af --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/public/js/frontend.js @@ -0,0 +1,262 @@ +const canvas = document.querySelector('canvas') +const c = canvas.getContext('2d') + +const socket = io() + +const scoreEl = document.querySelector('#scoreEl') + +const devicePixelRatio = window.devicePixelRatio || 1 + +canvas.width = 1024 * devicePixelRatio +canvas.height = 576 * devicePixelRatio + +c.scale(devicePixelRatio, devicePixelRatio) + +const x = canvas.width / 2 +const y = canvas.height / 2 + +const frontEndPlayers = {} +const frontEndProjectiles = {} + +socket.on('updateProjectiles', (backEndProjectiles) => { + for (const id in backEndProjectiles) { + const backEndProjectile = backEndProjectiles[id] + + if (!frontEndProjectiles[id]) { + frontEndProjectiles[id] = new Projectile({ + x: backEndProjectile.x, + y: backEndProjectile.y, + radius: 5, + color: frontEndPlayers[backEndProjectile.playerId]?.color, + velocity: backEndProjectile.velocity + }) + } else { + frontEndProjectiles[id].x += backEndProjectiles[id].velocity.x + frontEndProjectiles[id].y += backEndProjectiles[id].velocity.y + } + } + + for (const frontEndProjectileId in frontEndProjectiles) { + if (!backEndProjectiles[frontEndProjectileId]) { + delete frontEndProjectiles[frontEndProjectileId] + } + } +}) + +socket.on('updatePlayers', (backEndPlayers) => { + for (const id in backEndPlayers) { + const backEndPlayer = backEndPlayers[id] + + if (!frontEndPlayers[id]) { + frontEndPlayers[id] = new Player({ + x: backEndPlayer.x, + y: backEndPlayer.y, + radius: 10, + color: backEndPlayer.color, + username: backEndPlayer.username + }) + + document.querySelector( + '#playerLabels' + ).innerHTML += `
${backEndPlayer.username}: ${backEndPlayer.score}
` + } else { + document.querySelector( + `div[data-id="${id}"]` + ).innerHTML = `${backEndPlayer.username}: ${backEndPlayer.score}` + + document + .querySelector(`div[data-id="${id}"]`) + .setAttribute('data-score', backEndPlayer.score) + + // sorts the players divs + const parentDiv = document.querySelector('#playerLabels') + const childDivs = Array.from(parentDiv.querySelectorAll('div')) + + childDivs.sort((a, b) => { + const scoreA = Number(a.getAttribute('data-score')) + const scoreB = Number(b.getAttribute('data-score')) + + return scoreB - scoreA + }) + + // removes old elements + childDivs.forEach((div) => { + parentDiv.removeChild(div) + }) + + // adds sorted elements + childDivs.forEach((div) => { + parentDiv.appendChild(div) + }) + + frontEndPlayers[id].target = { + x: backEndPlayer.x, + y: backEndPlayer.y + } + + if (id === socket.id) { + const lastBackendInputIndex = playerInputs.findIndex((input) => { + return backEndPlayer.sequenceNumber === input.sequenceNumber + }) + + if (lastBackendInputIndex > -1) + playerInputs.splice(0, lastBackendInputIndex + 1) + + playerInputs.forEach((input) => { + frontEndPlayers[id].target.x += input.dx + frontEndPlayers[id].target.y += input.dy + }) + } + } + } + + // this is where we delete frontend players + for (const id in frontEndPlayers) { + if (!backEndPlayers[id]) { + const divToDelete = document.querySelector(`div[data-id="${id}"]`) + divToDelete.parentNode.removeChild(divToDelete) + + if (id === socket.id) { + document.querySelector('#usernameForm').style.display = 'block' + } + + delete frontEndPlayers[id] + } + } +}) + +let animationId +function animate() { + animationId = requestAnimationFrame(animate) + // c.fillStyle = 'rgba(0, 0, 0, 0.1)' + c.clearRect(0, 0, canvas.width, canvas.height) + + for (const id in frontEndPlayers) { + const frontEndPlayer = frontEndPlayers[id] + + // linear interpolation + if (frontEndPlayer.target) { + frontEndPlayers[id].x += + (frontEndPlayers[id].target.x - frontEndPlayers[id].x) * 0.5 + frontEndPlayers[id].y += + (frontEndPlayers[id].target.y - frontEndPlayers[id].y) * 0.5 + } + + frontEndPlayer.draw() + } + + for (const id in frontEndProjectiles) { + const frontEndProjectile = frontEndProjectiles[id] + frontEndProjectile.draw() + } + + // for (let i = frontEndProjectiles.length - 1; i >= 0; i--) { + // const frontEndProjectile = frontEndProjectiles[i] + // frontEndProjectile.update() + // } +} + +animate() + +const keys = { + w: { + pressed: false + }, + a: { + pressed: false + }, + s: { + pressed: false + }, + d: { + pressed: false + } +} + +const SPEED = 5 +const playerInputs = [] +let sequenceNumber = 0 +setInterval(() => { + if (keys.w.pressed) { + sequenceNumber++ + playerInputs.push({ sequenceNumber, dx: 0, dy: -SPEED }) + // frontEndPlayers[socket.id].y -= SPEED + socket.emit('keydown', { keycode: 'KeyW', sequenceNumber }) + } + + if (keys.a.pressed) { + sequenceNumber++ + playerInputs.push({ sequenceNumber, dx: -SPEED, dy: 0 }) + // frontEndPlayers[socket.id].x -= SPEED + socket.emit('keydown', { keycode: 'KeyA', sequenceNumber }) + } + + if (keys.s.pressed) { + sequenceNumber++ + playerInputs.push({ sequenceNumber, dx: 0, dy: SPEED }) + // frontEndPlayers[socket.id].y += SPEED + socket.emit('keydown', { keycode: 'KeyS', sequenceNumber }) + } + + if (keys.d.pressed) { + sequenceNumber++ + playerInputs.push({ sequenceNumber, dx: SPEED, dy: 0 }) + // frontEndPlayers[socket.id].x += SPEED + socket.emit('keydown', { keycode: 'KeyD', sequenceNumber }) + } +}, 15) + +window.addEventListener('keydown', (event) => { + if (!frontEndPlayers[socket.id]) return + + switch (event.code) { + case 'KeyW': + keys.w.pressed = true + break + + case 'KeyA': + keys.a.pressed = true + break + + case 'KeyS': + keys.s.pressed = true + break + + case 'KeyD': + keys.d.pressed = true + break + } +}) + +window.addEventListener('keyup', (event) => { + if (!frontEndPlayers[socket.id]) return + + switch (event.code) { + case 'KeyW': + keys.w.pressed = false + break + + case 'KeyA': + keys.a.pressed = false + break + + case 'KeyS': + keys.s.pressed = false + break + + case 'KeyD': + keys.d.pressed = false + break + } +}) + +document.querySelector('#usernameForm').addEventListener('submit', (event) => { + event.preventDefault() + document.querySelector('#usernameForm').style.display = 'none' + socket.emit('initGame', { + width: canvas.width, + height: canvas.height, + devicePixelRatio, + username: document.querySelector('#usernameInput').value + }) +}) diff --git a/Games/Multiplayer_Shooting_Game/readme.md b/Games/Multiplayer_Shooting_Game/readme.md new file mode 100644 index 0000000000..b040e0e575 --- /dev/null +++ b/Games/Multiplayer_Shooting_Game/readme.md @@ -0,0 +1,3 @@ +# Multiplayer online shooting game + +[Portfolio](https://vaibhavkesarwani.vercel.app) diff --git a/README.md b/README.md index 6c2158c946..a7918e1f5d 100644 --- a/README.md +++ b/README.md @@ -1662,7 +1662,7 @@ This repository also provides one such platforms where contributers come over an | [Airhockey_game](https://github.com/kunjgit/GameZone/tree/main/Games/Airhockey_game)| |[King_Sword_Runner](https://github.com/kunjgit/GameZone/tree/main/Games/King_Sword_Runner)| - +|[Multiplayer_Shooting_Game](https://github.com/kunjgit/GameZone/tree/main/Games/Multiplayer_Shooting_Game)| |[Smash-Monty-Mole](https://github.com/kunjgit/GameZone/tree/main/Smash-Monty-mole-master-main)| | [Hole_And_Mole_Game](https://github.com/kunjgit/GameZone/tree/main/Games/Hole_And_Mole_Game)| |[Animal_Name_Guessing](https://github.com/kunjgit/GameZone/tree/main/Games/Animal_Name_Guessing)| diff --git a/assets/images/Multiplayer_Shooting_Game.jpeg b/assets/images/Multiplayer_Shooting_Game.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9ec891ee6c800b83cf513d75c0c0fa8be0e806fa GIT binary patch literal 44092 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%0D8FF>-i^!Ueu{mMs z{Njvf7cHb`dvqy^hizkM(pFu0DDMupqxzK2%f6G0=WOM=e016rKhnNbg=dprrOGfqOU^UV;A1f(Ef$3~U{YtqkqI*2G z5P*%sktJ4adJPDWCr9}q_vtDrE8T%g*$ z8dV~XiP|R!cb-Bo4`FC->-@K+>MfCOf|w>6i;pDJ%DjR zQ5^Mv4W`Ll=s!R|NxOAS3@OBFXcIt?mo>|W)7i-8Z<@EG(<~3%inbp6j`@A7K|HPw zTwY5^0W2{wb~5_i`b_`g*VXR>x@D}tTscSRE$MK)PBBrv@;CHMx{jV`_XNb{))z6R zE{PxP52fA>z{Y4?!tBqz0xpv$bEZUAol=EWor05&8G>B6Z{{M7XdH1evFVA|)Bj|! zcfZm<(u}NrOIQENP=znAFD(Q4-ljgy&Yy#-n#7Sxql>cHwoFT#D5k11>;ZYw(q(YZesij~z`Ek8dM;E*fy{`|q@hLPff#7|#+44l4pE z5#X~6hCYe@MR!3}&Ec0^(%E+6a+2Bh#Y1j6OFHB+o_;E^HaTAQA0TlvU;Udn9-!|% zINr1$l2ZwO4Azni;|7&%ieOfD@>5dM`G7d6+s6! z&*ra&0(ga|bZE~=8`pvJd|LSlBTm1z$I{a{ih{X*Fns%sOJ+O9)SY(UBpAI)7>;7j zit~vmpD6$_f+|@FqEYk;s&I;zyiq4zUy6(B1+V$~J!xV334wx1Ze6jfWFrK^b5)+Q z!wBUC=&CUQ@tHs_1kA#LH18TP8*Na`&f07j#FC%bSC7I_MNjIuA&iakg;3(5`lpLX+#Sv1+QR8-7

ejBRNEL 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 tKze~-s|AT{ss{~RqJ}gDuqZkuTU=B&d~+`npv&