0

I have to create a game for my final project. The concept of the game is to move the square around and reach the white circle while avoiding the black circles. I was able to create a "Game Over" screen when the square touches the black circles, however, when I use the same logic for the white square it doesn't work. It works occasionally, when the square is in a certain position but the black circles are on top of the text.

My second question is, that I want to have a Title Screen that only runs in the beginning. I want the title screen to go away once the letter P is pressed on the keyboard. When I tried putting the "title screen" in the setup function, the game doesn't run. If I put the "title screen" in draw, it runs every time (I understand why though). I'm not skilled enough to write my own functions for the title screen either.

My main concern is the "You Won" screen though. If creating the "title screen" is too complex I don't need to add that in.

Here is my code: https://editor.p5js.org/pawlisko/sketches/WClx1upD-

var player; 
var goals = [];
var enemies = [];

function setup() {
  createCanvas(400, 400);
  noStroke();
  for(let i=0;i<150;i++) {
        enemies.push(new Enemy());
  }
  for(let i=0;i<1;i++) {
        goals.push(new Goal());
  }

  player = {};
  player.x = 350;
  player.y = 10;
  player.w = 10;
  player.h = 10;
}

function draw() {
  background(0);

//start screen
  fill(227, 101, 91);
  textSize(50);
  textAlign(CENTER);
  text("Circle Maze",200, 200);
  textSize(12);
  textAlign(CENTER);
  text("Press 'P' to play.",200, 250);
//text
  text("Goal: Reach the gold square. Don't touch black circles.", 200, 290);
  text("Use keys 'W, A, S, D' to move. Refresh page to play again.", 200, 330);

if(key == 'p'){
  background(227, 101, 91);

//player
  fill(255,183,173);
  rect(player.x, player.y, player.w, player.h);

//goal
   for(let i=0;i<goals.length;i++) {
        goals[i].show();
     var end = goals[i];

//game won
     for(let g of goals) {
      d = dist(player.x, player.y, g.x, g.y);
      if(d<player.w && player.h + g.r) {
        fill(0);
        rect(0,0,400,400);
        fill(227, 101, 91);
        textSize(50);
        textAlign(CENTER);
        text("You Win",200, 200);
        textSize(12);
        textAlign(CENTER);
        text("Press 'R' to play again.",200, 250);
        }
      }
    }


//enemies
   for(let i=0;i<enemies.length;i++) {
        enemies[i].show();
     var end2 = enemies[i];

//game over
     for(let e of enemies) {
      d = dist(player.x, player.y, e.x, e.y);
      if(d<player.w && player.h + e.x) {
        fill(0);
        rect(0,0,400,400);
        fill(227, 101, 91);
        textSize(50);
        textAlign(CENTER);
        text("Game Over",200, 200);
        textSize(12);
        textAlign(CENTER);
        text("Press 'R' to play again.",200, 250);
        }
      }
    }
  }
}

function keyTyped () {
  //Moving character
    if(key === 'w') {
    player.y -= 10;
    direction = 0;
    }
    else if(key === 's') {
    player.y += 10;
    direction = 1;
  }
  if(key === 'a'){
    player.x -= 10;
    direction = 3;
  }
  else if(key === 'd') {
    player.x += 10;
    direction = 2;

  }
  if(key === 'r') {
      resetSketch();
    }
}

class Enemy {
    constructor() {
        this.x = random(width);
        this.y = random(height);
        this.r = 8;
}
    show() {
        fill(5);
        circle(this.x,this.y,this.r);
    } 
}

class Goal {
  constructor() {
    this.x = random(width);
    this.y = random(height);
    this.r = 50;
  }
  show() {
    fill(255);
    circle(this.x,this.y,this.r);
    } 
}
Gen Wan
  • 1,979
  • 2
  • 12
  • 19

1 Answers1

0

For your first problem you could use this post that breaks down an algorithm for finding if a rectangle intersects a circle. For your case this should be even simpler since your rectangle has no rotation.


// something like

var circ = {};
circ.c = center;
circ.r = radius;

var rect= {};
rect.tl = topleft;
rect.l = length;
rect.h = height;

function circRectIntersection(circle, rectangle){
   if (  (circle.c.x > rectangle.tl.x) &&
       (circle.c.y > rectangle.tl.y) &&
       (circle.c.x < rectangle.tl.x + rectangle.l) &&
       (circle.c.y < rectangle.tl.y + rectangle.h))
      return true; // circle is "in" rectangle
  if (  (circle.c.x > rectangle.tl.x) &&
        (circle.c.x < rectangle.tl.x + rectangle.l) &&
        ((abs(circle.c.y - rectangle.tl.y) < r) || (abs(circle.c.y - (rectangle.tl.y + rectangle.h)) < r)))
      return true; // horizontal lines of the rectangle intersect with the circle  possibly with all vertices outside
  if (  (circle.c.y > rectangle.tl.y) &&
        (circle.c.y < rectangle.tl.y + rectangle.h) &&
        ((abs(circle.c.x - rectangle.tl.x) < r) || (abs(circle.c.x - (rectangle.tl.x + rectangle.l)) < r)))
      return true; // vertical lines of the rectangle intersect with the circle, possibly with all vertices outside
   if ( (dist(circle.c.x, circle.c.y, rectangle.tl.x, rectangle.tl.y) < r) ||
        (dist(circle.c.x, circle.c.y, rectangle.tl.x + rectangle.l, rectangle.tl.y) < r) ||
        (dist(cricle.c.x, circle.c.y, rectangle.tl.x, rectangle.tl.y + rectangle.h) < r) || 
        (dist(circle.c.x, circle.c.y, rectangle.tl.x + rectangle.l, rectangle.tl.y + rectangle.h) < r)) 
      return true; // one of the vertices of the rectangle is in the circle

      return false;
}

I try to save the dist functions to the end since they are more computationally expensive. Needless to say though the intersection between a rectangle and a circle is more complex than either a circle with a circle or a rectangle with another rectangle so I would advise rect-rect or circ-circ before you try rect-circ.

As to your second issue you should probably use flags that describe your current screenmode.

You can:

  1. Have a set of booleans that describe the state of your game
  2. Have an int that describes the mode (e.g. if the int is 2 you are "in game" if it is 1 you are in "main menu")
  3. Have the same as 2 but with a string that you case on

Either way the point is to only call the drawing and render functions for a certain "screen" when you are in that screen's "mode".

So something like:


var mode = 0;
const welcomeScreen = 0;
const gameScreen = 1;
const gameOverScreen = 2;
const winScreen = 3;


draw(){
  if (mode == welcomeScreen){ // draw welcome screen}
  else if (mode == gameScreen){ // draw and do game logic}
  else if (mode == gameOverScreen){ // draw game over screen}
  else if (mode == winScreen){ // draw win screen}
}

You could also use a switch-case instead of the else-if chain above.

Finally to make resetting your game easier you could put your "init" procedure for your game inside of its own function and call that every time you know you are about to transition to your gameScreen.

Hope this helps.