Quiz Game Tutorial & WalkthroughPer a couple requests, I've gone ahead and put together a very simple quiz game. Here's what the game does:
- Loads a welcome screen, with a button to start the game.
- Loads questions with 4 potential answers.
- Provides a simple scoring mechanism; 50 points for right answers, 50 points for wrong ones.
- Allows players a few seconds to answer questions, and gives a brief break between questions.
So, that's the basics of it. The source files are attached below.
Please note, this was coded in an afternoon, so there are some error messages that pop up, and some really bad code in the actual quiz itself! I'm going to update this thread once I rewrite the code...
Now I'm going to walk through some parts of the code. This is not the complete program, so to get the complete program please download the source code and run it. I'm just going to show off some of the highlights...
The header file:
#import <UIKit/UIKit.h>
@interface Quiz_GameViewController : UIViewController {
IBOutlet UILabel *theQuestion;
IBOutlet UILabel *theScore;
IBOutlet UILabel *theLives;
IBOutlet UIButton *answerOne;
IBOutlet UIButton *answerTwo;
IBOutlet UIButton *answerThree;
IBOutlet UIButton *answerFour;
NSInteger myScore;
NSInteger myLives;
NSInteger questionNumber;
NSInteger rightAnswer;
NSInteger time;
NSArray *theQuiz;
NSTimer *timer;
BOOL questionLive;
BOOL restartGame;
}
@property (retain, nonatomic) UILabel *theQuestion;
@property (retain, nonatomic) UILabel *theScore;
@property (retain, nonatomic) UILabel *theLives;
@property (retain, nonatomic) UIButton *answerOne;
@property (retain, nonatomic) UIButton *answerTwo;
@property (retain, nonatomic) UIButton *answerThree;
@property (retain, nonatomic) UIButton *answerFour;
@property (retain, nonatomic) NSArray *theQuiz;
@property (retain, nonatomic) NSTimer *timer;
-(IBAction)buttonOne;
-(IBAction)buttonTwo;
-(IBAction)buttonThree;
-(IBAction)buttonFour;
-(void)checkAnswer;
-(void)askQuestion;
-(void)updateScore;
-(void)loadQuiz;
-(void)countDown;
@end
One thing worth noting is that I created an IBOutlet for the buttons; this provides the ability to change the text on them so the answers will be "clickable". I figure that's a pretty straightforward way to program it. As you can see in the header I've initialized some variables like booleans and integers, and most importantly an array that we'll use to actually load the quiz itself.
In IB, there are 3 main labels: The question area, the "score" and the timer counter box (which, I labeled "lives" inadvertently thinking I was going to have a lives counter... just run with it).
So, now in the .m file, here are some of the notable functions...
(Please note, these are not in order as they appear in the code, so if you're looking at the source, you may have to scroll a little bit to find these things)viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
questionLive = NO;
restartGame = NO;
theQuestion.text = @\"Welcome to the Quiz Game! Think you're a pretty smart cookie, huh? Well, let's test your knowledge!\";
theScore.text = @\"Score:0\";
theLives.text = @\"\";
questionNumber = 0;
myScore = 0;
myLives = 0;
[answerOne setTitle:@\"Let's Play!\" forState:UIControlStateNormal];
[answerTwo setHidden:YES];
[answerThree setHidden:YES];
[answerFour setHidden:YES];
[self loadQuiz];
}
This is just the initialization of the app, but it has some notable activities which might be worth noticing. First off, we've established some values for some of the variables that we'll be using in the game, including questionLive (a boolean), the questionNumber, myScore, etc. myLives will likely be killed in the next iteration of the game, since I'm not using that feature. You'll see how a lot of these get used later on. One of the handy pieces of code that I've used is the [... setTitle:] and [... setHidden:] features for the buttons. The buttons are UIButtons with IBOutlets attached to them in the Interface Builder, so we can manipulate them to be visible or hidden, or change the content of their text label. There are several states that buttons can be in when you set the title, but for convenience sake I only really care about UIControlStateNormal. Press the escape key while you're typing the statement, and a popup will appear with all the options...
The loadQuiz function is pretty straightforward, but it's important to note that this is a TERRIBLE way to program this. It SHOULD be nested arrays based on a dictionary, but for the sake of just getting this done I put it all in a flat NSArray. This is the thing that I'll be updating when I update this program, probably to access an independent file from resources like a plist or a txt file. Stay tuned for that update.
The "game" itself is in the function askQuestion:
-(void)askQuestion
{
// Unhide all the answer buttons.
[answerOne setHidden:NO];
[answerTwo setHidden:NO];
[answerThree setHidden:NO];
[answerFour setHidden:NO];
// Set the game to a \"live\" question (for timer purposes)
questionLive = YES;
// Set the time for the timer
time = 8.0;
// Go to the next question
questionNumber = questionNumber + 1;
Here you can see some initialization features, such as un-hiding the buttons, setting the questionLive variable to "YES" so that the timer knows it's in a question (I'll explain that in a moment), setting the time for the timer (how long the player gets to answer the question, in this case 8 seconds), and updating the questionNumber to move to the next row.
// THIS IS REALLY TERRIBLE CODE!!!
// We get the question from the questionNumber * the row that we look up in the array.
// This is absolutely horrible, just a placeholder until the right way.
// I cannot even begin to describe how wrong this solution is.
NSInteger row = 0;
if(questionNumber == 1)
{
row = questionNumber - 1;
}
else
{
row = ((questionNumber - 1) * 6);
}
// Set the question string, and set the buttons the the answers
NSString *selected = [theQuiz objectAtIndex:row];
NSString *activeQuestion = [[NSString alloc] initWithFormat:@\"Question: %@\", selected];
[answerOne setTitle:[theQuiz objectAtIndex:row+1] forState:UIControlStateNormal];
[answerTwo setTitle:[theQuiz objectAtIndex:row+2] forState:UIControlStateNormal];
[answerThree setTitle:[theQuiz objectAtIndex:row+3] forState:UIControlStateNormal];
[answerFour setTitle:[theQuiz objectAtIndex:row+4] forState:UIControlStateNormal];
rightAnswer = [[theQuiz objectAtIndex:row+5] intValue];
// Set theQuestion label to the active question
theQuestion.text = activeQuestion;
// Start the timer for the countdown
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(countDown) userInfo:nil repeats:YES];
[selected release];
[activeQuestion release];
So all that stuff should be relatively self-explanatory if you just take a little while to look at it. Again, this is shameful programming (by skimming through a flat array to pull the question, answers, and right answer variables) but in short order it was what I came up with. Also, note the activation of the timer object, which uses the "countDown" function to warn the user of how much longer they have to answer the question.
Here's the code for -(IBAction)buttonOne function just so you see what's going on in there:
- (IBAction)buttonOne
{
if(questionNumber == 0){
// This means that we are at the startup-state
// We need to make the other buttons visible, and start the game.
[answerTwo setHidden:NO];
[answerThree setHidden:NO];
[answerFour setHidden:NO];
[self askQuestion];
}
else
{
NSInteger theAnswerValue = 1;
[self checkAnswer:(int)theAnswerValue];
if(restartGame==YES)
{
// Create a restart game function.
}
}
}
Note that since button 1 is being used both as an answer button and as the "Let's play" game starter, we have to have a conditional statement in there to change it from the start button to a normal answer statement, which we accomplish by finding out if we're on question #0. If it's a normal question (in the 'else' portion of the conditional, covering all other situations), we set up a variable called theAnswerValue, which is the button number that they pressed, and then send that value to the function checkAnswer. This is creating a warning message in the process, so I need to check my syntax to code it right (it will run, but with warning errors - nothing severe though).
... continued ...
Replies
checkAnswer is pretty straightforward:
Notice rightAnswer is set in the askQuestion function, and is being compared to the theAnswerValue that was passed from the button action function (depending on what button was pressed, 1-4). If it is a match, they got it right, and they get a plithy response and 50 points. If it's not a match, they got it wrong, get shamed, and lose 50 points.
Then we call updateScore function:
So, that's essentially the rest of the heavy lifting the the app. The countDown function is worth a look, since that's where the timer runs through, but I think if you take a look at the source you should get what I'm doing in there.
I welcome your questions about what I did, and I eagerly encourage any and all suggestions for improvements, enhancements, and coding short-cuts that I could have taken. Like I said, the main thing that I'm going to work on next is to change the method that the array is assembled (so we're using a series of multidimensional arrays to control questions, answers, etc); provide a mechanism to have variable question difficulty (and award variable points), and set it up so questions & answers will appear randomly. Also, I'd like to add a function to show the user the right answer when they get it wrong (or have that a setting that they can turn on or off).
Anyways, thanks for reading! Hope this was helpful. :)
Here's the link to the source: Quiz_Game.zip
Dave
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesomethanks Dave!!!
I will look over your codes as soon as i am off from the work (european time)!!!
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeezyTweet - $0.99
iZky - $0.99
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesome- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeezyTweet - $0.99
iZky - $0.99
- Spam
- Abuse
- Troll
1 • Off Topic Insightful Disagree Dislike 1Like AwesomeDave
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeAll this did was provide a quick way to create the array using a txt file called quizgame.txt moved in the 'Resources' group under "Groups & Files". Everything else in the code stays the same for now...
To explain what's going on in this function now:
1 - Create an instance of an NSBundle called bundle that we can use to access the file system. This way we don't need to actually write the exact path all the way to the root, this'll do it for us.
2 - Create a string called textFilePath which uses the bundle to create a string with the location of the file we're trying to access. Note that you don't need to include the extension when describing the file, but you do need to set it in the 'ofType'.
3 - Create a string called fileContents which contains the entire contents of the file. Worth noting, each line of the file will designate a new line in the array.
4 - Populate the array quizArray with the contents of the fileContents, using the method componentsSeparatedByString of @"\n" which means every line break means it's a new element in the array.
5 - Set theQuiz (our standing array of questions & answers) to quizArray and then...
... release quizArray
So that's about it. The only real hiccup that I had in testing this is that the text file cannot have an ending blank line in it, as if you were going to write out more content. It'll record that as a new line in the array, and the game-ending code will fry (because it'll think there are more questions & answers). The formatting is still the same: 1st line is the question, lines 2-5 are answers, and line 6 is the right answer. So the text file might look like this...
quizgame.txt:
So that's a quick upgrade to the code. Next, I'm trying to decide if I want to try to use a SQLite db or a plist file to actually break out these arrays in to something a little more meaningful (and add some new functionality in the process).
Dave
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeBut could you upload an example code ?
ezyTweet - $0.99
iZky - $0.99
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesome- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeDru, you should download the zip from the second post on this thread, change the function (void)loadQuiz to what I showed in the follow-up. Then create your own txt file of questions and answers, copy it to your project, and run the game. Should be literally that simple, since the main processes of the game haven't changed.
Dave
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeI studied a bit your quiz tutorial and now trying to make something similar but I desperately need your teaching!
I uploaded my files herehttp://www.jinweb.net/ferdi/iQQQ.zip, if u have time plz have a look and give me some directions how to move forward from here:o
Your game has 4 answers as buttons, but what i tried to do is basically to have a simple interface where the answers are all embedded in the question, and there are 4 fixed answer buttons A,B,C,and D.
Each time an answer is clicked (or Next button is clicked) the answer variable (ABCD) will be stored, and the next question will be displayed, and so on.
At the end, a table should show the list of questions (1.2.3...), selected answer (user selected) and correct answer (red if wrong), with a total percentage grade.
FIRST THING TO DO:
I have created three string variables and each contains a question.
now what i want to do is to have a loop function attached to button A,B,C, and D to store selected answer and move on to next question.
Any idea how i can do this?
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeThere's a few things that come to mind. First off, using the UIToolbar is different from using buttons... I haven't really played around with them much, but I think with a little searching you can find out how to trigger the action based upon what button the user presses (it's different from how buttons are treated, but not by much).
Regarding storing the information after you find out what someone pressed, I'd suggest glancing at this video tutorial: Welcome to the iPhone Development Central Website!
It covers NSMutableArray which is a modifiable array you can use to dynamically store your answers. I'm assuming that what you're trying to do is get a user to the end of the quiz before telling them how many they got right or wrong. That just means you'll need to do something simple at the end like:
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeMy problem is very banal, when I switch from intro view (clicking Start button), the main view is shown, but the toolbar's position is not where I see from Interface builder.
Intro View:
Main View:
What am I doing wrong? I also played with the size, position and autosizing, but no luck... also tried with other tools such as simple buttons (instead of toolbar), but the problem resists...
The code is here: http://www.jinweb.net/ferdi/iZZZ.zip
[SOLVED]: The size of the first view was : 480x300, and the second view was 460x320... don't know why, but I resized second view to 480x300 and resolved the problem :)
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesome- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeIf you do happen to cross that bridge, please post up your solution to help improve the overall tutorial!
Cheers,
Dave
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesome- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesome- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesome- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeI am trying to do a similar quiz app and wanted to put images to questions. For instance if its a sports question I would put a sports picture, music question pic of guitar, etc.
Could you perhaps give any guidance on this? I am thinking it would of course be another array with images loaded into it, however I am not sure how to tie the images to transition when the question was answered.
Any sort of help would be much appreciated!!
Thanks!
Shawn
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesome- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeI hace a question, how can I make Random Question Apear? I know how to create a random generator, but not to make it work with questions.
Thx
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeI started out with random in 'That Ain't It! Trivia Game', but eventually moved to keeping track of which questions were displayed because using random was causing repeat questions more often than we liked.
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeCan you upload a Sample Code? using the Quiz Game tutorial?
How do I create random number of questions?
Thx!
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesome- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like AwesomeBut thats not what I wanted to ask. I created a new button called endButton and set it to be the button to start the game and end it. I did this because I set my buttons to have a different layout and the start and end buttons look bad. So my problem is when ever i swich the button from this:
to:
and then hide answerOne the endButton does nothing. But when I unhide answerOne it still loads the quiz. What am I missing here? So it looks like this:
- (void)viewDidLoad {[super viewDidLoad];
questionLive = NO;
restartGame = NO;
theQuestion.text = @\"Welcome to the Quiz Game! Think you're a pretty smart cookie, huh? Well, let's test your knowledge!\";
theScore.text = @\"Score:0\";
theLives.text = @\"\";
questionNumber = 0;
myScore = 0;
myLives = 0;
[endButton setTitle:@\"Let's Play!\" forState:UIControlStateNormal];
[answerOne setHidden:YES];
[answerTwo setHidden:YES];
[answerThree setHidden:YES];
[answerFour setHidden:YES];
[self loadQuiz];
I've done all the connections and code i've needed to do that I know of. I hooked the button up in IB.
- Spam
- Abuse
- Troll
0 • Off Topic Insightful Disagree Dislike Like Awesome