This site requires JavaScript, please enable it in your browser!
Greenfoot back
Omniscience
Omniscience wrote ...

2012/4/21

...what am I doing wrong? :(

1
2
Omniscience Omniscience

2012/4/21

#
So anyway I have a class called QuestionWriter, which I add to the world under certain conditions; this class happens to contain the code that displays actual questions on the screen. Once the player has submitted an answer, I remove the QuestionWriter class., and the questions along with it. These questions are loaded from a .csv file and stored in a 2d array in the QuestionWriter class, using the algorithm below:
FileReader questionFile = new FileReader("Questions Log.csv"); 
        BufferedReader readQuestions = new BufferedReader(questionFile); 
        for (count = 0; count < maxQuestions; count++) {
            // read in the file, one line at a time  
            lineNo = readQuestions.readLine(); // reads a Line into 'line'  
            if (lineNo == null)  {
                break; // if no lines left exit for loop  
            }
            for (field = 0; field < 5; field++) // break the line down, one field at a time  
            {  
                if (lineNo.indexOf(',') < 0) {
                    break; // if no seperators left, exit for loop (only one field left) 
                }   
                data[count][field] = lineNo.substring(0, lineNo.indexOf(',')); // save first field of line  
                lineNo = lineNo.substring(lineNo.indexOf(',') + 1); // remove first field from line  
            }  
            data[count][field] = lineNo; // save last field of line  
        }  
        questionCount = count; // save total questions read in...  
        sort(data); //don't worry about this part- it does its job!
}
The problem is trying to display the next question after the first question has been removed from the world. I always seem to get the same question appearing, though the code should go to the next row of the array, thus displaying a new question. Note how instance increases, but still no row change:
//in the World
public void displayQuestions () { 
        try {
            addObject(questionWriter, 241, 267);
            questionWriter.generateQuestion();
            instance++; //swop to next question for next time...
        }
        catch (java.io.IOException h){ 
            System.out.println ("Failed to Load Questions :(");
        }
    }

//in QuestionWriter.class
public void generateQuestion () throws IOException {
        //the code below assigns each part of the array containing the questions to a variable.
        question = data[Level.instance][0]; //originally set to zero.
        optionA = data[Level.instance][1];
        optionB = data[Level.instance][2];
        optionC = data[Level.instance][3];
        optionD = data[Level.instance][4];
        actualAnswer = data[Level.instance][5];

        //the code below adds the classes that appear as the the question and options to the user.
        getWorld().addObject(opt1, 169, 251);
        getWorld().addObject(opt2, 342,251);
        getWorld().addObject(opt3, 169, 320);
        getWorld().addObject(opt4, 342, 320);
        getWorld().addObject(mathsQuestion, 236, 173);
    }
Can anyone tell me what I've done wrong, because to my understanding if Level.instance increases, the row of the array should increase to, changing the question that is displayed. Thanks again for all feedback!
danpost danpost

2012/4/21

#
Things that I made note of: 1) QuestionWriter always reads the same file into its data array every time an instance of it is created. 2) 'static int instance' is a world 'Level' variable 3) 'String data' is in the QuestionWriter class (not sure if 'static' or not) 4) there is duplication of data with OptionA thru OptionD, question, and actualAnswer My suggestions are: Create the QuestionWriter class object once through the world constructor and have the QuestionWriter constructor read the file in through its constructor (once and for all). Have QuestionWriter put the information read in a 'static String data' variable in the world 'Level' class. Also have the 'int questionCount' variable moved to the world 'Level' class. Move the generateQuestion() method to the world 'Level' class without the exception clause and without the variable assignments (and without the 'getWorld()'s). It will, for now, just be 4 addObject statements. Once you have done this much, let your opt1, opt2, opt3, opt4, and mathsQuestion objects use 'Level.data' to determine the data to display. Hopefully, that will simplify things enough to solve any issues.
Omniscience Omniscience

2012/4/21

#
I must say I agree with you- I need to make one instance once and for all... if I did something like this:
//in the World (Level)
public static int instance = 0; 
int questionCount = 0;
public static String [][] data = new String [maxQuestions][6];

private void prepare() {
QuestionWriter q = new QuestionWriter(); //made only once.
...
}

public void act() {
if(whatever condition is met) {
generateQuestion();
}
}

private void generateQuestion () {
addObject(q,x,y); 
addObject(option1,x,y); 
//[i]and so on...[/i]
instance++; 
questionCount++;
}

