Code viewer for World: University Bird v2.0 MULTI...
// UNIVERSITY BIRD IS ADAPTED FROM P5JS.ORG & MODIFIED TO INCLUDE TWO BIRDS AND SOCKETS
// SKINED TO THEME OF DUBLIN CITY UNIVERSITY
// BY COLM MCCARTHY & NIALL QUIGLEY 
// DECEMBER 2022



// Start Sockets
AB.socketStart();

let pipes = [];
let player1;
let player2;
let playing = false;

let birdImg, pipeImg, pipeRevImg, backgroundImg;

// Loading images
function preload() {
  birdImg = loadImage('uploads/quigln24/bird.png');
  birdImg2 = loadImage('uploads/quigln24/bird2.png');
  pipeImg = loadImage('uploads/quigln24/pipes.png');
  pipeRevImg = loadImage('uploads/quigln24/pipes_reverse.png');
  backgroundImg = loadImage('uploads/quigln24/background.png');
}


//Initatial setup, creating canvas, setting up two birds
function setup() {
  createCanvas(400, 600);
  frameRate(40);
  player1 = new Bird(width/3, height / 3);
  player1.flap();
  player2= new Bird(width/3, height / 3);
  player2.flap();
  player2.isTwo = true;
  angleMode(DEGREES);
  textAlign(CENTER, CENTER);
  textStyle(BOLD);
  textSize(50);
}


// Logic for drawing pipes 
function draw() {
  background(backgroundImg);
  if (frameCount % 50 == 0) {
    pipes.push(new Pipe());
    playing = true;
  }

  for (let i = pipes.length - 1; i >= 0; i--) {
    pipes[i].show();
    pipes[i].update();
    //get rid of them pipes
    if (pipes[i].offScreen()) {
      if (pipes[i].pass(player1)&& player1.isAlive) {
        player1.score++;
      }
      pipes.splice(i, 1);
    }
    //endgame
    if (pipes[i].hit(player1)) {
      AB.socketOut(player1.score);
      AB.socketOut(player1.isAlive);
      
      player1.isAlive = false;
    }
    if (!player1.isAlive && !player2.isAlive){
      strokeWeight(4);
      rectMode(CENTER);
      fill(241, 122, 60);
      rect(width / 2, height / 2, width - 80, 80);
      fill(255);
      text(player1.score, ((width / 2) - 80), height / 2);
      text("vs", width / 2, height / 2);
      text(player2.score, ((width / 2) + 80), height / 2);
      let title = "Final Score:"
      text(title, width / 2, ((height / 2) -70));
      playing = false;
      noLoop();
    }

  }
  // draw player 1 & 2
  player1.show();
  player1.update();
  player2.show();
  player2.update();
  // show the current score
  if (playing) {
    text(player1.score, width / 2, height / 5);
  }

}

// Control local player (send out your player1 signal and receive as player 2 on other client)
function keyPressed() {
  if (key == ' ') {
    player1.flap();
    AB.socketOut("flap");
  }
}

//Same thing as above but support for mouse
function mousePressed(){
  // click inside the canvas
  if(player1.isAlive){
      if(mouseX > 0 && mouseX < width &&
         mouseY > 0 && mouseY < height) {
        player1.flap();
        AB.socketOut("flap");
      }
  }
}


function drawLine() {
  let step = 100;
  stroke(1);
  for (let i = 0; i < height / step; i++) {
    line(0, i * step, width, i * step)
  }
}


// --------------------- PIPE --------------------------- //


class Pipe {
  constructor() {
    this.x = width;
    this.w = 90;
    this.gap = 120;
    this.min_height = 100;
    this.max_height = height - this.min_height - this.gap;
    this.top = floor(random(this.min_height, this.max_height));
    this.speed = 5;
  }

  show() {
    fill(255, 0, 0);
    /* top pipe */
    // rect(this.x, 0, this.w, this.top);
    image(pipeRevImg, this.x, 0, this.w, this.top);
    /* bottom pipe */
    fill(0, 255, 0);
    let height_b = height - this.gap - this.top;
    let y_b = height - height_b;
    // rect(this.x, y_b, this.w, height_b);
    image(pipeImg, this.x, y_b, this.w, height_b);
  }

  offScreen() {
    if (this.x + this.w + this.speed < 0) {
      return true;
    }
    return false;
  }

  hit(player1) {
    if (player1.x > this.x && player1.x < this.x + this.w) {
      if (player1.y < this.top ||
        player1.y > this.top + this.gap) {
        return true;
      }
    }
    return false;
  }

  pass(player1) {
    if (player1.x > this.x + this.w) {
      return true;
    }
    return false;
  }

  update() {
    this.x -= this.speed;
  }
}

// ------------------------------ BIRD ---------------------

//Adding isAlive Helps us disable controls without ending game and wait for other player
//Adding isTwo (player 2 is the connection from socket) & to set different bird texture

class Bird {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.r = 50;
    this.gravity = 2;
    this.velocity = 0;
    this.lift = -30;
    this.isTwo = false;
    this.isAlive = true;
    this.friction = 0.1;
    this.score = 0;
    this.up = false;
  }

  show() {
    fill(255);
    push();
    imageMode(CENTER);
    translate(this.x, this.y);
    if (this.up || this.velocity < 0) {
      rotate(-35);
    } else {
      rotate(35);
    }
    // ellipse(this.x, this.y, this.r);
    if(this.isTwo){
        image(birdImg2, 0, 0, this.r, this.r);
    }else{
        image(birdImg, 0, 0, this.r, this.r);
    }
    pop();
  }

  update() {
    this.velocity += this.gravity;
    this.velocity = constrain(this.velocity, -25, 25);
    this.y += this.velocity;
    if (this.y > height) {
      this.velocity = 0;
      this.y = height;
    } else if (this.y < 0) {
      this.velocity = 0;
      this.y = 0;
    }
    this.up = false;
  }

  flap() {
    this.velocity += this.lift;
    this.velocity *= (1 - this.friction);
    this.up = true;
  }
}

//MATE ITS 4:30 AM AND THE SOCKETS WONT F*CKING WORK and were overdue 4 hours :)
// they work now :)
function updatePlayer(flap2){
       player2.flap();
}
function updateScore(score2){
       player2.score = score2;
       console.log(player2.score);
}
AB.socketIn = function(n){
    if ( ! AB.runReady ) return;
    if (n == "flap"){
        updatePlayer(n);
    }
    else if(Number.isInteger(n)){
        updateScore(n);
    }
    else{
        player2.isAlive = false;
    }
}


//