Modifying a game: score, random, display

Hello,

I’m currently taking a ‘Learning Processing’ course and I need some help with a game I’m trying to create. It is a 2 person game (Player 1 controls the keyboard, Player 2 controls the mouse). It is a take on the arcade game whack-a-mole. I have a few different questions/areas I need help figuring out and debugging. (This is also the first time I post on a forum, so please let me know if I need to provide anything further).

  1. For player 1 have set keys (Q, W, E, A, S, D, Z, X, C) as the controls for popping up a virus (my "mole). I used the keyCode == to set a specific key. Each key is currently working. However, it only displays one key at a time. If I press ‘Q’ and then press ‘X’, the virus on ‘Q’ disappears and it ‘X’ appears.
  • Is it possible for the virus set to each key to appear at the same time as another? For example, if player 1 selects keys QSD can they all display at the same time?

  • Also, to make the game fair, I would like for the virus (mole) to appear at random times. For example, when a key is pressed, the virus would pop up anywhere between -1 and 7 seconds? This way Player 1 doesn’t have full control of how long player 2 has to whack it.

  • I have multiple classes built for this game. All code is set below.

  1. To win the game, I’m keeping score. Currently, I only have player 2 keeping score.
  • When the mouse is pressed on a virus, the score should increment. It is incrementing, by one, but if player 1 keeps the mouse pressed on the virus, the score continues to go up. How can I get it to only increment once?

  • For player 1, I tried adding an else clause to count the number of times missed, but the score for player one continues to increment indefinitely. How can I set the proper parameters to ensure player 1’s score only incrememnts when player 2 didn’t whack-a-more (virus) on time?

Mallet m; //Mallet Class
Canvas c; //Canvas Class

//COVID-19 Class multiple times for each area #
Virus topR;
Virus topM;
Virus topL;

Virus midL;
Virus midM;
Virus midR;

Virus botR;
Virus botM;
Virus botL;

//Variables for scores
int player1Score;
int player2Score;

void setup() {
  size(700, 700);
  rectMode(CORNERS);

  //Initialize the scores for both players
  player1Score = 0;
  player2Score = 0;

  //Initialize objects
  c = new Canvas();
  m = new Mallet();
  
  topR = new Virus(200, 195, 65);
  topM = new Virus(350, 195, 65);
  topL = new Virus(500, 195, 65);

  midL = new Virus(200, 345, 65);
  midM = new Virus(350, 345, 65);
  midR = new Virus(500, 345, 65);

  botR = new Virus(200, 495, 65);
  botM = new Virus(350, 495, 65);
  botL = new Virus(500, 495, 65);
}

void draw() {
  background(33, 57, 65);
  c.display();

  //Text Area for players score
  textSize(14);
  fill(255);
  String player1 = "Player 1 Score: " + player1Score;
  text(player1, 40, 35, 120, 100);
  fill(150);
  String player2 = "Player 2 Score: " + player2Score;
  text(player2, 40, 350, 120, 100);

  //Virus & Player 1 Controlls
  if (keyCode == 'Q') { //top right
    topR.checkHit();
    topR.display();
  }
  if (keyCode == 'W') { //top middle
    topM.checkHit();
    topM.display();
  }
  if (keyCode == 'E') { //top left
    topL.checkHit();
    topL.display();
  }

  if (keyCode == 'A') { //middle left
    midL.checkHit();
    midL.display();
  }
  if (keyCode == 'S') { //center
    midM.checkHit();
    midM.display();
  }
  if (keyCode == 'D') { //middle right
    midR.checkHit();
    midR.display();
  }
  if (keyCode == 'Z') { //bottom right
    botR.checkHit();
    botR.display();
  }
  if (keyCode == 'X') { //bottom middle
    botM.checkHit();
    botM.display();
  }
  if (keyCode == 'C') { //bottom left
    botL.checkHit();
    botL.display();
  }

  //Mallet
  m.display();
} //end draw

class Virus {
  //variables
  float x;
  float y;
  float r;
  
  //Constructor
  Virus(float tempX, float tempY, float tempR) {
    x = tempX; //temporary x value
    y = tempY; //temporary y value
    r = tempR; //temporary width value
  }

  void display() { //what to display
    ellipseMode(CENTER);
    strokeWeight(1);
    ellipse(x, y, r, r);
  } //End Display

  void checkHit() { //check if the virus has been hit
    if (dist(mouseX, mouseY, x, y) < r){
      fill(0);
    }
    if ((dist(mouseX, mouseY, x, y) < r) && mousePressed && (player2Score < 100)) { //figure out how to make it oence clicked
      fill(50);
      player2Score++;
    } 
  } //End checkHit
} //End Class

class Canvas { //grid for play
  int edge = 125;

  //Constructor
  Canvas() {
  }


  void display() { //what to display
    rectMode(CORNERS);
    stroke(0);
    strokeWeight(4);
    noFill();
    rect(edge, edge, width-edge, height-edge);

    line(125, 275, 575, 275); //horizontal 1
    line(125, 425, 575, 425); //horizontal 2
    line(275, 125, 275, 575); //vertical 1
    line(425, 125, 425, 575); //vertical 2
    
    if (mousePressed) {
      mouseX = constrain(mouseX, edge + 30, 545); //constrain mouse X to canvas
      mouseY = constrain(mouseY, edge + 30, 545); //constrain mouse Y to canvas
    }
    
  } //end Display
} //end Class

class Mallet {


  //Constructor
  Mallet() {
  }


  void display() { //what to display

    rectMode(CENTER);
    if (!mousePressed) { 
      noStroke();
      fill(255);
      rect(mouseX, mouseY, 55, 55, 7);
    } else { 
      noStroke();
      fill(150);
      ellipse(mouseX, mouseY, 55, 55);
    }
  }
}

Hello,

Welcome to the forum.

One of the best tools in a programmers tool chest is knowing the resources available to you and learning to navigate, filter and use them.

This is a very short list:

Resources < Click here to expand !

I encourage you to review the resources available here:

Be mindful of our homework policy:
https://discourse.processing.org/faq#homework

I find the the println() statement useful for debugging:

There are many keyboard related discussions in the forum.
I encourage you to glean insight from these and try them on your own and decide what best fits with your project.

I suggest asking one question at a time with something you have researched and attempted; break it down and share minimal code that you are asking about.

I generally do not assist with homework projects of this scope but will assist if I see a question that I can offer help with.

:)