//in QuestionWriter class.
public QuestionWriter() {
//read in algorithm that you helped me design. [i]Thanks for that by the way![/i]
data[row][col] = lineNo; //where data[][] has been defined (as static) in the world...
}

//within the "opt1" classes 
GreenfootImage optImage = new GreenfootImage... //blank image to draw on to

public OptionOne() {
//set image colour
//set the blank image.
}

private void displayOption() {
if(questionPresent == true) //this is just some boolean I've got in the world (Level)
String text = data[Level.instance][1] //as this item is in the 1st position of the row.
//set font
//set font colour 
//set background colour 
//set image 
}
danpost danpost

2012/4/21

#
The QuestionWriter class should have the code you posted at the front of this discussion, except for the following: Line 14 should start 'Level.dataimport greenfoot.*; import java.util.List; public class Option extends Actor { static int selected = 0; int optionNumber = 0; String txt = ""; public Option(int num) { optionNumber = num; txt = Level.data; updateImage(); } public void act() { if (Greenfoot.mouseClicked(this)) selected = optionNumber; updateAllImages(); } private static void updateAllImages() { List<Option> options = (List<Option>) getWorld().getObjects(Option.class); for (Option option : options) updateImage(); } private void updateImage() { // code to create image here // use 'txt', and 'if (selected == optionNumber)' to help modify image } public static int getSelected() { return selected; } } With the above class, we can create and add the options to the world with
Option.selected = 0;
for (int opt = 0; opt < 4; opt++)
{
    addObject(new Option(opt + 1), 342 - 173 * (opt % 2), 320 - 69 * (opt - (opt % 2)) / 2);
}
Omniscience Omniscience

2012/4/21

#
One question... what do the lines 17-20 do? Where does mouseClicked come into it more specifically?
danpost danpost

2012/4/21

#
I thought maybe you would want the user to click on an option to select it. So, this will set 'selected' to the 'optionNumber' of the Option class object clicked on.
Omniscience Omniscience

2012/4/21

#
So essentially the code above will add display the question and the options, but the user will then click on an option to submit it? If so, that will be a great improvement to the way that I'm currently doing it!
Omniscience Omniscience

2012/4/22

#
Hey danpost! Thanks for all this by the way- I've still got this annoying problem where the questions don't change. I'm starting to think that maybe the options are responsible? And um, the code that you've written above... the only bit I still can't figure out is where I pass the parameters for the option constructor in the first place...
danpost danpost

2012/4/22

#
My last 5-liner supplied has the constructor call with the parameter included. It would replace some of your code in your generateQuestion method in the world class. Line 10 of the Option class code is the beginning of the Option constructor that recieves the parameter.
Omniscience Omniscience

2012/4/22

#
Okay! So I've run the code- but I get this message for line 25: "Non-static method getWorld() can not be accessed from a static context". This is because getWorld is called in a public static method right?
danpost danpost

2012/4/22

#
You are so right! I guess we will have to keep track of the options as well. Add another variable to the Option class 'private static Option options = new Option;'. Insert at line 14 'options = this;' and remove line 25 (the problem line).
Omniscience Omniscience

2012/4/22

#
Thanks! I swapped this- but now I faced with a similar problem. To create the image as you said in line 31, use setImage();
int fontSize = 30;  
        Color textColor = Color.WHITE;  
        Color bgColor = new Color(0, 0, 0, 0); //Transparent.  
        setImage(new GreenfootImage(txt, fontSize, textColor, bgColor));
How do I set the image of the options from a static context? Is there a trick to it?
danpost danpost

2012/4/22

#
Line 31 is NOT is a static method. That method is an object method (not a class method). You should have no problem creating the image of an option here.
Omniscience Omniscience

2012/4/22

#
Don't worry about that... I fixed it! And by the way, the options now change! The biggest concern now is that the question (which is always the 0th item in the rows of data) does not match up with the options... firstly, is it possible to incorporate this array item into the code above? Secondarily, the options are displayed on the screen in reverse order... so the option 1 is plopped in option 4's place, and option 2 is plopped in option 3's place, and so on. Is this just a logic error in line 4 of the world's part of the code?
danpost danpost

2012/4/22

#
Just add a sixth line to the 5-liner 'addObject(mathsQuestion, 236, 173);'. I do not see where mathsQuestion get initialized, or what class name you gave that type of object. But the constructor (if that class only displays mathsQuestion objects) can use 'Level.data' for its text.
There are more replies on the next page.
1
2