Quiz with XML need help

Hi all, I am new to both coding and this forum so sorry in advance for whatever errors I am probably already making. For context, for this project, we were provided with a code skeleton. Right now I am having trouble figuring out how to move from one question to the next. The pieces are there, I just don’t know how to put them together and it’s driving me a little crazy. Should I be using cases or I have a feeling some kind of loop would probably be best? Not sure how much code is necessary but below are the two main tabs. I’d truly appreciate any help you all could provide.

ArrayList<Question> questions;
ArrayList<Answer> answers;
int state = 0; //game state
int activeQuestion = 0; //which question id is active
int score = 0;
int titleH;
boolean answered = false;
PFont ubu;
color c1 = #4EEE94;
color c2 = #68C7D4;
color c3 = #FFCC00;

XML data;

void setup(){
  size(640, 640);
  titleH = height/2 - 100;
  loadData();
  ubu = createFont("Ubuntu-Medium.ttf", 30);
}

void draw(){
  background(c2);
  switch(state){
    case 0:
      startScreen();
      break;
    case 1:
      game();
      break;
    case 2:
      endScreen();
      break;
  }
}


//Create array lists of objects and load external data
void loadData(){
  data = loadXML("QuizGame.xml");
  
  questions = new ArrayList();
  answers = new ArrayList();
  
  XML[] qnas = data.getChildren("qna");
  
  for(int i = 0; i < qnas.length; i++){
    String qt = qnas[i].getChild("qText").getContent();
    String at = qnas[i].getChild("aText").getContent();
    int id = qnas[i].getInt("id");
    int score = qnas[i].getChild("aText").getInt("score");
    String possAnsS = qnas[i].getChild("possAns").getString("pA");
    String[] possAns = split(possAnsS, ',');
    String cA = qnas[i].getChild("aText").getString("cA");
    
    PImage img = loadImage(qnas[i].getChild("qText").getString("img"));
 
    Question q = new Question(qt, id, score, img);
    Answer a = new Answer(at, id, score, img, possAns, cA);
    
    questions.add(q);
    answers.add(a);
    
  }
  
}

void mouseClicked(){
  if(overStart){
    state = 1; //move to the game state
 
  //check the multiple choice buttons for clicks
  for(int i = 0; i < overMulti.length; i++){
    if(overMulti[i]){
      questions.get(activeQuestion).guess = answers.get(activeQuestion).possAns[i];
      answered = true;
      //THIS IS WHERE THE USER ANSWERS 
    }
  }
}
}

boolean overStart = false;
boolean overCont = false;
boolean overSubmit = false;
boolean[] overMulti = {false, false, false, false};

void startScreen(){
  
  //Display title
  textAlign(CENTER);
  textSize(36);
  textFont(ubu);
  fill(255);
  text("Fun Fact Trivia!", width/2, titleH);
  
  //Start button
  noStroke();
  overStart = button(width/2, height/2, 150, 75, "START");
      if((mouseX>width/2) && (mouseX<width/2 + 150) && (mouseY>height/2) && (mouseY<height/2+75)) { 
        //fill(c1); 
        println("fill");
    } else { 
        //fill(c3); 
        println("fill2");
    }
    
  //Score and Q# displayed
  scoreAndQN();
  //if(.correctAns == true score ++);
  //else()
}

void game(){
  
  //Active question and answer objects
  Question q = questions.get(activeQuestion);
  Answer a = answers.get(activeQuestion);
  
  //Display img
  q.displayImage(width/4,height/4);
  
  //Display text
  q.displayText();
  
  //Display multiple choice buttons
  for(int i = 0; i < a.possAns.length; i++){ 
    
    //fill(c1);
    overMulti[i] = button(width/2, height/2+90*i, 150, 75, a.possAns[i]);
     if((mouseX>width/2) && (mouseX<width/2 + 150) && (mouseY>height/2+90*i) && (mouseY<height/2+90*i+75)) { 
         fill(c1); 
         //println("yes");
  } else { 
         fill(c3); 
         //println("unlucky");
    }
  }
  
  if(answered){
    q.checkAnswer();
  }
  
  //Score and Q# displayed
  scoreAndQN();
}

void feedbackScreen() {
  overCont = button(550, 550, 150, 75, "Continue");
  fill(0);
  //if correct play this sound, if not, play this sound or show check or x
}

void endScreen(){
  //display score somehow
}

void scoreAndQN(){
  textSize(28);
  fill(255);
  text("Score: "+score, width-100, 40);
  text("Question: "+activeQuestion, 100, 40);
}

