Quiz game - need help


#29

Hmm… Sorry, but I do not understand how to put it in my code, could you give an example? I would appreciate it very much.


#30

Could you maybe post your current code so we know what you’re working with now?


#31
boolean pickNewQuestion;
int questionNb;
boolean pickNewQuestion2;
int questionNb2;
PImage[] myImageArray = new PImage [85];
final int stateGame=0;
final int stateMenu = 1;
final int stateSplashScreen = 2;
final int stateHelp = 3;
final int stateSplashScreen2 = 4;
final int stateMenu2 = 5;
int state = stateSplashScreen;
long t=0;
int points = 0;
int puntos = 0;
int num = 0;

void setup() {
   size(400, 600);
  background(255);  
  myImageArray[1] = loadImage("65.png");
  myImageArray[2] = loadImage("66.png");
  myImageArray[3] = loadImage("67.png");
  myImageArray[4] = loadImage("68.png");
  myImageArray[5] = loadImage("69.png");
  myImageArray[6] = loadImage("70.png");
  myImageArray[7] = loadImage("71.png");
  myImageArray[8] = loadImage("72.png");
  myImageArray[9] = loadImage("73.png");
  myImageArray[10] = loadImage("74.png");
  myImageArray[11] = loadImage("75.png");
  myImageArray[12] = loadImage("76.png");
  myImageArray[13] = loadImage("77.png");
  myImageArray[14] = loadImage("78.png");
  myImageArray[15] = loadImage("79.png");
  myImageArray[16] = loadImage("80.png");
  myImageArray[17] = loadImage("81.png");
  myImageArray[18] = loadImage("82.png");
  myImageArray[19] = loadImage("83.png");
  myImageArray[20] = loadImage("84.png");
  myImageArray[21] = loadImage("85.png");
  myImageArray[22] = loadImage("54.png");
  myImageArray[23] = loadImage("56.png");
  myImageArray[24] = loadImage("46.png");
  myImageArray[25] = loadImage("47.png");
  myImageArray[26] = loadImage("55.png");
  myImageArray[27] = loadImage("63.png");
  myImageArray[28] = loadImage("2.png");
  myImageArray[29] = loadImage("41.png");
  myImageArray[30] = loadImage("10.png");
  myImageArray[31] = loadImage("28.png");
  myImageArray[32] = loadImage("37.png");
  myImageArray[33] = loadImage("20.png");
  myImageArray[34] = loadImage("3.png");
  myImageArray[35] = loadImage("14.png");
  myImageArray[36] = loadImage("11.png");
  myImageArray[37] = loadImage("20.png");
  myImageArray[38] = loadImage("4.png");
  myImageArray[39] = loadImage("21.png");
  myImageArray[40] = loadImage("39.png");
  myImageArray[41] = loadImage("31.png");
  myImageArray[42] = loadImage("19.png");
  myImageArray[43] = loadImage("5.png");
  myImageArray[44] = loadImage("4.png");
  myImageArray[45] = loadImage("13.png");
  myImageArray[46] = loadImage("2.png");
  myImageArray[47] = loadImage("1.png");
  myImageArray[48] = loadImage("9.png");
  myImageArray[49] = loadImage("29.png");
  myImageArray[50] = loadImage("12.png");
  myImageArray[51] = loadImage("23.png");
  myImageArray[52] = loadImage("17.png");
  myImageArray[53] = loadImage("16.png");
  myImageArray[54] = loadImage("48.png");
  myImageArray[55] = loadImage("24.png");
  myImageArray[56] = loadImage("8.png");
  myImageArray[57] = loadImage("6.png");
  myImageArray[58] = loadImage("58.png");
  myImageArray[59] = loadImage("33.png");
  myImageArray[60] = loadImage("64.png");
  myImageArray[61] = loadImage("15.png");
  myImageArray[62] = loadImage("62.png");
  myImageArray[63] = loadImage("47.png");
  myImageArray[64] = loadImage("51.png");
  myImageArray[65] = loadImage("59.png");
  myImageArray[66] = loadImage("27.png");
  myImageArray[67] = loadImage("93.png");
  myImageArray[68] = loadImage("94.png");
  myImageArray[69] = loadImage("95.png");
  myImageArray[70] = loadImage("89.png");
  myImageArray[71] = loadImage("97.png");
  myImageArray[72] = loadImage("86.png");
  myImageArray[73] = loadImage("87.png");
  myImageArray[74] = loadImage("88.png");
  myImageArray[75] = loadImage("90.png");
  myImageArray[76] = loadImage("91.png");
  myImageArray[77] = loadImage("42.png");
  myImageArray[78] = loadImage("50.png");
  myImageArray[79] = loadImage("49.png");
  myImageArray[80] = loadImage("56.png");
  myImageArray[81] = loadImage("43.png");
  myImageArray[82] = loadImage("36.png");
  myImageArray[83] = loadImage("40.png");
  myImageArray[84] = loadImage("7.png"); 
  points = 0;
}

void draw() { 
  background(255);
  fill(0);
  stroke(0);
  textSize(22);

  switch(state) {
  case stateGame:
    drawForStateGame();
    break;
  case stateSplashScreen://menu1
    drawForStateSplashScreen();
    break; 
  case stateHelp:
    drawForStateHelp();
    break;  
  case stateMenu://juego
    drawForStateMenu();
    break; 
  case stateMenu2://juego2
    drawForStateMenu2();
    break;
  case stateSplashScreen2://menu2
    drawForStateSplashScreen2();
    break;   
  default:
    // error 
    break;
  }
} 
void drawForStateGame() {}
 
void drawForStateSplashScreen() {//menu1
  textSize(40);
  text("1 para jugar",30,30);
  textSize(40);
  text("2 para ayuda",30,50);
  textSize(40);
  text("3para salir",30,70);
  points=0;
  t=0;
  t = millis();
}
 void drawForStateSplashScreen2(){//menu2
  textSize(40);
  text("comeme el donut",30,30);
  textSize(40);
  text("2 para pedro",30,50);
  textSize(40);
  text("3para cagar",30,70);
  puntos=0;
  t=0;
  t = millis();
 }
