Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next
/* Dude Vs ball by JohnLee Cooper.
 This is a two player game, with one player controlling a ball with the mouse,
 and another controller the dude (square) with the arrow keys. The ball can be slung by
 clicking and dragging with the mouse. The dude can run left and right, and jump. 
 When the dude goes off of one side, he returns on the other. he can also wall jump 
 by pressing away from the side of the screen he's touching. The two players must avoid the
 deadly blue diamond, or knock each other into it. */

//---------------------------------------
//GLOBAL CONSTANTS:
//---------------------------------------

//background square size:
float backgroundSize = 50;
//the message to display 
//used for an initial instruction thing and listing who died
String words = "Control the square with the arrow keys, and the ball with the mouse.";
//the opacity of the message
//imma fade it over time.
float alpha = 255;

//dude constants:

float dudeGrav = .5;
//how much power the jump has
float dudeJump=10; 
float maxDudeSpeed=10;

//half the size of the dudes torso, the distance from his collision place to his sides.
float squareSize = 15; //so, he's 30 wide, 30 tall.

//ball constants:

float ballGrav = .4;
//balls can't move faster than ballMaxSpeed pixels per frame
float ballMaxSpeed = 10; 
//the width and height of the ball
float ballSize = 30; 
//I'm going to use box collision for the ball cause circles are hard:
float ballWall = ballSize*.4;

//diamond constants:

//the distance between each point of the diamond
float diamondSize = 15;


//---------------------------------------
//GLOBAL VARIABLES:
//---------------------------------------
//tracks the win condition. when someone loses, it records who and resets variables
String ended = "none"; 
//whether or not to increase the above ball speed things
boolean ballClicked = false;
//dude starts 1/4th through the screen, on the ground.
float dudeX = 100;
float dudeY = 400;
float dudeSpeedX = 0;
float dudeSpeedY = 0;

//the ball starts more'n 3/4ths through the screen
float ballX = 300; 
float ballY = 350;

float ballSpeedX = 0;
float ballSpeedY = 0;

//these are used to determine the power to launch with:
//essentially, a line is drawn between the first two and the length of that line is the power.
float launchX = 0;
float launchY = 0;
float tempSpeedX = 0;
float tempSpeedY = 0;

//diamond variables:

//diamond speed is randomly set
float diamondSpeedX=random(-3, 4);
float diamondSpeedY=random(-3, 4);
//diamond points, diamond starts in the dead centre.
float diamondX1=200;
float diamondY1=200-diamondSize;
float diamondX2=diamondX1-diamondSize;
float diamondY2=diamondY1+diamondSize;
float diamondX3=diamondX1;
float diamondY3=diamondY1+diamondSize*2;
float diamondX4=diamondX1+diamondSize;
float diamondY4=diamondY1+diamondSize;


//functions:
//the longer the player is alive, the higher this number gets.
void timer() {
} 

void squaresAnimation() {
  //this function alone would like corner mode
  rectMode(CORNER);
  //give these bois white outlines
  stroke(255, 255, 255);
  for (int x=0; x<width; x+=backgroundSize) {
    for (int y=0; y<height; y+=backgroundSize) {//times 2 cause resolutions are weird
      //the color depends on how far away the square is from the dude, diamond  and ball.
      //it compares the centre of the background squares to the centre of the ball and dude.
      //the closer to the dude, the more red
      float red = 150 -abs(x+(backgroundSize/2)-dudeX) -abs(y+(backgroundSize/2)-dudeY+squareSize/2);
      //the closer to the ball, the more green.
      float green = 150 - abs(x+(backgroundSize/2)-ballX) -abs(y+(backgroundSize/2)-ballY);
      //the closer to the diamond, the more blue.
      float blue = 150 - abs(x+(backgroundSize/2)-diamondX1) -abs(y+(backgroundSize/2)-diamondY2);
      fill(red, green, blue);

      rect(x, y, backgroundSize, backgroundSize*2);//times 2 cause resolutions are weird
    }
  }
  //gotta change that back
  rectMode(CORNERS);
  noStroke();
}

