xxxxxxxxxx
702
//options for player colors
let playerColors = ["blue","red","orange","yellow","green","purple","teal","black","grey"];
let players = {};
let items = {};
let bullets = {};
let walls = [];
let userId,userRef;
let gameWidth = 600;
let gameHeight = 600;
const spawns = [[gameWidth/6,gameHeight/6],[5*gameWidth/6,gameHeight/6],[5*gameWidth/6,5*gameHeight/6],[gameWidth/6,5*gameHeight/6],[gameWidth/2,gameHeight/2]];
let possibleSpawns = [];
const tankWidth = 25;
const tankHeight = 20;
const barrelWidth = 18;
const bulletSpeed = 3;
const bulletLifeTimeMax = 250;
const maxBullets = 7;
const bulletSize = 5;
const wallSize = 10;
let roundOver = true;
let roundBeginning = false;
let startTimer = 0;
let noShoot = false;
//to do
//Fix item pick ups to use hit detection rather than point to point pick up
//consider bullet radius in hit detection
//--------------------------------\\
//-------------BUGS---------------\\
//--------------------------------\\
//bullets travel through hor walls\\
//bullets lag at end of their life. Maybe have each user only update their own bullets\\
//round does not begin for everyone\\
//--------------------------------\\
function restartGame(){
console.log("restarting game");
//reset all spawn lasdocations
possibleSpawns = spawns.slice();
//set all players to be alive and on a new spawn location
Object.keys(players).forEach((key) => {
//increase score for player that is alive
if(players[key].alive){
players[key].score++;
}
//set new spawn location
const spawnIndex = floor(random(possibleSpawns.length));
const pos = spawns[spawnIndex];
possibleSpawns.splice(spawnIndex,1);
players[key].x = pos[0];
players[key].y = pos[1];
//set alive
players[key].alive = true;
//update
const playerRef = firebase.database().ref(`players/${key}`);
playerRef.set(players[key]);
});
roundOver = false;
roundBeginning = true;
startTimer = 0;
noShoot = false;
}
function makeBasicMap(){
//create walls
//top wall
append(walls,new Wall(0,0,gameWidth,wallSize));
//left wall
append(walls,new Wall(gameWidth-wallSize,0,wallSize,gameHeight));
//bot wall
append(walls,new Wall(0,gameHeight-wallSize,gameWidth,wallSize));
//right
append(walls,new Wall(0,0,wallSize,gameHeight));
//basic horizontal wall
//append(walls,new Wall(gameWidth/wallSize,0,wallSize,gameHeight/wallSize));
//basic vertical wall
//append(walls, new Wall(0,gameHeight/wallSize,gameWidth/wallSize,wallSize));
append(walls,new Wall(3*gameWidth/wallSize,0,wallSize,gameHeight/wallSize));
append(walls,new Wall(3*gameWidth/wallSize,2*gameHeight/wallSize,wallSize,gameHeight/wallSize));
append(walls, new Wall(0,3*gameHeight/wallSize,gameWidth/wallSize,wallSize));
append(walls, new Wall(2*gameWidth/wallSize,3*gameHeight/wallSize,gameWidth/wallSize,wallSize));
append(walls,new Wall(7*gameWidth/wallSize,0,wallSize,gameHeight/wallSize));
append(walls,new Wall(7*gameWidth/wallSize,2*gameHeight/wallSize,wallSize,gameHeight/wallSize));
append(walls, new Wall(7*gameWidth/wallSize,3*gameHeight/wallSize,gameWidth/wallSize,wallSize));
append(walls, new Wall(9*gameWidth/wallSize,3*gameHeight/wallSize,gameWidth/wallSize,wallSize));
append(walls,new Wall(3*gameWidth/wallSize,7*gameHeight/wallSize,wallSize,gameHeight/wallSize));
append(walls,new Wall(3*gameWidth/wallSize,9*gameHeight/wallSize,wallSize,gameHeight/wallSize));
append(walls, new Wall(0,7*gameHeight/wallSize,gameWidth/wallSize,wallSize));
append(walls, new Wall(2*gameWidth/wallSize,7*gameHeight/wallSize,gameWidth/wallSize,wallSize));
append(walls,new Wall(7*gameWidth/wallSize,7*gameHeight/wallSize,wallSize,gameHeight/wallSize));
append(walls,new Wall(7*gameWidth/wallSize,9*gameHeight/wallSize,wallSize,gameHeight/wallSize));
append(walls, new Wall(7*gameWidth/wallSize,7*gameHeight/wallSize,gameWidth/wallSize,wallSize));
append(walls, new Wall(9*gameWidth/wallSize,7*gameHeight/wallSize,gameWidth/wallSize,wallSize));
append(walls,new Wall(5*gameWidth/wallSize,gameHeight/wallSize,wallSize,3*gameHeight/wallSize));
append(walls,new Wall(5*gameWidth/wallSize,6*gameHeight/wallSize,wallSize,3*gameHeight/wallSize));
append(walls, new Wall(gameWidth/wallSize,5*gameHeight/wallSize,3*gameWidth/wallSize,wallSize));
append(walls, new Wall(6*gameWidth/wallSize,5*gameHeight/wallSize,3*gameWidth/wallSize,wallSize));
}
function setup() {
createCanvas(gameWidth, gameHeight + 100);
initFirebase();
makeBasicMap();
possibleSpawns = spawns;
Object.keys(players).forEach((key) => {
players[key].score=0;
});
}
function draw() {
background(200);
//not enough players
if(Object.keys(players).length <= 1){
//roundOver = true;
notEnoughUsers = true;
}else{
notEnoughUsers = false;
}
//round beginning
if(roundBeginning){
startTimer++
noStroke();
fill(255,0,0);
textSize(30);
if(startTimer <= 50){
text("3",gameWidth/2,gameHeight/2);
}else if(startTimer <= 100){
text("2",gameWidth/2,gameHeight/2);
}else if(startTimer <= 150){
text("1",gameWidth/2,gameHeight/2);
}else{
text("GO",gameWidth/2,gameHeight/2);
roundBeginning = false;
}
}
//not enough players
if(notEnoughUsers){
renderWait();
}
//enough players and in round
if(!roundOver && !notEnoughUsers){
game();
}
//enough players and round over]
if(roundOver && !notEnoughUsers){
restartGame();
}
}
function renderWait(){
textSize(20);
noStroke();
fill(255,0,0);
textAlign(CENTER)
text("find some friends :(",width/2 + random(-0.9,0.9),height/2+ random(-0.9,0.9));
}
function game(){
//move the user's player if alive and round started
if(players[userId].alive && !roundBeginning){
movePlayer();
}
//one in 50 chance to place item each frame (items not spawning since -1)
if(floor(random(0,10000)) == -1){
console.log("Item Placed")
placeItem();
}
//loops through each player to render them
Object.keys(items).forEach((key) => {
const itemState = items[key];
renderItem(itemState);
});
//loops through each player to render them
let usersAlive = 0;
Object.keys(players).forEach((key) => {
const characterState = players[key];
//if player is alive
if(characterState.alive){
usersAlive ++;
renderPlayer(characterState);
checkBulletPlayer(key);
}
});
//loops through each bullet to ?update? and render them
Object.keys(bullets).forEach((key) =>{
const bulletState = bullets[key];
if(bulletState.alive){
updateBullet(bulletState,key);
renderBullet(bulletState);
}
})
//render walls
for(const wall of walls){
wall.render();
}
//render the scores
renderScores();
//check if there is less than one user alive, more than one user, and no bullets left. Restart the game
if(usersAlive <= 1){
noShoot = true;
}
if(usersAlive <= 1 && Object.keys(bullets).length == 0){
//check how many players are logged on
roundOver = true;
}
}
function renderScores(){
const playerNumber = Object.keys(players).length;
const w = width/(playerNumber+1);
let i = 1;
//for each player
Object.keys(players).forEach((key) => {
let j = 0;
if(i % 2 == 0 && playerNumber > 2){
j = 15;
}
noStroke();
fill(players[key].color);
textSize(12);
textAlign(CENTER)
text(players[key].name,i*w,height-70 - j);
textSize(25);
text(players[key].score,i*w,height-15);
stroke(0);
fill(players[key].color);
rect(i*w,height-60,tankWidth,tankHeight);
i++;
});
}
//function to generate random keys for bullets
function create_random_generator(string_length){
var random_string = ''
var char = 'abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ'
var i
for(i = 0; i < string_length; i++){
random_string = random_string + char.charAt(Math.floor(Math.random()* char.length))
}
return random_string
}
function getKeyString(x, y) {
return `${x}x${y}`;
}
//attempt to pick up an item
function attemptItemPick(x,y){
//create the potential key for the item based on player position
const key = getKeyString(floor(x),floor(y));
if(items[key]){
//if item with such string exists, remove it
firebase.database().ref(`items/${key}`).remove();
}
}
//function to randomly place items
function placeItem(){
const x = round(random(gameWidth));
const y = round(random(gameHeight));
//generate key based on x and y position
const itemRef = firebase.database().ref(`items/${getKeyString(x,y)}`);
//set x and y values for item in firebase
itemRef.set({
x,
y,
})
}
//render la item
function renderItem(item){
const x = item.x;
const y = item.y;
const size = 20;
noStroke();
fill(0);
rect(x-size/2,y-size/2,size,size);
fill(255,0,0);
circle(x,y,10)
}
//update bullets
function updateBullet(bullet,key){
bullet.lifeTime ++;
let newX = bulletSpeed * cos(bullet.heading);
let newY = bulletSpeed * sin(bullet.heading);
const newPosX = bullet.x + newX;
const newPosY = bullet.y + newY;
const dif = checkWallHit(newPosX,newPosY)
if(dif != 0){
bullet.heading = dif - bullet.heading;
}
bullet.x += newX;
bullet.y += newY;
//if bullet hits life max, delete it, Otherwise update it
if(bullet.lifeTime >= bulletLifeTimeMax){
bullet.alive = false;
firebase.database().ref(`bullets/${key}`).remove();
}else{
const bulletRef = firebase.database().ref(`bullets/${key}`);
bulletRef.set(bullet);
}
}
//check if bullets hit a wall
function checkWallHit(x,y){
for(const wall of walls){
if(checkWithinBorder(x,y,wall.origin.x,wall.origin.y,wall.width,wall.height)){
//if above or below, return 2 PI. If left or right, return PI
//hit side
if(y - bulletSize >= wall.origin.y && y + bulletSize <= wall.origin.y + wall.height){
return PI
}
//hit top or bot
else{
return 2 * PI
}
}
}
return 0;
}
//check if (x,y) is within a rect
function checkWithinBorder(x,y,bx,by,bw,bh){
//check if within the rect
if(x >= bx && x <= bx + bw && y >= by && y < by + bh){
return true
}else{
return false
}
}
//check if tank has hit a bullet
function checkBulletPlayer(userKey){
Object.keys(bullets).forEach((key) =>{
const bulletX = bullets[key].x;
const bulletY = bullets[key].y;
const bx = players[userKey].x - tankWidth/2;
const by = players[userKey].y - tankHeight/2;
if(checkWithinBorder(bulletX,bulletY,bx,by,tankWidth,tankHeight) && bullets[key].alive){
players[userKey].alive = false;
const playerRef = firebase.database().ref(`players/${userKey}`);
playerRef.set(players[userKey]);
return;
}
});
}
//draw bullets
function renderBullet(bullet){
//console.log(bullet);
const x = bullet.x;
const y = bullet.y;
noStroke();
fill(0);
circle(x,y,bulletSize);
}
//shoot from the player
function keyPressed() {
//if spaced is pressed and not too many bullets and player is alive and more than one player
if(keyIsDown(32)){
const heading = players[userId].heading;
const x = players[userId].x + barrelWidth * cos(heading);
const y = players[userId].y + barrelWidth * sin(heading);
//create a bullet with a random key
const bulletRef = firebase.database().ref(`bullets/${create_random_generator(40)}`);
bulletRef.set({
x,
y,
heading,
lifeTime: 0,
alive: true,
})
}
}
//move the player
function movePlayer(){
const speed = 2;
const rotationSpeed = 0.1;
let newPosition = createVector(0,0);
let newAngle = 0;
let a = 0;
// a - rotate the player counter clockwise
if(keyIsDown(65)){
newAngle -= rotationSpeed;
}
// d - rotate the player clockwise
if(keyIsDown(68)){
newAngle += rotationSpeed;
}
// w - move forward
if(keyIsDown(87)){
//console.log("Moving Forward")
newPosition.x = speed * cos(players[userId].heading);
newPosition.y = speed * sin(players[userId].heading);
}
// s - move backward
if(keyIsDown(83)){
newPosition.x = - speed * cos(players[userId].heading);
newPosition.y = - speed * sin(players[userId].heading);
}
if(newPosition.x != 0 || newPosition.y !=0 || newAngle != 0){
//check if new position is within a wall
if(!checkPlayerWall(newPosition.x + players[userId].x - tankWidth/2,newPosition.y + players[userId].y - tankHeight/2)){
players[userId].x += newPosition.x;
players[userId].y += newPosition.y;
players[userId].heading += newAngle;
userRef.set(players[userId]);
}
//pick up items -- !!!!super duper hard to pick up items
attemptItemPick(players[userId].x,players[userId].y)
}
}
//check if the players new position is in a wall
function checkPlayerWall(x,y){
for(let wall of walls){
//rect-rect intersection
if (x + tankWidth >= wall.origin.x && x <= wall.origin.x + wall.width && y + tankHeight >= wall.origin.y && y <= wall.origin.y + wall.height) {
return true;
}
}
return false;
}
//draw players
function renderPlayer(player){
let clr = player.color;
let x = player.x;
let y = player.y;
let a = player.heading;
//body background
push();
translate(x,y);
noStroke();
if(roundBeginning){
noStroke();
textSize(12);
fill(clr);
textAlign(CENTER);
text(player.name,-40,40)
}
rotate(a);
noStroke();
fill(clr);
rect(-tankWidth/2,-tankHeight/2,tankWidth,tankHeight);
//top tred
stroke(100);
fill(100,90);
rect(-tankWidth/2,-tankHeight/2,tankWidth,tankHeight/4);
//bot tred
rect(-tankWidth/2,tankHeight/4,tankWidth,tankHeight/4);
//body outline
noFill();
stroke(0);
rect(-tankWidth/2,-tankHeight/2,tankWidth,tankHeight);
//barrel
const barrelHeight = 5;
stroke(0);
fill(clr);
rect(0,-barrelHeight/2,barrelWidth,barrelHeight);
//circle on top of body
const topSize = 12;
stroke(0);
fill(clr);
circle(0,0,topSize);
pop();
}
//generate name for player
function createName(){
const title = random(["MR.","MS.","DR.","SIR","GOD FEARING AMERICAN","KING","QUEEN"]);
const prefix = random(["SOFT", "DOPE", "DANK", "MASTER", "LARD", "LOVE", "CRAZY","FEARING" , "DODGING" , "GREEDY", "LEO","ELLIOTT"]);
const suffix = random(["STONER", "BEAR", "GOAT", "TRUMP", "SEAL", "SKYHAMMER", "76","GRUNCKEL", "MONKEY MAN", "VINSON", "RUDY"]);
return `${title} ${prefix} ${suffix}`
}
function zeroScore(){
Object.keys(players).forEach((key) => {
const characterState = players[key];
characterState.score = 0;
const playerRef = firebase.database().ref(`players/${key}`);
playerRef.set(players[key]);
});
}
//init game
function initGame(){
//read all the players
const allPlayersRef = firebase.database().ref(`players`);
const allItemsRef = firebase.database().ref(`items`);
const allBulletsRef = firebase.database().ref(`bullets`);
allPlayersRef.on("value", (snapshot) => {
//fires whenever a change occurs
players = snapshot.val() || {};
});
allPlayersRef.on("child_added", (snapshot) =>{
//fires whenever a new node is added
const addedPlayer = snapshot.val();
renderPlayer(addedPlayer);
restartGame();
});
allItemsRef.on("child_added", (snapshot) =>{
//triggers when item is spawned
//get the value of the item
const item = snapshot.val();
//get the key of the item
const itemKey = snapshot.getKey();
//store the item under its key in the items object
items[itemKey] = item;
})
allItemsRef.on("child_removed", (snapshot) =>{
//fires when an item is removed
const keyToRemove = snapshot.getKey();
delete items[keyToRemove];
})
// allBulletsRef.on("value", (snapshot) =>{
// bullets = snapshot.val() || {};
// });
allBulletsRef.on("child_added", (snapshot) => {
//triggers when a bullet is added
const bullet = snapshot.val();
//get the key of the item
const bulletKey = snapshot.getKey();
//store the item under its key in the items object
bullets[bulletKey] = bullet;
});
allBulletsRef.on("child_removed", (snapshot) => {
const keyToRemove = snapshot.getKey();
delete bullets[keyToRemove];
})
}
//init fire base
function initFirebase(){
let playerId;
let playerRef;
//prevent from logging in twice ISSUE PREVENTS LOG OUT
var authFlag = true;
firebase.auth().onAuthStateChanged((user) => {
if(authFlag){
authFlag = false
console.log(user)
if(user){
//logged in!
//get unique player id
playerId = user.uid;
//open player node
playerRef = firebase.database().ref(`players/${playerId}`);
userId = playerId;
userRef = playerRef;
// create
const name = createName();
const pos = possibleSpawns[floor(random(possibleSpawns.length))];
//data being saved to firebase
playerRef.set({
id: playerId,
name,
alive: true,
color: random(playerColors),
x: pos[0],
y: pos[1],
heading: 0,
powerup: 0,
score: 0
});
//init the game
initGame();
}else{
//didn't log in
}
}
//remove player from firebaes when leaving
playerRef.onDisconnect().remove();
})
firebase.auth().signInAnonymously().catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode,errorMessage);
});
}