void drawForStateHelp() {
  text("the help...", 200, 100);
}
 
void drawForStateMenu() {//juego1
  {
  if (pickNewQuestion) { 
    pickRandomQuestion(); 
    pickNewQuestion = false;
  }
  {
  float timer = (millis() - t) / 1000; 
  if (timer >= 30) { 
  noLoop();
}
  {
  background(255);
  fill(0);
  textSize(20);
  text("score:" + points, 20, 550);
   fill(0);
  textSize(20);
  text("time:" + (30-timer), 200, 550);
   }
  if (questionNb == 0) {
    image(myImageArray[1], 20, 20);
    image(myImageArray[22], 0, 180);
    image(myImageArray[23], 200, 180);
    image(myImageArray[24], 90, 350);
  }  
  if (questionNb == 1) {
   image(myImageArray[2],30, 20);
   image(myImageArray[25], 0, 180);
   image(myImageArray[26],200,180);
   image(myImageArray[27], 90, 350);  
  }
  
  if (questionNb == 2) {
   image(myImageArray[3],30, 20);
   image(myImageArray[28], 0, 180);
   image(myImageArray[29],200,180);
   image(myImageArray[30], 90, 350);
   
  }
  if (questionNb == 3) {
   image(myImageArray[4],30, 20);
   image(myImageArray[31], 0, 180);
   image(myImageArray[32],200,180);
   image(myImageArray[33], 90, 350);

  }
  if (questionNb == 4) {
   image(myImageArray[5],30, 20);
   image(myImageArray[36], 0, 180);
   image(myImageArray[35],200,180);
   image(myImageArray[34], 90, 350);
  }
  if (questionNb == 5) {
   image(myImageArray[6],30, 20);
   image(myImageArray[37], 0, 180);
   image(myImageArray[38],200,180);
   image(myImageArray[39], 90, 350);
  }
  if (questionNb == 6) {
   image(myImageArray[7],30, 20);
   image(myImageArray[40], 0, 180);
   image(myImageArray[41],200,180);
   image(myImageArray[42], 90, 350);
  }
  
  if (questionNb == 7) {
   image(myImageArray[8],30, 20);
   image(myImageArray[43], 0, 180);
   image(myImageArray[50],200,180);
   image(myImageArray[45], 90, 350);
  }
  
  if (questionNb == 8) {
   image(myImageArray[6],30, 20);
   image(myImageArray[33], 0, 180);
   image(myImageArray[38],200,180);
   image(myImageArray[39], 90, 350);
  }
  
  if (questionNb == 9) {
   image(myImageArray[12],30, 20);
   image(myImageArray[40], 0, 180);
   image(myImageArray[41],200,180);
   image(myImageArray[66], 90, 350);
  }
  
  if (questionNb == 10) {
   image(myImageArray[11],30, 20);
   image(myImageArray[43], 0, 180);
   image(myImageArray[50],200,180);
   image(myImageArray[45], 90, 350);
  }
  
  if(points == 10) {
    state = stateSplashScreen2;
  }
  }
  }
  }
  
  
  
  void drawForStateMenu2() {//juego2
  {
  if (pickNewQuestion2) { 
    pickRandomQuestion2(); 
    pickNewQuestion2 = false;
  }
  {
  float timer = (millis() - t) / 1000; 
  if (timer >= 30) { 
  noLoop();
}
  {
  background(255);
  fill(0);
  textSize(20);
  text("score:" + puntos, 20, 550);
   fill(0);
  textSize(20);
  text("time:" + (30-timer), 200, 550);
  }
  if (questionNb2 == 0) {
    image(myImageArray[67], 20, 20);
    image(myImageArray[77], 0, 180);
    image(myImageArray[78], 200, 180);
    image(myImageArray[79], 90, 350);
  }  
  if (questionNb2 == 1) {
   image(myImageArray[68],30, 20);
   image(myImageArray[54], 0, 180);
   image(myImageArray[24],200,180);
   image(myImageArray[80], 90, 350);  
  }
  
  if (questionNb2 == 2) {
   image(myImageArray[69],30, 20);
   image(myImageArray[61], 0, 180);
   image(myImageArray[81],200,180);
   image(myImageArray[36], 90, 350);
   
  }
  if (questionNb2 == 3) {
   image(myImageArray[70],30, 20);
   image(myImageArray[81], 0, 180);
   image(myImageArray[82],200,180);
   image(myImageArray[49], 90, 350);

  }
  if (questionNb2 == 4) {
   image(myImageArray[71],30, 20);
   image(myImageArray[22], 0, 180);
   image(myImageArray[81],200,180);
   image(myImageArray[64], 90, 350);
  }
  if (questionNb2 == 5) {
   image(myImageArray[72],30, 20);
   image(myImageArray[24], 0, 180);
   image(myImageArray[35],200,180);
   image(myImageArray[25], 90, 350);
  }
  if (questionNb2 == 6) {
   image(myImageArray[73],30, 20);
   image(myImageArray[64], 0, 180);
   image(myImageArray[25],200,180);
   image(myImageArray[26], 90, 350);
  }
  
  if (questionNb2 == 7) {
   image(myImageArray[74],30, 20);
   image(myImageArray[28], 0, 180);
   image(myImageArray[84],200,180);
   image(myImageArray[47], 90, 350);
  }
  
  if (questionNb2 == 8) {
   image(myImageArray[70],30, 20);
   image(myImageArray[49], 0, 180);
   image(myImageArray[33],200,180);
   image(myImageArray[31], 90, 350);
  }
  
  if (questionNb2 == 9) {
   image(myImageArray[75],30, 20);
   image(myImageArray[61], 0, 180);
   image(myImageArray[36],200,180);
   image(myImageArray[34], 90, 350);
  }
  
  if (questionNb2 == 10) {
   image(myImageArray[76],30, 20);
   image(myImageArray[49], 0, 180);
   image(myImageArray[39],200,180);
   image(myImageArray[33], 90, 350);
  }
  }
  }
  }
  
  
  
  