void ballCollide(float ballBottom, float ballTop, float ballRight, float ballLeft) {
  //if the bottomish of the circle is above the floor, you fall.
  if (ballBottom < height) {
    ballSpeedY+=ballGrav;
  }

  //the bounce formula is just divide speed by two and reverse
  else {
    //this is to make SURE they stay in bounds, by at first setting it at the length of it's hitbox away from the wall 
    ballY=height-ballWall;
    ballSpeedY=-ballSpeedY;
  }
  if (ballTop<0) {
    //this is to make SURE they stay in bounds, by at first setting it at the length of it's hitbox away from the wall 
    ballY=0+ballWall;
    ballSpeedY=-ballSpeedY;
  }
  if (ballRight>width) {
    //this is to make SURE they stay in bounds, by at first setting it at the length of it's hitbox away from the wall 
    ballX=width-ballWall;
    ballSpeedX=-ballSpeedX;
  }
  if (ballLeft<0) {
    //this is to make SURE they stay in bounds, by at first setting it at the length of it's hitbox away from the wall 
    ballX=0+ballWall;
    ballSpeedX=-ballSpeedX;
  }
}
void ballClick(float ballBottom, float ballTop, float ballRight, float ballLeft) {
  // when you click:
  if (mousePressed) {
    //when mouse is pressed, set the start of drag coords and toggle the boolean about it.
    if (!ballClicked) { //only does this if when mouse is first pressed.
      launchX=mouseX;
      launchY=mouseY;
      ballClicked = true;
    }
    //does the rest of this the whole time.
    int launchFract = 8;
    tempSpeedX = (launchX-mouseX)/launchFract;
    tempSpeedY = (launchY-mouseY)/launchFract;

    //draw a white line between the point you started dragging and the current point:
    stroke(255);
    line(mouseX, mouseY, launchX, launchY);
    noStroke();
  }
  //when you let go:
  else if (ballClicked) { 
    //reset the drag numbers and bool, and apply the speeds.
    ballClicked = false;
    ballSpeedX+=tempSpeedX;
    ballSpeedY+=tempSpeedY;
    tempSpeedX=0;
    tempSpeedY=0;
    launchX=0;
    launchY=0;
  }
}
void ballLimit(float ballBottom, float ballTop, float ballRight, float ballLeft) {
  //let's limit just how fast the ball can move ever:
  if (ballSpeedX>ballMaxSpeed) {
    ballSpeedX=ballMaxSpeed;
  }
  if (ballSpeedX<-ballMaxSpeed) {
    ballSpeedX=-ballMaxSpeed;
  }
  if (ballSpeedY>ballMaxSpeed) {
    ballSpeedY=ballMaxSpeed;
  }    
  if (ballSpeedY<-ballMaxSpeed) {
    ballSpeedY=-ballMaxSpeed;
  }
}

void ballMove() {

  float ballBottom = ballY+ballWall;
  float ballTop = ballY-ballWall;
  float ballRight = ballX+ballWall;
  float ballLeft = ballX-ballWall;
  //determines how the ball falls over time and bounces off walls
  ballCollide(ballBottom, ballTop, ballRight, ballLeft);
  //controls the ball launching mechanic.
  ballClick(ballBottom, ballTop, ballRight, ballLeft);
  //makes sure the ball doesn't go too fast
  ballLimit(ballBottom, ballTop, ballRight, ballLeft);

  //actually move the ball:
  ballX+=ballSpeedX;
  ballY+=ballSpeedY;
}