Thank you for those resources! I will check them out.

As far as my post, should I remove it, and repost as you suggested? With smaller amounts of code, and each question individually?

1 Like

Hello,

I will leave that with you.
I am a member of the community just like you are.

Take a look at some of the other posts for examples.

My only suggestion is to break it down into parts, take it one step at a time, keep it simple and integrate it all in the end.

Lots of folks here to help guide you.

:)

For the first problem, if I understood correctly, what I would do is assign a boolean for each virus and pressing the key toggles the boolean.
Like this:
Edit: I think now this is not exactly what you wanted but it may help

boolean virus1 = false;

if (virus1 == true) {
  topR.checkHit();
  topR.display();
}

void keyPressed() {
  if (key == 'q') virus1 = true;
}

void keyReleased() {
  if (key == 'q') virus1 = false;
}

For this,:

delay(int(random(1000, 6000)));

delay() works pretty good.

Also always search on google first if you have questions using “processing ‘your question/error/problem’” format. It helps me a lot everyday.

Edit: actually dont use delay it doesnt work

Actually delay should not be used as it would completely freeze the game.

In a general matter, it is often a bad idea to use the delay function.

I don’t have the time right now to go into more details but you want to use the millis() function to keep tack of the elapsed time. You can have a look on this forum, the question pops up often.

3 Likes

Yes I know delay() sometimes causes problems (happened a lot lol) but I tried it in the code above and it worked fine.

Edit: I put it in the keyCode if statements.

if (keyCode == 'Q') { //top right
    delay(int(random(1000, 6000)));
    topR.checkHit();
    topR.display();
  }
  if (keyCode == 'W') { //top middle
    delay(int(random(1000, 6000)));
    topM.checkHit();
    topM.display();
  }

like this

EDIT: @glv @jb4x yes delay actually doesnt work my bad sorry about that

2 Likes

Agreed!

And also stated here along with when it should be used:

:)

1 Like

A virus should not show up in the past (-1 sec) to impact the future.

I shared is a snippet of code (recycled yours) using frameCount to randomly display a virus on the grid every second.

I often use frameCount for timing and millis(); it very much depends on my application.