void pickRandomQuestion() {
  questionNb = ((int)random(11));
}

void pickRandomQuestion2() {
  questionNb2 = ((int)random(11));
}




  void mousePressed(){ 
     if (answerClicked(mouseX, mouseY)) { 
    pickNewQuestion = true; 
    switch(state) {
    case stateSplashScreen:
     if((mouseX > 0 && mouseX < 400) && (mouseY > 0 && mouseY < 200)){
      state = stateMenu;
     }
     else if((mouseX > 0 && mouseX < 400) && (mouseY > 200 && mouseY < 400)){
     state = stateHelp;
     }
     else if((mouseX > 0 && mouseX < 400) && (mouseY > 200 && mouseY < 600)){
     exit();
     }
    
    case stateMenu:
    if((mouseX > 312 && mouseX < 380) && (mouseY > 530 && mouseY < 590)){
      state = stateSplashScreen;
     }
     }
    }
     
     if (answerClicked2(mouseX, mouseY)) { 
    pickNewQuestion2 = true;
     switch(state) {
    case stateSplashScreen2:
     if ((mouseX > 0 && mouseX < 400) && (mouseY > 200 && mouseY < 400)){
      state = stateMenu2;
     }
     }
     }
  }
  

boolean answerClicked(int x, int y) {
  if (questionNb == 0) { 
    if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){
      if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){//3
    points++;
      }
  }
    }
    {  
  if (questionNb == 1) { 
    if((mouseX > 220 && mouseX < 380) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 220 && mouseX < 385) && (mouseY > 175 && mouseY < 340)){//2
    points++;
  }
    }
  }
    {
 if (questionNb == 2) { 
    if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){//1
    points++;
    }
    }
  }
    {
 if (questionNb == 3) { 
    if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){//1
    points++;
    }
    }
  }
    {
 if (questionNb == 4) { 
   if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){
      if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){//3
    points++;
    }
    }
  }
    {
 if (questionNb == 5) { 
    if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){//1
    points++;
    }
    }
  }
    {
 if (questionNb == 6) { 
     if((mouseX > 220 && mouseX < 380) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 220 && mouseX < 385) && (mouseY > 175 && mouseY < 340)){//2
    points++;
    }
    }
  }
    {
 if (questionNb == 7) { 
    if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){
      if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){//3
    points++;
    }
    }
  }
    {
 if (questionNb == 8) { 
    if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){//1
    points++;
    }
    }
  }
    {
 if (questionNb == 9) { 
    if((mouseX > 220 && mouseX < 380) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 220 && mouseX < 385) && (mouseY > 175 && mouseY < 340)){//2
    points++;
    }
    }
  }
    {
 if (questionNb == 10) { 
    if((mouseX > 220 && mouseX < 380) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 220 && mouseX < 385) && (mouseY > 175 && mouseY < 340)){//2
    points++;
      }
    }
  }
    }
  }
  return true;
    }
    }
    }
    }
    }
    }
    }
    }
}

boolean answerClicked2(int x, int y) {
if (questionNb2 == 0) { 
    if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){
      if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){//3
    puntos++;
      }
  }
    }
    {  
  if (questionNb2 == 1) { 
    if((mouseX > 220 && mouseX < 380) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 220 && mouseX < 385) && (mouseY > 175 && mouseY < 340)){//2
    puntos++;
  }
    }
  }
    {
 if (questionNb2 == 2) { 
    if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){//1
    puntos++;
    }
    }
  }
    {
 if (questionNb2 == 3) { 
    if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){//1
    puntos++;
    }
    }
  }
    {
 if (questionNb2 == 4) { 
   if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){
      if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){//3
    puntos++;
    }
    }
  }
    {
 if (questionNb2 == 5) { 
    if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){//1
    puntos++;
    }
    }
  }
    {
 if (questionNb2 == 6) { 
     if((mouseX > 220 && mouseX < 380) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 220 && mouseX < 385) && (mouseY > 175 && mouseY < 340)){//2
    puntos++;
    }
    }
  }
    {
 if (questionNb2 == 7) { 
    if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){
      if((mouseX > 120 && mouseX < 265) && (mouseY > 355 && mouseY < 490)){//3
    puntos++;
    }
    }
  }
    {
 if (questionNb2 == 8) { 
    if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 20 && mouseX < 190) && (mouseY > 175 && mouseY < 340)){//1
    puntos++;
    }
    }
  }
    {
 if (questionNb2 == 9) { 
    if((mouseX > 220 && mouseX < 380) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 220 && mouseX < 385) && (mouseY > 175 && mouseY < 340)){//2
    puntos++;
    }
    }
  }
    {
 if (questionNb2 == 10) { 
    if((mouseX > 220 && mouseX < 380) && (mouseY > 175 && mouseY < 340)){
      if((mouseX > 220 && mouseX < 385) && (mouseY > 175 && mouseY < 340)){//2
    puntos++;
      }
    }
  }
    }
  }
  return true;
    }
    }
    }
    }
    }
    }
    }
    }
}

#32

Remember when I said you shouldn’t try to get it all working at once?

Remember what I said would happen?

  1. You won’t get it to work all at once.
  2. You will go insane trying to get it to work all at once.
  3. You will ask us for help trying to get it to work all at once.
  4. We will go insane trying to help you getting it to work all at once.

We’re currently at #3.


Honestly, your code is a horrible mess. Sure, it works. But to edit it at all is a nightmare. It is very WET, which means you Write Everything Twice. DRY code is better. DRY stands for Don’t Repeat Yourself.

Let’s throw away your current code for now and jump back in time to the sketch that I really wanted you to write, since it never happened. Yes, it’s the classic “Click on the rectangle!” quiz.