boolean button(int x, int y, int w, int h, String s){
  rect(x-w/2,y-h/2,w,h);
  textSize(28);
  text(s, x, y+10);
  
 if((mouseX>x-w/2) && (mouseX<x-w/2 + w) && (mouseY>y-h/2) && (mouseY<y-h/2+y)) { 
    //println("over");
    return true;  
  } else { 
    //println("not over");
    return false; 
  }
}
  
1 Like

no, in draw(), no new case is needed

Instead activeQuestion is the index that tells which question to show.

after a question say activeQuestion++; answered = false;

1 Like

Hi Chrisir,

seriously thank you so much for your help!! I am making some progress here. However, now my code only has the user move to the next question when it is answered correctly. How would I have it go to an intermediate screen (regardless of if it was answered correctly) that could provide feedback on whether or not the question was answered correctly? Then I could just have a next question button I assume?

my guess is that the variable answered has this purpose:

when it’s true, provide feedback on whether or not the question was answered correctly

see in function game():

  if(answered){
    q.checkAnswer();
  }
  

Okay, some more progress. I can now click through the quiz and there is an intermediate screen (I added another case for this). How can I display on that intermediate screen ‘correct’ or ‘incorrect’? Because it would obviously depend on if they got it right or not.

1 Like

It seems that this function shows this screen.

I guess here the answer is checked.

You have not shown the Question class

I also assume that the answer is stored in variable guess in the class

You are totally right! The answer is stored in the question class in this bit of code below. Both correct and incorrect return the state to the feedbackScreen. In English, I would want code that would basically say if the correct answer is selected display ‘correct!’ and if incorrect answer selected display ‘incorrect!’. In code, what would this look like? Could I add an if() statement or boolean underneath (like in place of just println()) that would say if this true, display “correct”, and under false do the same but with false? Thanks again for your continued help with this code, I really appreciate it.

void checkAnswer(){
    if(this.guess.equals(answers.get(activeQuestion).correctAns)){
      println("true");
      state = 2;
    }
    else{
      println("false");
      state = 2;
    }
  }

is called from game() throughout (so maybe no new state needed? But new state is also okay)

Try using text(“Correct”, …) instead of println

when checkAnswer() is called throughout in the new state, fine.

Okay, wait I have two questions for you. Firstly, the bottom three answer buttons are colored how I want them to be colored. They have white text, c1 as the standard fill, and c3 on hover. However, the top answer box does not follow the same rules as the other three. It gets its fill from this code I believe which is in the question class. How do I make it behave like the other buttons? Secondly, while trying to find the root of the previous problem with displaying correct or incorrect, I noticed the quiz questions are skipping one every time. Like it asks question id 0, id 2, id 4, etc. But not the other questions. Why could that be happening?

void displayText(){
    //All formatting for text here
    fill(255); 
    textSize(36);
    text(text, width/2, titleH);
  }

Apart from the question, did you make Progress otherwise…?

Search fill command
Chrisir

Sorry, I’m confused. If I was unclear I can elaborate and or provide more information/code. I have not made much progress really.

Search fill command in the code

The lines you posted just are the text color, not the color for the sorrounding box / button

Idea

maybe place

overMulti[i] = button(width/2, height/2+90*i, 150, 75, a.possAns[i]);

after the else??

Chrisir

That helped still not working exactly how I want it to but its progress and I can figure it out from here I think. To go back to a previous question, what do you think could be the cause of the game to skip every other question?

1 Like

this should be the relevant variable

What do you mean? Is it not right now, or like what is?

the change of the question is done by incrementing the var activeQuestion

Therefore you have to read /search every occurance of activeQuestion.

somewhere you increment it twice where one time is enough

The error is related to activeQuestion

activeQuestion is used as an index for the ArrayLists

for example here:

 if(this.guess.equals(answers.get(activeQuestion).correctAns)){
1 Like

Aha, I understand now! I found the mistake. That was really helpful. I also need to make a scoring system, and its already partially built-in. In the XML each question already has a score attached to it, I am loading the score in void loadData, and in the Quizgame superclass score is set as a variable. How would I add the score up? Each question is worth 10 points. I am assuming I should put this code underneath the code below. Because I only want this to run if the question was answered correctly. Maybe something along the lines of score += ? would I create a new variable for total score?

void checkAnswer(){
    if(this.guess.equals(answers.get(activeQuestion).correctAns)){
1 Like

I think by now you should have enough experience to answer this yourself

hint: just test it in the code

Ahh fingers crossed, thank you SO MUCH for your help.

as you can see in loadData() the score is part of each answer in the arraylist

just search score (search function, ctrl-f)

see void scoreAndQN()

and there is one line //if(.correctAns == true score ++);

it’s commented out

but could be something like this:

  if( questions.get(activeQuestion).correctAns == true) 
            score++;