void dudeLimit() {
  //this function limits dude's speed to his max speeds.
  if (dudeSpeedX>maxDudeSpeed) {
    dudeSpeedX=maxDudeSpeed;
  }
  if (dudeSpeedX<-maxDudeSpeed) {
    dudeSpeedX=-maxDudeSpeed;
  }
  if (dudeSpeedY>maxDudeSpeed) {
    dudeSpeedY=maxDudeSpeed;
  }
  if (dudeSpeedY<-maxDudeSpeed) {
    dudeSpeedY=-maxDudeSpeed;
  }
}
void dudeStop() {
  //dude, STOP

  //if neither left or right are being pressed, slow down to 0
  dudeSpeedX=dudeSpeedX/1.5;
}
char dudeLeftRight() {
  //returns r if player is pressing right, l if they press left
  //n if they press neither.
  char dir = 'n';
  if (keyPressed) {
    if (key == CODED) {
      if (keyCode == LEFT) {
        dir='l';
      } else if (keyCode == RIGHT) {
        dir='r';
      }
    }
  }
  return dir;
}
void verticalMove() {
  //if you press when up when on the ground, you jump
  if (dudeY==height) {
    if (keyPressed) {
      if (key == CODED) {
        if (keyCode == UP) {
          jump();
        }
      }
    }
  } else {
    dudeSpeedY+=dudeGrav;
  }
}
void dudeWalls() {
  //when the dude hits a wall, he can either screenwrap or jump backwards
  if (dudeY>height) {
    //if you hit the floor, stop falling and set bottom to floor.
    dudeSpeedY=0;
    dudeY=height;
  }
  if (dudeY<0) {
    dudeSpeedY=0;
    dudeY=0;
  }
  if (dudeX>width) {

    if (dudeLeftRight() == 'l') {
      //jump and reverse direction
      jump();
      dudeSpeedX=(-dudeSpeedX/2) -5;
    }

    //otherwise, warp to other side  
    else {
      //plus 6 so as not to insta wall jump
      dudeX=6;
    }
  }
  //let's give a little extra lee way for wall jumps:
  //if the box is slightly over the side, you can still jump
  else if (dudeX+5>width) { 
    if (dudeLeftRight() == 'l') {
      //jump and reverse direction
      jump();
      dudeSpeedX=(-dudeSpeedX/2) -5;
    }
  }
  if (dudeX<0) {

    if (dudeLeftRight() == 'r') {
      //jump and reverse direction
      jump();
      dudeSpeedX=(-dudeSpeedX/2) +5;
    }
    //otherwise warp to other side
    else {
      //minus six so as not to immediately wall jump.
      dudeX=width-6;
    }
  } else if (dudeX-5<0) {
    //let's give a little extra lee way for wall jumps:
    //if the box is slightly over the side, you can still jump
    if (dudeLeftRight() == 'r') {
      //jump and reverse direction
      jump();
      //this formula flips the speed
      //then it adds a little more push so you can't have 0 speed out of this (caused problems)
      dudeSpeedX=(-dudeSpeedX/2) +5;
    }
  }
}
void horizontalMove() {
  //determine the direction currently being pressed
  char dir = dudeLeftRight();

  if (dir=='r') {
    //if right, start accelerating right.
    dudeSpeedX++;
  }
  if (dir=='l') {
    //if left, accel left
    dudeSpeedX--;
  }
  if (dir=='n') {
    //if neither is pressed, and you're on the ground, slow down.
    if (dudeY==height) {
      dudeSpeedX/=1.1;
    }
  }
}

void dudeMove() {
  //general movement function

  //accels left if left is pressed, right if right, slows if neither.
  horizontalMove();
  //applies jump if up is pressed and youse on the floor
  //otherwise apply gravity
  verticalMove();

  //boundaries, screenwrapping, walljumping
  dudeWalls();
  //limiting the guy's speed
  dudeLimit();
  //actually move the dude:
  dudeX+=dudeSpeedX;
  dudeY+=dudeSpeedY;
}

void jump() {
  //apply the jump force
  dudeSpeedY-=dudeJump;
}


void bounceCollide() {
  //when the ball and dude overlap, they exchange speeds
  //this a really silly way of doing this. But I've been trying to get real collision for hours and it isn't worth the time.
  //basically, if the centre of dude is in the collision of ball:
  if (dudeX==constrain(dudeX, (ballX-ballWall), (ballX+ballWall))) {
    if ((dudeY-squareSize*2)==constrain((dudeY-squareSize*2), (ballY-ballWall), (ballY+ballWall))) {
      //exchange the x speeds
      float swapper=dudeSpeedX;
      dudeSpeedX=ballSpeedX;
      //this exception is for if the dude is just sitting on the floor.
      //other wise they get stuck together
      if (swapper==0) {
        ballSpeedX=-ballSpeedX;
      } else {
        ballSpeedX=swapper;
      }
      //exchange the y speeds
      swapper=dudeSpeedY;
      dudeSpeedY=ballSpeedY;
      //this exception is for if the dude is just sitting on the floor.
      //otherwise they get stuck together
      if (swapper==0) {
        ballSpeedY=-ballSpeedY;
      } else {
        ballSpeedY=swapper;
      }
    }
  }
}
void diamondCollide() {
  //if the top tip hits the top or the bottom hits the bottom:
  if (diamondY1<0 || diamondY3>height) {
    //push it back so it doesnt collide,
    //just a quick fix for some glitchiness in the corners
    diamondY1-=diamondSpeedY;
    //reverse vertical speed
    diamondSpeedY=-diamondSpeedY;
    //randomize horizontal speed
    diamondSpeedX= random(-3, 4);
  }
  //if the left point hits the left, or the right the right side:
  if (diamondX2<0 || diamondX4>width) {
    //push it back so it doesnt collide,
    //just a quick fix for some glitchiness in the corners
    diamondX1-=diamondSpeedX;
    //reverse horizontal speed
    diamondSpeedX=-diamondSpeedX;
    //randomize vertical speed
    diamondSpeedY= random(-3, 4);
  }
}
void diamondMove() {
  //when the diamond hits walls:
  diamondCollide();
  //actually move the diamond:
  diamondX1+=diamondSpeedX;
  diamondY1+=diamondSpeedY;
}
void killBall(float pointX, float pointY) {
  //if the point is in the ball, the ball loses
  if (pointX==constrain(pointX, (ballX-ballWall), (ballX+ballWall))) {
    if (pointY==constrain(pointY, (ballY-ballWall), (ballY+ballWall))) {
      ended="ball";
    }
  }
}
void killDude(float pointX, float pointY) {
  //if the point is in the ball, the ball loses
  if (pointX==constrain(pointX, (dudeX-squareSize), (dudeX+squareSize))) {
    if (pointY==constrain(pointY, (dudeY-squareSize*2), dudeY)) {
      ended="dude";
    }
  }
}