Start with a blank sketch. This is an important step because you know that this sketch works 100% correct, and you understand it completely.

void setup(){
  size(600,400);
}

void draw(){
  background(0);
}

Next, add the question:

void setup(){
  size(600,400);
}

void draw(){
  background(0);
  fill(255);
  textAlign(CENTER);
  text("Click on the rectangle!", width/2, 40);
}

Great. Next, add the first possible answer choice.

void setup(){
  size(600,400);
}

void draw(){
  background(0);
  // The question.
  fill(255);
  textAlign(CENTER);
  text("Click on the rectangle!", width/2, 40);
  // The first possible answer - a circle.
  fill(64);
  stroke(196);
  rectMode(CENTER);
  rect(width/4, 2*height/3,120,80);
  fill(0,200,0);
  noStroke();
  ellipse(width/4, 2*height/3, 70,70); 
}

Next, the second possible answer choice.

void setup(){
  size(600,400);
}

void draw(){
  background(0);
  // The question.
  fill(255);
  textAlign(CENTER);
  text("Click on the rectangle!", width/2, 40);
  // The first possible answer - a circle.
  fill(64);
  stroke(196);
  rectMode(CENTER);
  rect(width/4, 2*height/3,120,80);
  fill(0,200,0);
  noStroke();
  ellipse(width/4, 2*height/3, 70,70);
  // A second answer choice - the rectangle.
  fill(64);
  stroke(196);
  rectMode(CENTER);
  rect(3*width/4, 2*height/3,120,80);
  fill(0,0,200);
  noStroke();
  rect(3*width/4, 2*height/3, 80,50);
}

Looks good. Now we need to add the logic for clicking on one of the answers. Since that involves detecting a mouse click, this will happen in the mousePressed() function. We will also add the concept of states at this time.

int playing_state = 0;
int won_state = 1;
int lost_state = 2;
int state;

void setup() {
  size(600, 400);
  state = playing_state;
}

void draw() {
  if ( state == playing_state ) {
    background(0);
    // The question.
    fill(255);
    textAlign(CENTER);
    text("Click on the rectangle!", width/2, 40);
    // The first possible answer - a circle.
    fill(64);
    stroke(196);
    rectMode(CENTER);
    rect(width/4, 2*height/3, 120, 80);
    fill(0, 200, 0);
    noStroke();
    ellipse(width/4, 2*height/3, 70, 70);
    // A second answer choice - the rectangle.
    fill(64);
    stroke(196);
    rectMode(CENTER);
    rect(3*width/4, 2*height/3, 120, 80);
    fill(0, 0, 200);
    noStroke();
    rect(3*width/4, 2*height/3, 80, 50);
  }
  if ( state == won_state ) {
    background(0, 255, 0);
    fill(0);
    textSize(64);
    text("YOU WON!", width/2, height/2);
  }
  if ( state == lost_state ) {
    background(255, 0, 0);
    fill(0);
    textSize(64);
    text("YOU LOST!", width/2, height/2);
  }
}

void mousePressed() {
  // is the mouse over the circle choice?
  if ( width/4 - 60 < mouseX && mouseX < width/4 + 60 &&
    2*height/3 -40 < mouseY && mouseY < 2*height/3 + 40 ) {
    state = lost_state;
  }
  // Is the mouse over the rectangle choice?
  if ( 3*width/4 - 60 < mouseX && mouseX < 3*width/4 + 60 &&
    2*height/3 -40 < mouseY && mouseY < 2*height/3 + 40 ) {
    state = won_state;
  }
}

Why do we bother doing this? You’ll see…


#33

The next step is to tidy up the code we have. I know, it looks fine, and it works. But if we tried to make multiple questions this way we are going to run into a ton of problems. If we sort out things now with a simple quiz, we won’t have to worry about them when we’re working with more difficult questions.

The first problem I see is that we’re doing a ton of logic to detect if we’re clicking on an answer, and we’re putting a lot of effort in to drawing our answer choices. This needs to be abstracted. So let’s write an AnswerChoice class now.

class AnswerChoice {
  float x, y, w, h;
  int i;
  boolean c;
  AnswerChoice(int position, int image, boolean correct_answer) {
    x = xs[position];
    y = ys[position];
    i = image;
    w = images[image].width;
    h = images[image].height;
    c = correct_answer;
  }
  void draw() {
    imageMode(CENTER);
    image(images[i], x, y);
  }
  boolean over() {
    return( x-w/2 < mouseX && mouseX < x+w/2 && y-h/2 < mouseY && mouseY < y+h/2 );
  }
  void click() {
    if ( over() ) {
      if ( c ) {
        //score++;
        state = won_state;
      } else {
        state = lost_state;
      }
      new_question();
    }
  }
}

PImage[] images = new PImage[2];
float[] xs = new float[3];
float[] ys = new float[3];
//int score;

void new_question() {
}

void make_images() {
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 200, 0);
  noStroke();
  ellipse(60, 40, 70, 70);
  images[0] = get(0, 0, 121, 81);
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 0, 200);
  noStroke();
  rect(20, 15, 80, 50);
  images[1] = get(0, 0, 121, 81);
}

AnswerChoice[] choices = new AnswerChoice[2];

int playing_state = 0;
int won_state = 1;
int lost_state = 2;
int state;


void setup() {
  size(600, 400);
  state = playing_state;
  make_images();
  make_question();
}

void make_question() {
  xs[0] = width/4;
  xs[1] = 3*width/4;
  ys[0] = 2*height/3;
  ys[1] = 2*height/3;
  choices[0] = new AnswerChoice(0, 0, false);
  choices[1] = new AnswerChoice(1, 1, true);
}