I used println() to display outputs to aid in understanding this.

  int test = 0;   //This is a global variable and should be outside of setup() and draw()

 //println(frameCount);      //prints frameCount

  if (frameCount%60 == 0)
    {
    float rand = random(0, 3);
    test = int(rand);  
    println(frameCount, frameCount%60, frameCount/60, rand, test);
    }

  //Virus & Player 1 Controls
  if (test == 0) { //top right
    topR.checkHit();
    topR.display();
  }
  if (test == 1) { //top middle
    topM.checkHit();
    topM.display();
  }
  if (test == 2) { //top left
    topL.checkHit();
    topL.display();
  }

The above was integrated with your code only as an example of timing with frameCount.

References:
See my previous link.
You can also “right click” on the keywords in your code and display references.

:)

1 Like

No worries! It happens… to me as well. Even when I test my code first!

:)

1 Like

Thank you for your advise… I tried it out on my code, and it’s not doing what I need it to do. When I press ‘Q’ nothing happens now.

This is kind of what I need. If I implement what jb4x mentioned about the millis() function to keep track of time, then something like this could work, right?

Would I add the millis() function to the main program?
Maybe declare

float rand = random(0, 3);

at the top and under each if keyCode statement add

rand;

would something like that work? or is my theory flawed somewhere?

it works on me with his code:

Mallet m; //Mallet Class
Canvas c; //Canvas Class

//COVID-19 Class multiple times for each area #
Virus topR;
Virus topM;
Virus topL;

Virus midL;
Virus midM;
Virus midR;

Virus botR;
Virus botM;
Virus botL;

//Variables for scores
int player1Score;
int player2Score;
boolean virus1 = false;

void setup() {
  size(700, 700);
  rectMode(CORNERS);

  //Initialize the scores for both players
  player1Score = 0;
  player2Score = 0;

  //Initialize objects
  c = new Canvas();
  m = new Mallet();
  
  topR = new Virus(200, 195, 65);
  topM = new Virus(350, 195, 65);
  topL = new Virus(500, 195, 65);

  midL = new Virus(200, 345, 65);
  midM = new Virus(350, 345, 65);
  midR = new Virus(500, 345, 65);

  botR = new Virus(200, 495, 65);
  botM = new Virus(350, 495, 65);
  botL = new Virus(500, 495, 65);
}

void draw() {
  background(33, 57, 65);
  c.display();

  //Text Area for players score
  textSize(14);
  fill(255);
  String player1 = "Player 1 Score: " + player1Score;
  text(player1, 40, 35, 120, 100);
  fill(150);
  String player2 = "Player 2 Score: " + player2Score;
  text(player2, 40, 350, 120, 100);
  
  if (virus1 == true) {
  topR.checkHit();
  topR.display();
}

  if (keyCode == 'W') { //top middle
    topM.checkHit();
    topM.display();
  }
  if (keyCode == 'E') { //top left
    topL.checkHit();
    topL.display();
  }

  if (keyCode == 'A') { //middle left
    midL.checkHit();
    midL.display();
  }
  if (keyCode == 'S') { //center
    midM.checkHit();
    midM.display();
  }
  if (keyCode == 'D') { //middle right
    midR.checkHit();
    midR.display();
  }
  if (keyCode == 'Z') { //bottom right
    botR.checkHit();
    botR.display();
  }
  if (keyCode == 'X') { //bottom middle
    botM.checkHit();
    botM.display();
  }
  if (keyCode == 'C') { //bottom left
    botL.checkHit();
    botL.display();
  }

  //Mallet
  m.display();
} //end draw

void keyPressed() {
  if (key == 'q') virus1 = true;
}

void keyReleased() {
  if (key == 'q') virus1 = false;
}

class Virus {
  //variables
  float x;
  float y;
  float r;
  
  //Constructor
  Virus(float tempX, float tempY, float tempR) {
    x = tempX; //temporary x value
    y = tempY; //temporary y value
    r = tempR; //temporary width value
  }

  void display() { //what to display
    ellipseMode(CENTER);
    strokeWeight(1);
    ellipse(x, y, r, r);
  } //End Display

  void checkHit() { //check if the virus has been hit
    if (dist(mouseX, mouseY, x, y) < r){
      fill(0);
    }
    if ((dist(mouseX, mouseY, x, y) < r) && mousePressed && (player2Score < 100)) { //figure out how to make it oence clicked
      fill(50);
      player2Score++;
    } 
  } //End checkHit
} //End Class

class Canvas { //grid for play
  int edge = 125;

  //Constructor
  Canvas() {
  }