void dudeDraw() {
  //draws a little rectangle, with little rectangle legs
  fill(255, 0, 0); //red
  //these variables are to get the corners of the rect 
  //based on the bottom centre, which is the anchor
  float top = dudeY-squareSize*2; 
  float bottom = dudeY; 
  float left = dudeX-squareSize;
  float right = dudeX+squareSize;
  rect(left, top, right, bottom);
}

void ballDraw() {
  //draws a green circle. wooo
  fill(0, 255, 0);
  ellipse(ballX, ballY, ballSize, ballSize);
  //  stroke(255); //these can be turned on if I want to see the ball's hitbox.
  //  rect(ballX-ballWall, ballY-ballWall, ballX+ballWall, ballY+ballWall);
  //  noStroke();
}

void diamondDraw() {
  //diamond is blue
  fill(0, 0, 255);
  //lots a coords
  diamondX2=diamondX1-diamondSize;
  diamondY2=diamondY1+diamondSize;
  diamondX3=diamondX1;
  diamondY3=diamondY1+diamondSize*2;
  diamondX4=diamondX1+diamondSize;
  diamondY4=diamondY1+diamondSize;
  quad(diamondX1, diamondY1, diamondX2, diamondY2, diamondX3, diamondY3, diamondX4, diamondY4); //diamond no longer looks like a word
}

//imforms cube of their loss, resets all the variables to their initial things.
void reset() {
  //display kill stuff
  words = ended+" is kill!";
  alpha = 255; 
  //reset the end trigger.
  ended = "none";
  //the rest of this is the same as the top.

  //whether or not to increase the above ball speed things
  ballClicked = false;
  //dude starts 1/4th through the screen, on the ground.
  dudeX = 100;
  dudeY = 400;
  dudeSpeedX = 0;
  dudeSpeedY = 0;

  //the ball starts more than 3/4ths through the screen
  ballX = 300; 
  ballY = 350;

  ballSpeedX = 0;
  ballSpeedY = 0;

  //these are used to determine the power to launch with:
  //essentially, a line is drawn between the first two and the length of that line is the power.
  launchX = 0;
  launchY = 0;
  tempSpeedX = 0;
  tempSpeedY = 0;

  //diamond variables:

  //diamond speed is randomly set
  diamondSpeedX=random(-3, 4);
  diamondSpeedY=random(-3, 4);
  //diamond points, diamond starts in the dead centre.
  diamondX1=200;
  diamondY1=200-diamondSize;
  diamondX2=diamondX1-diamondSize;
  diamondY2=diamondY1+diamondSize;
  diamondX3=diamondX1;
  diamondY3=diamondY1+diamondSize*2;
  diamondX4=diamondX1+diamondSize;
  diamondY4=diamondY1+diamondSize;
}
void displayText() {
  fill(255, 255, 255, alpha); 
  text(words, 0, 0, width, height);
  if (alpha>0) {
    alpha--;
  }
}
void setup() {
  size(400, 400);
  noStroke();
  rectMode(CORNERS);
  textSize(40);
  textAlign(CENTER);
}

void draw() {

  background(0);
  //draw the background squares
  squaresAnimation();

  //UPDATES:
  ballMove();
  dudeMove();
  diamondMove();
  //for the interaction between ball and dude
  bounceCollide();
  //for their interaction with diamond
  //test each diamond point with each to see if anyone dies
  killDude(diamondX1, diamondY1);
  killBall(diamondX1, diamondY1);
  killDude(diamondX2, diamondY2);
  killBall(diamondX2, diamondY2);
  killDude(diamondX3, diamondY3);
  killBall(diamondX3, diamondY3);
  killDude(diamondX4, diamondY4);
  killBall(diamondX4, diamondY4);
  //DRAW:
  dudeDraw();
  ballDraw();
  diamondDraw();
  //display text:
  displayText();
  //set the things in the first place
  if (ended != "none") {
    reset();
  }
}