void draw() {
  if ( state == playing_state ) {
    background(0);
    // The question.
    fill(255);
    textAlign(CENTER);
    text("Click on the rectangle!", width/2, 40);
    // Draw all possible answers.
    for ( int ac = 0; ac < choices.length; ac++) {
      choices[ac].draw();
    }
  }
  if ( state == won_state ) {
    background(0, 255, 0);
    fill(0);
    textSize(64);
    text("YOU WON!", width/2, height/2);
  }
  if ( state == lost_state ) {
    background(255, 0, 0);
    fill(0);
    textSize(64);
    text("YOU LOST!", width/2, height/2);
  }
}

void mousePressed() {
  // Check for click on all answer choices.
  for ( int ac = 0; ac < choices.length; ac++) {
    choices[ac].click();
  }
}

WHOA… That’s a ton of changes! But wait, look, the sketch is EXACTLY THE SAME.
But these changes are super important - since I’ve generalized what it means to be an answer choice now, it’s going to be much easier to work with them later.

The next step is to do the same thing for a whole question!


#34

Look at this!

class AnswerChoice {
  float x, y, w, h;
  int i;
  boolean c;
  AnswerChoice(int position, int image, boolean correct_answer) {
    x = xs[position];
    y = ys[position];
    i = image;
    w = images[image].width;
    h = images[image].height;
    c = correct_answer;
  }
  void draw() {
    imageMode(CENTER);
    image(images[i], x, y);
  }
  boolean over() {
    return( x-w/2 < mouseX && mouseX < x+w/2 && y-h/2 < mouseY && mouseY < y+h/2 );
  }
  void click() {
    if ( over() ) {
      if ( c ) {
        //score++;
        state = won_state;
      } else {
        state = lost_state;
      }
      new_question();
    }
  }
}

class Question {
  String s;
  AnswerChoice[] acs;
  Question(String questionText, int correctChoice ) {
    s = questionText;
    acs = new AnswerChoice[2];
    int correct_position = int(random(acs.length));
    for ( int ps = 0; ps < acs.length; ps++) {
      if ( ps == correct_position ) {
        acs[ps] = new AnswerChoice( ps, correctChoice, true );
      } else {
        int randoChoice = correctChoice;
        while ( randoChoice == correctChoice ) {
          randoChoice = int(random(images.length));
        }
        acs[ps] = new AnswerChoice( ps, randoChoice, false );
      }
    }
  }
  void draw() {
    fill(255);
    textAlign(CENTER);
    text(s, width/2, 40);
    // Draw all possible answers.
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].draw();
    }
  }
  void click() {
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].click();
    }
  }
}


PImage[] images = new PImage[2];
float[] xs = new float[3];
float[] ys = new float[3];

//int score;
void new_question() {
}

void make_images() {
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 200, 0);
  noStroke();
  ellipse(60, 40, 70, 70);
  images[0] = get(0, 0, 121, 81);
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 0, 200);
  noStroke();
  rect(20, 15, 80, 50);
  images[1] = get(0, 0, 121, 81);
}

int playing_state = 0;
int won_state = 1;
int lost_state = 2;
int state;

Question q;

void setup() {
  size(600, 400);
  state = playing_state;
  make_images();
  xs[0] = width/4;
  xs[1] = 3*width/4;
  ys[0] = 2*height/3;
  ys[1] = 2*height/3;
  q = new Question("Click on the rectangle!", 1);
}

void draw() {
  background(0);
  q.draw();
  win_screen();
  lost_screen();
}

void mousePressed() {
  q.click();
}

void win_screen() {
  if ( state == won_state ) {
    background(0, 255, 0);
    fill(0);
    textSize(64);
    text("YOU WON!", width/2, height/2);
  }
}

void lost_screen() {
  if ( state == lost_state ) {
    background(255, 0, 0);
    fill(0);
    textSize(64);
    text("YOU LOST!", width/2, height/2);
  }
}

Now we have a Question class! The Question class keeps track of a whole question for us. We only have one Question, q. Its question is to click on the rectangle and its correct answer is 1, because that is the image of the rectangle.

If you run this code a few times, you might notice that this sketch is slightly different from what came before. It’s subtle, but the answer choices might switch positions. This is because the Question class is actually randomly putting the right answer into one of two possible answer choice positions.

… I know what you’re thinking. That is a TON of code to do such a simple quiz. There are layers on layers of understanding in there, and it’s a lot to wrap your head around. AND THAT’S WHY WE DID IT WITH A SIMPLE QUIZ FIRST. This is the basic quiz system that I wanted you to get working.

Now that we have this basic system, we can easily make changes to it…


#35

For example, we can start by cranking up the number of answer choices to 6.

class AnswerChoice {
  float x, y, w, h;
  int i;
  boolean c;
  AnswerChoice(int position, int image, boolean correct_answer) {
    x = xs[position];
    y = ys[position];
    i = image;
    w = images[image].width;
    h = images[image].height;
    c = correct_answer;
  }
  void draw() {
    imageMode(CENTER);
    image(images[i], x, y);
  }
  boolean over() {
    return( x-w/2 < mouseX && mouseX < x+w/2 && y-h/2 < mouseY && mouseY < y+h/2 );
  }
  void click() {
    if ( over() ) {
      if ( c ) {
        //score++;
        state = won_state;
      } else {
        state = lost_state;
      }
      new_question();
    }
  }
}

class Question {
  String s;
  AnswerChoice[] acs;
  Question(String questionText, int correctChoice ) {
    s = questionText;
    acs = new AnswerChoice[6];
    int correct_position = int(random(acs.length));
    for ( int ps = 0; ps < acs.length; ps++) {
      if ( ps == correct_position ) {
        acs[ps] = new AnswerChoice( ps, correctChoice, true );
      } else {
        int randoChoice = correctChoice;
        while ( randoChoice == correctChoice ) {
          randoChoice = int(random(images.length));
        }
        acs[ps] = new AnswerChoice( ps, randoChoice, false );
      }
    }
  }
  void draw() {
    fill(255);
    textAlign(CENTER);
    text(s, width/2, 40);
    // Draw all possible answers.
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].draw();
    }
  }
  void click() {
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].click();
    }
  }
}


