mirror of
https://github.com/owenlejeune/AirHockey.git
synced 2025-11-08 00:22:45 -05:00
323 lines
10 KiB
JavaScript
Executable File
323 lines
10 KiB
JavaScript
Executable File
const app = require("http").createServer(handler);
|
|
const fs = require("fs");
|
|
const url = require("url");
|
|
const io = require("socket.io")(app);
|
|
const PORT = process.env.PORT || 3000;
|
|
const ROOT_DIR = "html";
|
|
const MIME_TYPES = {
|
|
css: "text/css",
|
|
gif: "image/gif",
|
|
htm: "text/html",
|
|
html: "text/html",
|
|
ico: "image/x-icon",
|
|
jpeg: "image/jpeg",
|
|
jpg: "image/jpeg",
|
|
js: "application/javascript",
|
|
json: "application/json",
|
|
png: "image/png",
|
|
txt: "text/plain"
|
|
};
|
|
const timer = setInterval(handleTimer, 30);
|
|
const PLAYERS_AVAILABLE = {
|
|
p1: true,
|
|
p2: true
|
|
}
|
|
const PLAYER_ONE_STATE = 0;
|
|
const PLAYER_TWO_STATE = 1;
|
|
const SPECTATOR_STATE = 3;
|
|
const PLAYER_1_DEFAULT_X = 100;
|
|
const PLAYER_2_DEFAULT_X = 825;
|
|
const PLAYER_DEFAULT_Y = 200;
|
|
const PLAYER_DEFAULT_DIM = 75;
|
|
const PLAYER_DEFAULT_COLOUR = 'grey';
|
|
const PUCK_DEFAULT_COLOUR = 'black'
|
|
const PLAYER_1_COLOUR = 'orange';
|
|
const PLAYER_2_COLOUR = 'green';
|
|
const PLAYER_DEFAULT_NAME = "";
|
|
const PLAYER_DEFAULT_SCORE = 0;
|
|
const PUCK_DEFAULT_X = 500;
|
|
const PUCK_DEFAULT_Y = 235;
|
|
const PUCK_DEFAULT_RADIUS = 25;
|
|
const DIR_UP = -1;
|
|
const DIR_DOWN = 1;
|
|
const DIR_LEFT = -1;
|
|
const DIR_RIGHT = 1;
|
|
const DIR_NONE = 0;
|
|
const dXY = 5;
|
|
|
|
var canvasWidth = 1000;
|
|
var canvasHeight = 500;
|
|
var windowsID = 0;
|
|
var spectators = [];
|
|
var player1 = {
|
|
state: PLAYER_ONE_STATE,
|
|
x: PLAYER_1_DEFAULT_X,
|
|
y: PLAYER_DEFAULT_Y,
|
|
side: PLAYER_DEFAULT_DIM,
|
|
score: PLAYER_DEFAULT_SCORE,
|
|
colour: PLAYER_DEFAULT_COLOUR,
|
|
name: PLAYER_DEFAULT_NAME
|
|
};
|
|
var player2 = {
|
|
state: PLAYER_TWO_STATE,
|
|
x: PLAYER_2_DEFAULT_X,
|
|
y: PLAYER_DEFAULT_Y,
|
|
side: PLAYER_DEFAULT_DIM,
|
|
score: PLAYER_DEFAULT_SCORE,
|
|
colour: PLAYER_DEFAULT_COLOUR,
|
|
name: PLAYER_DEFAULT_NAME
|
|
};
|
|
var puck = {
|
|
x: PUCK_DEFAULT_X,
|
|
y: PUCK_DEFAULT_Y,
|
|
radius: PUCK_DEFAULT_RADIUS,
|
|
directionX: DIR_NONE,
|
|
directionY: DIR_NONE,
|
|
colour: PUCK_DEFAULT_COLOUR
|
|
}
|
|
|
|
function get_mime(filename){
|
|
let ext, type;
|
|
for(let ext in MIME_TYPES){
|
|
type = MIME_TYPES[ext];
|
|
if(filename.indexOf(ext, filename.length - ext.length) !== -1){
|
|
return type;
|
|
}
|
|
}
|
|
return MIME_TYPES['txt'];
|
|
}
|
|
|
|
app.listen(PORT);
|
|
|
|
io.on("connection", (socket) => {
|
|
socket.on("newWindowLoad", (data) => {
|
|
var responseObj = {player1: player1, player2: player2, puck: puck, id: windowsID};
|
|
windowsID++;
|
|
io.emit("newWindowLoadResponse", JSON.stringify(responseObj));
|
|
});
|
|
socket.on("keyPressed", (data) => {
|
|
var receivedData = JSON.parse(data);
|
|
if(receivedData.state === PLAYER_ONE_STATE){
|
|
player1.x = receivedData.x;
|
|
player1.y = receivedData.y;
|
|
}else{
|
|
player2.x = receivedData.x;
|
|
player2.y = receivedData.y;
|
|
}
|
|
io.emit("playerMove", data);
|
|
});
|
|
socket.on("newPlayerRequest", (data) => {
|
|
var receivedData = JSON.parse(data);
|
|
findPlayerPosition(receivedData.name, receivedData.id);
|
|
});
|
|
socket.on("playerLeaveGame", (data) => {
|
|
var receivedData = JSON.parse(data);
|
|
if(receivedData.state === PLAYER_ONE_STATE){
|
|
PLAYERS_AVAILABLE.p1 = true;
|
|
resetPlayer(player1);
|
|
}else if(receivedData.state === PLAYER_TWO_STATE){
|
|
PLAYERS_AVAILABLE.p2 = true;
|
|
resetPlayer(player2);
|
|
}else{
|
|
var id = receivedData.id;
|
|
for(let spectator of spectators){
|
|
if(id === spectator.id){
|
|
spectators.splice(spectator, 1);
|
|
break;
|
|
}
|
|
}
|
|
io.emit("spectatorLeft", JSON.stringify({spectators: spectators}));
|
|
}
|
|
});
|
|
socket.on("spectatorJoinRequest", (data) => {
|
|
var receivedData = JSON.parse(data);
|
|
var id = receivedData.id;
|
|
var name;
|
|
for(let spectator of spectators){
|
|
if(id === spectator.id){
|
|
name = spectator.name;
|
|
spectators.splice(spectator, 1);
|
|
break;
|
|
}
|
|
}
|
|
io.emit("spectatorLeft", JSON.stringify({spectators: spectators}));
|
|
findPlayerPosition(name, id);
|
|
});
|
|
});
|
|
|
|
function findPlayerPosition(name, id){
|
|
if(PLAYERS_AVAILABLE.p1){
|
|
PLAYERS_AVAILABLE.p1 = false;
|
|
player1.colour = PLAYER_1_COLOUR;
|
|
player1.name = name;
|
|
var responseObj = {id: id, player: player1};
|
|
io.emit("newPlayerResponse", JSON.stringify(responseObj));
|
|
}else if(PLAYERS_AVAILABLE.p2){
|
|
PLAYERS_AVAILABLE.p2 = false;
|
|
player2.colour = PLAYER_2_COLOUR;
|
|
player2.name = name;
|
|
var responseObj = {id: id, player:player2};
|
|
io.emit("newPlayerResponse", JSON.stringify(responseObj));
|
|
}else{
|
|
spectators.push({id: id, name: name});
|
|
io.emit("newPlayerResponse", JSON.stringify({id: id, player: SPECTATOR_STATE, names: spectators}));
|
|
}
|
|
startGame();
|
|
}
|
|
|
|
function resetPlayer(player){
|
|
player1.x = PLAYER_1_DEFAULT_X;
|
|
player1.y = PLAYER_DEFAULT_Y;
|
|
player2.x = PLAYER_2_DEFAULT_X;
|
|
player2.y = PLAYER_DEFAULT_Y;
|
|
player1.score = PLAYER_DEFAULT_SCORE;
|
|
player2.score = PLAYER_DEFAULT_SCORE;
|
|
player.colour = PLAYER_DEFAULT_COLOUR;
|
|
player.name = PLAYER_DEFAULT_NAME;
|
|
puck.x = PUCK_DEFAULT_X;
|
|
puck.y = PUCK_DEFAULT_Y;
|
|
puck.directionX = DIR_NONE;
|
|
puck.directionY = DIR_NONE;
|
|
var responseObj = {player1: player1, player2: player2, puck: puck};
|
|
io.emit("playerReset", JSON.stringify(responseObj));
|
|
}
|
|
|
|
function startGame(){
|
|
if(!PLAYERS_AVAILABLE.p1 && !PLAYERS_AVAILABLE.p2){
|
|
puck.directionX = (Math.random() < 0.5) ? DIR_LEFT : DIR_RIGHT;
|
|
puck.directionY = (Math.random() < 0.5) ? DIR_UP : DIR_DOWN;
|
|
io.emit('startGame', JSON.stringify(puck));
|
|
}
|
|
}
|
|
|
|
function handler(request, response){
|
|
let urlObj = url.parse(request.url, true, false);
|
|
|
|
console.log("\n============================")
|
|
console.log("PATHNAME: " + urlObj.pathname)
|
|
console.log("REQUEST: " + ROOT_DIR + urlObj.pathname)
|
|
|
|
let receivedData = ""
|
|
|
|
request.on("data", (chunk) => {
|
|
receivedData += chunk;
|
|
});
|
|
|
|
request.on("end", () =>{
|
|
console.log("REQUEST END: ");
|
|
|
|
if(request.method == "GET"){
|
|
console.log("METHOD: GET");
|
|
fs.readFile(ROOT_DIR + urlObj.pathname, (err, data) => {
|
|
if(err){
|
|
console.log("ERROR: " + JSON.stringify(err).red);
|
|
response.writeHead(404);
|
|
response.end(JSON.stringify(err));
|
|
return;
|
|
}
|
|
response.writeHead(200, {"Content-Type": get_mime(urlObj.pathname)});
|
|
response.end(data);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function handleTimer(){
|
|
if(!PLAYERS_AVAILABLE.p1 && !PLAYERS_AVAILABLE.p2){
|
|
puck.x = puck.x + 5 * puck.directionX;
|
|
puck.y = puck.y + 5 * puck.directionY;
|
|
|
|
var hit = false;
|
|
|
|
if(puck.x + puck.radius >= canvasWidth){
|
|
if(puck.y > canvasHeight/3 && puck.y < canvasHeight*(2/3)){
|
|
puck.directionX = 0;
|
|
puck.directionY = 0;
|
|
player1.score += 1;
|
|
pointScored();
|
|
}else{puck.directionX = DIR_LEFT;}
|
|
}
|
|
if(puck.x-puck.radius <= 0){
|
|
if(puck.y > canvasHeight/3 && puck.y < canvasHeight*(2/3)){
|
|
puck.directionX = 0;
|
|
puck.directionY = 0;
|
|
player2.score += 1;
|
|
pointScored();
|
|
}else{puck.directionX = DIR_RIGHT;}
|
|
}
|
|
if(puck.y-puck.radius < 0){hit = true; puck.directionY = DIR_DOWN;}
|
|
if(puck.y + puck.radius > canvasHeight){hit = true; puck.directionY = DIR_UP;}
|
|
|
|
if(hit){io.emit("collision", null);}
|
|
|
|
detectCollision();
|
|
}
|
|
}
|
|
|
|
function detectCollision(){
|
|
var collision = false;
|
|
//TOP
|
|
if(player1.x <= puck.x && player1.x+player1.side >= puck.x
|
|
&& puck.y+puck.radius >= player1.y && puck.y < player1.y){
|
|
collision = true;
|
|
puck.directionY = DIR_UP;
|
|
}
|
|
if(player2.x <= puck.x && player2.x+player2.side >= puck.x
|
|
&& puck.y+puck.radius >= player2.y && puck.y < player2.y){
|
|
collision = true;
|
|
puck.directionY = DIR_UP;
|
|
}
|
|
//BOTTOM
|
|
if(player1.x <= puck.x && player1.x+player1.side >= puck.x
|
|
&& puck.y-puck.radius <= player1.y+player1.side && puck.y > player1.y+player1.side){
|
|
collision = true;
|
|
puck.directionY = DIR_DOWN;
|
|
}
|
|
if(player2.x <= puck.x && player2.x+player2.side >= puck.x
|
|
&& puck.y-puck.radius <= player2.y+player2.side && puck.y > player2.y+player2.side){
|
|
collision = true;
|
|
puck.directionY = DIR_DOWN;
|
|
}
|
|
//RIGHT
|
|
if(puck.y >= player1.y && puck.y <= player1.y+player1.side
|
|
&& puck.x-puck.radius <= player1.x+player1.side && puck.x > player1.x+player1.side){
|
|
collision = true;
|
|
puck.directionX = DIR_RIGHT;
|
|
}
|
|
if(puck.y >= player2.y && puck.y <= player2.y+player2.side
|
|
&& puck.x-puck.radius <= player2.x+player2.side && puck.x > player2.x+player2.side){
|
|
collision = true;
|
|
puck.directionX = DIR_RIGHT;
|
|
}
|
|
//LEFT
|
|
if(puck.y >= player1.y && puck.y <= player1.y+player1.side
|
|
&& puck.x+puck.radius >= player1.x && puck.x < player1.x){
|
|
collision = true;
|
|
puck.directionX = DIR_LEFT;
|
|
}
|
|
if(puck.y >= player2.y && puck.y <= player2.y+player2.side
|
|
&& puck.x+puck.radius >= player2.x && puck.x < player2.x){
|
|
collision = true;
|
|
puck.directionX = DIR_LEFT;
|
|
}
|
|
io.emit('timerTick', JSON.stringify(puck));
|
|
if(collision){io.emit("collision", null);}
|
|
}
|
|
|
|
function pointScored(){
|
|
puck.x = PUCK_DEFAULT_X;
|
|
puck.y = PUCK_DEFAULT_Y;
|
|
puck.directionX = (Math.random() < 0.5) ? DIR_LEFT : DIR_RIGHT;
|
|
puck.directionY = (Math.random() < 0.5) ? DIR_UP : DIR_DOWN;
|
|
player1.x = PLAYER_1_DEFAULT_X;
|
|
player1.y = PLAYER_DEFAULT_Y;
|
|
player2.x = PLAYER_2_DEFAULT_X;
|
|
player2.y = PLAYER_DEFAULT_Y;
|
|
var returnObj = {p1Score: player1.score, p2Score: player2.score, p1x: player1.x,
|
|
p1y: player1.y, p2x: player2.x, p2y: player2.y, puck: puck};
|
|
io.emit("pointScored", JSON.stringify(returnObj));
|
|
}
|
|
|
|
console.log("Server Running at PORT: 3000 CNTL-C to quit");
|
|
console.log("To Test: open several browsers at: http://localhost:3000/airhockey.html")
|