  void display() { //what to display
    rectMode(CORNERS);
    stroke(0);
    strokeWeight(4);
    noFill();
    rect(edge, edge, width-edge, height-edge);

    line(125, 275, 575, 275); //horizontal 1
    line(125, 425, 575, 425); //horizontal 2
    line(275, 125, 275, 575); //vertical 1
    line(425, 125, 425, 575); //vertical 2
    
    if (mousePressed) {
      mouseX = constrain(mouseX, edge + 30, 545); //constrain mouse X to canvas
      mouseY = constrain(mouseY, edge + 30, 545); //constrain mouse Y to canvas
    }
    
  } //end Display
} //end Class

class Mallet {


  //Constructor
  Mallet() {
  }


  void display() { //what to display

    rectMode(CENTER);
    if (!mousePressed) { 
      noStroke();
      fill(255);
      rect(mouseX, mouseY, 55, 55, 7);
    } else { 
      noStroke();
      fill(150);
      ellipse(mouseX, mouseY, 55, 55);
    }
  }
}

But what this code does is, when you press q virus appears and when you release it, it dissapears. I think that is not exactly you want but you can delete the keyReleased part and make the virus’ dissapear after some time.

Hello,

Stop asking questions (I counted 4) and start writing code. << That is encouragement and the same advise I give everyone. :)

Every time I have an idea or given a suggestion… I research it, explore it, start writing a simple example to understand it and then may integrate it into my code.

There are numerous posts on timers.
Look at them, try them out and then write them out on your own; the last step will help you understand them and a good exercise.

A few of mine:

:)

Thank you for that. I put the boolean in the wrong place which made it not work. It’s working now, but I don’t see how that is much different than what I currently have set up. Would doing it this way have some kind of advantage to my current code?

What I’m having trouble figuring out is how to make each virus appear for a random amount of time.

I’m just trying to make sure that what I want to try is worth spending time on. I’m not unwilling to try or research things, I just don’t want to waist my time trying to implement something that isn’t possible. I’m still learning how this all works, which is why I’m asking questions.

Hello,

You can use frameCount or millis() for a timer.

Look up references for these and run the examples.

I like to use the modulo % operator:
https://processing.org/reference/modulo.html

In my example I am using frameCount%60 which is a one second timer
draw() has a frameRate of 60 frames per second so every 60 frames is one second.

frameCount%2 is 2/60 of a second and so on…

You could make the 60 (in %60) a variable and work with that.

You could also go the millis() way for timing.

I work with both so not going to recommend one or the other.

The code I shared was only a simple example of a timer; you had some if statements there and it was easy to integrate rather than writing a separate example. The focus was on timers and not your overall project.

:)

The only advantage of my code is that there can be two viruses at the same time. What I suggest doing there is remove the mouseReleased void and make it so the boolean becomes false when you click on the virus.

Oh, I see now! That makes sense! Thank you! Hopefully, with the timer, I can implement a random feature, and make it disappear without the keyReleased function and implement your suggestion about the disappearing when it becomes false. Thank you :slight_smile:

1 Like

Everything on that list is possible.

Considerations:

I worked through your code and it is all achievable except for time warp (the -1 sec.).

In the end I ended up using arrays of objects as this was much easier and then it was simple to assign color, times, state, boolean, etc. to each object and work with that.

Simple Example of Object Array < Click here!
Virus [] v = new Virus[3];

void setup()
  {
  size(700, 400);
  
  //Use this:     
  //for(int i = 0; i< v.length; i++)
  //  {
  //  color c1 = color(random(0, 255), random(0, 255), random(0, 255));  
  //  v[i] = new Virus(random(0+100, width-100), random(0+100, height-100), random(10, 100), c1);
  //  }
  
  // Or use below:
  color c1 = color(random(0, 255), random(0, 255), random(0, 255));  //EAch has the same color
  
  v[0] = new Virus(200, 195, 65, c1);
  v[1] = new Virus(350, 195, 65, c1);
  v[2] = new Virus(500, 195, 65, c1);
  }

void draw()
  {
  background(200);
  
  for(int i = 0; i< v.length; i++)
    {
    fill(v[i].c);
    circle(v[i].x, v[i].y, v[i].r);
    }
  }    
 
//***************************************************************************************************
class Virus 
  {
  float x;
  float y;
  float r;
  color c;
  // What else can I add here?
  
  //Constructor
  Virus(float tempX, float tempY, float tempR, color tempC) 
    {
    x = tempX;
    y = tempY; 
    r = tempR; 
    c = tempC;
    }
  }

:)

2 Likes