PImage[] images = new PImage[2];
float[] xs = new float[6];
float[] ys = new float[6];

//int score;
void new_question() {
}

void make_images() {
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 200, 0);
  noStroke();
  ellipse(60, 40, 70, 70);
  images[0] = get(0, 0, 121, 81);
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 0, 200);
  noStroke();
  rect(20, 15, 80, 50);
  images[1] = get(0, 0, 121, 81);
}

int playing_state = 0;
int won_state = 1;
int lost_state = 2;
int state;

Question q;

void setup() {
  size(600, 400);
  state = playing_state;
  make_images();
  xs[0] = xs[3] = width/4;
  xs[1] = xs[4] = width/2;
  xs[2] = xs[5] = 3*width/4;  
  ys[0] = ys[1] = ys[2] = 2*height/4;
  ys[3] = ys[4] = ys[5] = 3*height/4;
  
  q = new Question("Click on the rectangle!", 1);
}

void draw() {
  background(0);
  q.draw();
  win_screen();
  lost_screen();
}

void mousePressed() {
  q.click();
}

void win_screen() {
  if ( state == won_state ) {
    background(0, 255, 0);
    fill(0);
    textSize(64);
    text("YOU WON!", width/2, height/2);
  }
}

void lost_screen() {
  if ( state == lost_state ) {
    background(255, 0, 0);
    fill(0);
    textSize(64);
    text("YOU LOST!", width/2, height/2);
  }
}

#36

Or we can throw some more shapes in.

class AnswerChoice {
  float x, y, w, h;
  int i;
  boolean c;
  AnswerChoice(int position, int image, boolean correct_answer) {
    x = xs[position];
    y = ys[position];
    i = image;
    w = images[image].width;
    h = images[image].height;
    c = correct_answer;
  }
  void draw() {
    imageMode(CENTER);
    image(images[i], x, y);
  }
  boolean over() {
    return( x-w/2 < mouseX && mouseX < x+w/2 && y-h/2 < mouseY && mouseY < y+h/2 );
  }
  void click() {
    if ( over() ) {
      if ( c ) {
        //score++;
        state = won_state;
      } else {
        state = lost_state;
      }
      new_question();
    }
  }
}

class Question {
  String s;
  AnswerChoice[] acs;
  Question(String questionText, int correctChoice ) {
    s = questionText;
    acs = new AnswerChoice[6];
    int correct_position = int(random(acs.length));
    for ( int ps = 0; ps < acs.length; ps++) {
      if ( ps == correct_position ) {
        acs[ps] = new AnswerChoice( ps, correctChoice, true );
      } else {
        int randoChoice = correctChoice;
        while ( randoChoice == correctChoice ) {
          randoChoice = int(random(images.length));
        }
        acs[ps] = new AnswerChoice( ps, randoChoice, false );
      }
    }
  }
  void draw() {
    fill(255);
    textAlign(CENTER);
    text(s, width/2, 40);
    // Draw all possible answers.
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].draw();
    }
  }
  void click() {
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].click();
    }
  }
}

PImage[] images = new PImage[4];
void make_images() {
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 200, 0);
  noStroke();
  ellipse(60, 40, 70, 70);
  images[0] = get(0, 0, 121, 81);
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 0, 200);
  noStroke();
  rect(20, 15, 80, 50);
  images[1] = get(0, 0, 121, 81);
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(200, 200, 0);
  noStroke();
  pushMatrix();
  translate(60,40);
  triangle(-20,20,0,-25,20,20);
  popMatrix();
  images[2] = get(0, 0, 121, 81);
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(200, 0, 200);
  noStroke();
  rect(35, 15, 50, 50);
  images[3] = get(0, 0, 121, 81);
  
}

int playing_state = 0;
int won_state = 1;
int lost_state = 2;
int state;
float[] xs = new float[6];
float[] ys = new float[6];
//int score;
void new_question() {}

Question q;

void setup() {
  size(600, 400);
  state = playing_state;
  make_images();
  xs[0] = xs[3] = width/4;
  xs[1] = xs[4] = width/2;
  xs[2] = xs[5] = 3*width/4;  
  ys[0] = ys[1] = ys[2] = 2*height/4;
  ys[3] = ys[4] = ys[5] = 3*height/4;
  
  q = new Question("Click on the rectangle!", 1);
}

void draw() {
  background(0);
  q.draw();
  win_screen();
  lost_screen();
}

void mousePressed() {
  q.click();
}

void win_screen() {
  if ( state == won_state ) {
    background(0, 255, 0);
    fill(0);
    textSize(64);
    text("YOU WON!", width/2, height/2);
  }
}

void lost_screen() {
  if ( state == lost_state ) {
    background(255, 0, 0);
    fill(0);
    textSize(64);
    text("YOU LOST!", width/2, height/2);
  }
}

Why, you could even load your shapes from a selection of shapes…


#37

Or generate your question randomly…

class AnswerChoice {
  float x, y, w, h;
  int i;
  boolean c;
  AnswerChoice(int position, int image, boolean correct_answer) {
    x = xs[position];
    y = ys[position];
    i = image;
    w = images[image].width;
    h = images[image].height;
    c = correct_answer;
  }
  void draw() {
    imageMode(CENTER);
    image(images[i], x, y);
  }
  boolean over() {
    return( x-w/2 < mouseX && mouseX < x+w/2 && y-h/2 < mouseY && mouseY < y+h/2 );
  }
  void click() {
    if ( over() ) {
      if ( c ) {
        //score++;
        state = won_state;
      } else {
        state = lost_state;
      }
      new_question();
    }
  }
}

class Question {
  String s;
  AnswerChoice[] acs;
  Question(String questionText, int correctChoice ) {
    s = questionText;
    acs = new AnswerChoice[6];
    int correct_position = int(random(acs.length));
    for ( int ps = 0; ps < acs.length; ps++) {
      if ( ps == correct_position ) {
        acs[ps] = new AnswerChoice( ps, correctChoice, true );
      } else {
        int randoChoice = correctChoice;
        while ( randoChoice == correctChoice ) {
          randoChoice = int(random(images.length));
        }
        acs[ps] = new AnswerChoice( ps, randoChoice, false );
      }
    }
  }
  void draw() {
    fill(255);
    textAlign(CENTER);
    text(s, width/2, 40);
    // Draw all possible answers.
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].draw();
    }
  }
  void click() {
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].click();
    }
  }
}

PImage[] images = new PImage[4];
String[] names = new String[4];
void make_images() {
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 200, 0);
  noStroke();
  ellipse(60, 40, 70, 70);
  images[0] = get(0, 0, 121, 81);
  names[0] = "green circle";
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(0, 0, 200);
  noStroke();
  rect(20, 15, 80, 50);
  images[1] = get(0, 0, 121, 81);
  names[1] = "blue rectangle";
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(200, 200, 0);
  noStroke();
  pushMatrix();
  translate(60,40);
  triangle(-20,20,0,-25,20,20);
  popMatrix();
  images[2] = get(0, 0, 121, 81);
  names[2] = "yellow triangle";
  fill(64);
  stroke(196);
  rect(0, 0, 120, 80);
  fill(200, 0, 200);
  noStroke();
  rect(35, 15, 50, 50);
  images[3] = get(0, 0, 121, 81);
  names[3] = "pink square";  
}

int playing_state = 0;
int won_state = 1;
int lost_state = 2;
int state;
float[] xs = new float[6];
float[] ys = new float[6];
//int score;
void new_question() {}

Question q;

void setup() {
  size(600, 400);
  state = playing_state;
  make_images();
  xs[0] = xs[3] = width/4;
  xs[1] = xs[4] = width/2;
  xs[2] = xs[5] = 3*width/4;  
  ys[0] = ys[1] = ys[2] = 2*height/4;
  ys[3] = ys[4] = ys[5] = 3*height/4;
  
  int rq = int(random(4));
  q = new Question("Click on the " + names[rq] + "!", rq);
}

void draw() {
  background(0);
  q.draw();
  win_screen();
  lost_screen();
}

void mousePressed() {
  q.click();
}

void win_screen() {
  if ( state == won_state ) {
    background(0, 255, 0);
    fill(0);
    textSize(64);
    text("YOU WON!", width/2, height/2);
  }
}

void lost_screen() {
  if ( state == lost_state ) {
    background(255, 0, 0);
    fill(0);
    textSize(64);
    text("YOU LOST!", width/2, height/2);
  }
}

#38

The important point is that I don’t have to edit hundreds of lines to make little changes like these. That’s because I haven’t “hard coded” what any of the questions are. My code is very DRY in that there are no repeating patterns in it.

Well, that’s not actually true. Look at make_shapes() again. See how it’s starting to look like a repeating pattern? even that can be fixed. Hey, why not.

class AnswerChoice {
  float x, y, w, h;
  int i;
  boolean c;
  AnswerChoice(int position, int image, boolean correct_answer) {
    x = xs[position];
    y = ys[position];
    i = image;
    w = images[image].width;
    h = images[image].height;
    c = correct_answer;
  }
  void draw() {
    imageMode(CENTER);
    image(images[i], x, y);
  }
  boolean over() {
    return( x-w/2 < mouseX && mouseX < x+w/2 && y-h/2 < mouseY && mouseY < y+h/2 );
  }
  void click() {
    if ( over() ) {
      if ( c ) {
        score++;
        //state = won_state;
      } else {
        //state = lost_state;
      }
      new_question();
    }
  }
}

class Question {
  String s;
  AnswerChoice[] acs;
  Question(String questionText, int correctChoice ) {
    s = questionText;
    acs = new AnswerChoice[6];
    int correct_position = int(random(acs.length));
    for ( int ps = 0; ps < acs.length; ps++) {
      if ( ps == correct_position ) {
        acs[ps] = new AnswerChoice( ps, correctChoice, true );
      } else {
        int randoChoice = correctChoice;
        while ( randoChoice == correctChoice ) {
          randoChoice = int(random(images.length));
        }
        acs[ps] = new AnswerChoice( ps, randoChoice, false );
      }
    }
  }
  void draw() {
    fill(255);
    textAlign(CENTER);
    text(s, width/2, 40);
    // Draw all possible answers.
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].draw();
    }
  }
  void click() {
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].click();
    }
  }
}

color[] colors = { color(255), color(128), color(0), color(200, 0, 0), color(200, 200, 0), color(0, 200, 0), color(0, 0, 200), color(200, 0, 200) };
String[] color_names = { "white", "grey", "black", "red", "yellow", "green", "blue", "pink"};
PImage[] images = new PImage[32];
String[] names = new String[32];
void make_images() {
  int sx = 0;
  for ( int cx = 0; cx < colors.length; cx++) {
    color c = colors[cx];
    fill(64);
    stroke(196);
    rect(0, 0, 120, 80);
    fill(c);//0, 200, 0);
    noStroke();
    ellipse(60, 40, 70, 70);
    images[sx] = get(0, 0, 121, 81);
    names[sx] = color_names[cx] + " circle";
    sx++;

    fill(64);
    stroke(196);
    rect(0, 0, 120, 80);
    fill(c);//
    noStroke();
    rect(20, 15, 80, 50);
    images[sx] = get(0, 0, 121, 81);
    names[sx] = color_names[cx] + " rectangle";
    sx++;

    fill(64);
    stroke(196);
    rect(0, 0, 120, 80);
    fill(c);
    noStroke();
    pushMatrix();
    translate(60, 40);
    triangle(-20, 20, 0, -25, 20, 20);
    popMatrix();
    images[sx] = get(0, 0, 121, 81);
    names[sx] = color_names[cx] + " triangle";
    sx++;

    fill(64);
    stroke(196);
    rect(0, 0, 120, 80);
    fill(c);
    noStroke();
    rect(35, 15, 50, 50);
    images[sx] = get(0, 0, 121, 81);
    names[sx] = color_names[cx] + " square";
    sx++;
  }
}

int playing_state = 0;
int won_state = 1;
int lost_state = 2;
int state;
float[] xs = new float[6];
float[] ys = new float[6];
int score;
int total = -1;

Question q;

void setup() {
  size(600, 400);
  state = playing_state;
  make_images();
  xs[0] = xs[3] = width/4;
  xs[1] = xs[4] = width/2;
  xs[2] = xs[5] = 3*width/4;  
  ys[0] = ys[1] = ys[2] = 2*height/4;
  ys[3] = ys[4] = ys[5] = 3*height/4;

  new_question();
}

void new_question() {
  int rq = int(random(4));
  q = new Question("Click on the " + names[rq] + "!", rq);
  total++;
}


void draw() {
  background(0);
  q.draw();
  text( "Score: " + score + " / " + total, width/2, 70);
  
  //win_screen();
  //lost_screen();
}

void mousePressed() {
  q.click();
}

/*
void win_screen() {
  if ( state == won_state ) {
    background(0, 255, 0);
    fill(0);
    textSize(64);
    text("YOU WON!", width/2, height/2);
  }
}

void lost_screen() {
  if ( state == lost_state ) {
    background(255, 0, 0);
    fill(0);
    textSize(64);
    text("YOU LOST!", width/2, height/2);
  }
}
*/

I also made it ask more than one question, and track the score and total in this version.
If you want to add your menu and timer to this, that should be easy enough.


#40

Alright. You’re on your own now then. For everyone else, the lessons here are:

  1. Don’t try to get it all working at once.
  2. Your sketch can have states.
  3. Loops are useful! Use them.
  4. Objects are great! Use them too.

And the goal is to get your main functions’ code to be as simple as possible:

Question q;

void setup() {
  size(600, 400);
  make_images();
  set_positions();
  new_question();
}

void draw() {
  background(0);
  q.draw();
  text("Score: " + score + " / " + total, width/2, 70);
}

void mousePressed() {
  q.click();
}

// --- DO NOT SCROLL BEYOND THIS POINT ---

class AnswerChoice {
  float x, y, w, h;
  int i;
  boolean c;
  AnswerChoice(int position, int image, boolean correct_answer) {
    x = xs[position];
    y = ys[position];
    i = image;
    w = images[image].width;
    h = images[image].height;
    c = correct_answer;
  }
  void draw() {
    imageMode(CENTER);
    image(images[i], x, y);
  }
  boolean over() {
    return( x-w/2 < mouseX && mouseX < x+w/2 && y-h/2 < mouseY && mouseY < y+h/2 );
  }
  void click() {
    if ( over() ) {
      if ( c ) {
        score++;
        //state = won_state;
      } else {
        //state = lost_state;
      }
      new_question();
    }
  }
}

class Question {
  String s;
  AnswerChoice[] acs;
  Question(String questionText, int correctChoice ) {
    s = questionText;
    acs = new AnswerChoice[6];
    int correct_position = int(random(acs.length));
    for ( int ps = 0; ps < acs.length; ps++) {
      if ( ps == correct_position ) {
        acs[ps] = new AnswerChoice( ps, correctChoice, true );
      } else {
        int randoChoice = correctChoice;
        while ( randoChoice == correctChoice ) {
          randoChoice = int(random(images.length));
        }
        acs[ps] = new AnswerChoice( ps, randoChoice, false );
      }
    }
  }
  void draw() {
    fill(255);
    textAlign(CENTER);
    text(s, width/2, 40);
    // Draw all possible answers.
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].draw();
    }
  }
  void click() {
    for ( int ac = 0; ac < acs.length; ac++) {
      acs[ac].click();
    }
  }
}

color[] colors = { color(255), color(128), color(0), color(200, 0, 0), color(200, 200, 0), color(0, 200, 0), color(0, 0, 200), color(200, 0, 200) };
String[] color_names = { "white", "grey", "black", "red", "yellow", "green", "blue", "pink"};
PImage[] images = new PImage[32];
String[] names = new String[32];
void make_images() {
  int sx = 0;
  for ( int cx = 0; cx < colors.length; cx++) {
    color c = colors[cx];
    fill(64);
    stroke(196);
    rect(0, 0, 120, 80);
    fill(c);//0, 200, 0);
    noStroke();
    ellipse(60, 40, 70, 70);
    images[sx] = get(0, 0, 121, 81);
    names[sx] = color_names[cx] + " circle";
    sx++;

    fill(64);
    stroke(196);
    rect(0, 0, 120, 80);
    fill(c);//
    noStroke();
    rect(20, 15, 80, 50);
    images[sx] = get(0, 0, 121, 81);
    names[sx] = color_names[cx] + " rectangle";
    sx++;

    fill(64);
    stroke(196);
    rect(0, 0, 120, 80);
    fill(c);
    noStroke();
    pushMatrix();
    translate(60, 40);
    triangle(-20, 20, 0, -25, 20, 20);
    popMatrix();
    images[sx] = get(0, 0, 121, 81);
    names[sx] = color_names[cx] + " triangle";
    sx++;

    fill(64);
    stroke(196);
    rect(0, 0, 120, 80);
    fill(c);
    noStroke();
    rect(35, 15, 50, 50);
    images[sx] = get(0, 0, 121, 81);
    names[sx] = color_names[cx] + " square";
    sx++;
  }
}

float[] xs = new float[6];
float[] ys = new float[6];
int score;
int total = -1;

void new_question() {
  int rq = int(random(4));
  q = new Question("Click on the " + names[rq] + "!", rq);
  total++;
}

void set_positions() {
  xs[0] = xs[3] = width/4;
  xs[1] = xs[4] = width/2;
  xs[2] = xs[5] = 3*width/4;  
  ys[0] = ys[1] = ys[2] = 2*height/4;
  ys[3] = ys[4] = ys[5] = 3*height/4;
}