Create A Quiz Game

Author: Theodore Odeluga

The source files for this project can be downloaded from here

Before I got into computers, I was (and still am) a massive film fanatic. Let's build a quiz testing our knowledge of some of the most successful films of the last 50 years.

Let's start with the folder structure. Create a folder named 'app'. Inside the 'app' folder, set up additional folders: 'css', 'jquery', 'js' and 'json'.

Outside this folder structure, create an empty file named 'index.html'.

Although jQuery and JSON are all part of the JavaScript family, I thought it'd be easier to organise the project with separate folders for each of the different forms of JavaScript. The latest version of jQuery can be downloaded from here. We'll be using jquery.min - the 'minified' version of the library.

Now we have our folders prepared and dependencies in place, let's move on to the HTML, to build our app's interface.

Copy, paste and save the code below into 'index.html'.

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Movie Quiz</title>

<!--javascript-->
<script src = "jquery/jquery.min.js"></script>
<script src = "json/questions.json"></script>
<script src = "json/answers.json"></script>
<script src = "js/get-questions-and-answers.js"></script>
<script src = "js/multiplechoice.js"></script>

<!--css-->
<link rel="stylesheet" type="text/css" href="css/quiz.css">
</head>

<body>
<div id = "question_text"></div>
<div id = "question_panel"></div>
<div id = "message"></div>
<div id = "finalscore"></div>
<div id = "option1"></div>
<div id = "option2"></div>
<div id = "option3"></div>
<div id = "next"><b>NEXT</b></div>
</body>
</html>

To style our HTML, we'll need some CSS. Open up the 'css' folder and create a new file inside it - 'quiz.css'.

Place and save the following code in quiz.css.

#question_text{
position:absolute;
color: white;
font-family:Arial;
font-weight:bold;
font-size:4.5vw;
text-shadow: 2px 2px 4px #000000;
background:opacity: 0;
}

#question_panel{
background-image: linear-gradient(to right, grey , white);
padding: 20px;
}

#option1,#option2,#option3,#next,#quit
{
border-radius: 27px;
color: white;
font-family:Arial;
font-weight:bold;
font-size:3.3vw;
border-color: white;
border-style: solid;
background-color:black;
padding: 20px;
}

#option1{
margin-top:7.2%;
}

#option2{
margin-top:1%;
}

#option3{
margin-top:1%;
}

#next{
margin-top:1%;
}

#message {
margin-top:12%;
margin-left:30%;
color: white;
font-family:Arial;
font-weight:bold;
font-size:9vw;
text-shadow: 2px 2px 4px #000000;
background:opacity: 0;
position:absolute;
display:none;
}

#finalscore {
margin-top:1%;
margin-left:24%;
color: white;
font-family:Arial;
font-weight:bold;
font-size:4.2vw;
text-shadow: 2px 2px 4px #000000;
background:opacity: 0;
position:absolute;
display:none;
}

@media (orientation: landscape) {
#question_text{
font-size:3vw;
}
}

body{
background-image: linear-gradient(to right, grey , white);
}

The 'question_text' element is styled with white coloured text and a drop-shadow effect to create a 3D look. It's background has been made completely transparent by its opacity property being set to zero.

The 'question_panel' element is styled identically to the main page and so blends into the background. This element is a placeholder for positioning 'question_text' (I like the overall effect - against the black and white background, everything looks like the opening titles to some classic 1940's movie).

All multiple choice buttons, along with the control to advance to the next question are also styled identically, creating a uniform appearance. The first button in the list is positioned at vertically 7% down from the top of the visible window area, with all subsequent buttons spaced apart equally at 1% each on the vertical axis. Each button has a padding of 20 pixels to provide an additional bit of sorrounding space.

'Message' and 'finalscore' are almost stylistically the same, apart from differences in their output text and positioning.

The media query instructs mobile devices to render the text at 3% of the viewport width when users turn their smartphones or digital tablets horizontally to view the app in landscape mode.

Ok, so now we have an interface but we still don't have any functionality, so we can't get a sense of how the app actually works. Let's change that now.

Open up the 'js' folder and create a file in it called 'get-questions-and-answers.js'.

Open up this file, then copy, paste and save the following code.

let questiontxt;
let randomoption;
let randomanswer;
let opt1view;
let opt2view;
let opt3view;
let nextq = -1;
let score = 0;
let chosenoption = 0;
let correct = 0;
let endofquiz = 19;
let mymessage;
let a = -1;

function QuestionsAndAnswers(){

nextq++;
a++;
correct = 0;

questiontxt = document.getElementById("question_text");
questiontxt.innerHTML = QuestionList[nextq].question.qtext;

randomoption = Math.ceil(Math.random()*2);
randomanswer = Math.ceil(Math.random()*2);

opt1view = document.getElementById("option1");
opt2view = document.getElementById("option2");
opt3view = document.getElementById("option3");

opt1view.innerHTML = ' ' + optionone[randomoption] + ' ';
opt2view.innerHTML = ' ' + optiontwo[randomoption] + ' ';
opt3view.innerHTML = ' ' + optionthree[randomoption] + ' ';

switch(randomanswer){

case 0:
opt1view.innerHTML = AnswerList[a].answer.atext;
correct = 1;
break;

case 1:
opt2view.innerHTML = AnswerList[a].answer.atext;
correct = 2;
break;

case 2:
opt3view.innerHTML = AnswerList[a].answer.atext;
correct = 3;
break;
}
}

function NotificationMessage(){
$(function(){
$("#message").fadeIn();
});

$(function(){
$("#message").fadeOut(1500);
});
}

function checkAnswer(){

if(chosenoption == correct){
score++;
mymessage = document.getElementById("message");
mymessage.innerHTML = "Correct!";
NotificationMessage();
}

if(chosenoption != correct){
mymessage = document.getElementById("message");
mymessage.innerHTML = "Sorry, that is incorrect.";
NotificationMessage();
}

if(chosenoption == correct && nextq == endofquiz){
finalscore.innerHTML = "Your final score is:" + " " + score;
$("#finalscore").fadeIn();
}

if(chosenoption != correct && nextq == endofquiz){
finalscore.innerHTML = "Your final score is:" + " " + score;
$("#finalscore").fadeIn();
}
}

$(document).ready(function(){
$("#next").on("click",function(event){
NextMultipleChoice();
QuestionsAndAnswers();
});
});

$(document).ready(function(){
$("#option1").on("click",function(event){
chosenoption = 1;
checkAnswer();
});
});

$(document).ready(function(){
$("#option2").on("click",function(event){
chosenoption = 2;
checkAnswer();
});
});

$(document).ready(function(){
$("#option3").on("click",function(event){
chosenoption = 3;
checkAnswer();
});
});

First all the programs variables are initialised. Then comes 'QuestionsAndAnswers', the largest function in the file.

At the start of its definition, the 'nextq' and 'a' variables are incremented simultaneously. This keeps each subsequent question and answer in sync, as both are extracted from 'questions.json' and 'answers.json' respectively.

The 'correct' variable, initialised at zero, acts as a flag whose output is displayed by the 'message' element, communicating to the user when they've got an answer right or wrong.

Next, a new document object is declared - 'questiontxt'. 'questiontxt' uses the document classes getElementById method to grab 'question_text' (referencing it as a string through its single parameter).

As a result, given that 'question_text' is a div object, 'questiontxt' can use the innerHTML method to insert data from the 'questions.json' file via the QuestionList object into question_text.

To pull out this data, we use dot notation to traverse the object heirarchy of questions.json and target the 'qtext' field directly. In the process, QuestionList is treated as an array and 'nextq' becomes the iterator counting through its elements.

After this, we initialise two random variables 'randomoption' and 'randomanswer'.

Three instances of randomoption are created for each of the multiplechoice buttons. These instances randomly select elements from each array associated with a multiple choice. This happens every time the user clicks the next button, and its done to keep the quiz interesting by displaying slightly different multiple choices every time its played.

Before the user selects one of the multiple choices, the answer is taken first from answers.json using the AnswerList object and then placed in a random position among the multiple choices by 'randomanswer'.

Again, the answer is selected in a similar way to the way we've used JSON before, by processing the answers.json object AnswerList as an array.

Once the user makes a choice for their answer, NotificationMessage accesses the 'message' div with jQuery syntax to display the result (correct or incorrect).

The actual calling of NotificationMessage is done by the checkAnswer function, which of course as it's name implies, first ascertains if the selected option is correct by accessing the 'correct' variable.

If right, the 'score' variable is incremented by 1. If not, the document object 'mymessage' uses innerHTML to display the appropriate message.

If the 'nextq' variable is equal in value to the 'endofquiz' flag, checkAnswer finally displays the player's score in 'finalscore'.

To see all this in action, we need to populate both JSON files and 'multiplechoice.js', so let's do that.

Copy, paste and save the code for questions.json...

var QuestionList = [
{
"question": {
"qtext":"The Exorcist (1973) - Who played the possessed girl?",
}
},
{
"question": {
"qtext":"American Graffiti (1973) - Who directed this film?",
}
},
{
"question": {
"qtext":"Jaws (1975) - Who wrote the novel this film was based on?",
}
},
{
"question": {
"qtext":"Rocky (1976) - Who wrote the screenplay?",
}
},
{
"question": {
"qtext":"The Omen (1976) - Which actor played Ambassador Thorn?",
}
},
{
"question": {
"qtext":"Saturday Night Fever (1977) - Which band created the soundtrack?",
}
},
{
"question": {
"qtext":"Star Wars (1977) - When was it first released in the US?",
}
},
{
"question": {
"qtext":"Close Encounters of the Third Kind (1977) - Who created the SFX?",
}
},
{
"question": {
"qtext":"Grease (1978) - Who starred alongside John Travolta?",
}
},
{
"question": {
"qtext":"Superman the Movie (1978) - Who played Lois Lane?",
}
},
{
"question": {
"qtext":"Alien (1979) - Who composed the music?",
}
},
{
"question": {
"qtext":"Raiders of the Lost Ark (1981) - Who played Belloq?",
}
},
{
"question": {
"qtext":"ET - The Extraterrestrial (1982) - Who wrote the screenplay?",
}
},
{
"question": {
"qtext":"Ghostbusters (1984) - Who created the soundtrack?",
}
},
{
"question": {
"qtext":"Jurassic Park (1993) - Where was this film shot?",
}
},
{
"question": {
"qtext":"Titanic (1997) - Who played Captain J. Smith?",
}
},
{
"question": {
"qtext":"Harry Potter and the Philosophers Stone (2001) - Who wrote the original novel?",
}
},
{
"question": {
"qtext":"Lord of the Rings - Fellowship of the Ring (2001) - Who co-produced this film?",
}
},
{
"question": {
"qtext":"The Dark Knight (2008) - Who directed this film?",
}
},
{
"question": {
"qtext":"Avatar (2009) - Which studio distributed this film?",
}
},
]

Then do the same with answers.json...

var AnswerList = [
{
"answer": {
"atext":"Linda Blair",
}
},
{
"answer": {
"atext":"George Lucas",
}
},
{
"answer": {
"atext":"Peter Benchley",
}
},
{
"answer": {
"atext":"Sylvester Stallone",
}
},
{
"answer": {
"atext":"Gregory Peck",
}
},
{
"answer": {
"atext":"The Bee Gees",
}
},
{
"answer": {
"atext":"May 25th 1977",
}
},
{
"answer": {
"atext":"Douglas Trumbull",
}
},
{
"answer": {
"atext":"Olivia Newton John",
}
},
{
"answer": {
"atext":"Margot Kidder",
}
},
{
"answer": {
"atext":"Jerry Goldsmith",
}
},
{
"answer": {
"atext":"Paul Freeman",
}
},
{
"answer": {
"atext":"Melissa Mathison",
}
},
{
"answer": {
"atext":"Ray Parker Jnr",
}
},
{
"answer": {
"atext":"Hawaii",
}
},
{
"answer": {
"atext":"Bernard Hill",
}
},
{
"answer": {
"atext":"JK Rowling",
}
},
{
"answer": {
"atext":"Peter Jackson",
}
},
{
"answer": {
"atext":"Christopher Nolan",
}
},
{
"answer": {
"atext":"Twentieth Century Fox",
}
},
]

...and finally populate 'multiplechoice.js' with the following.

let optionone;
let optiontwo;
let optionthree;
let q = -1;

function NextMultipleChoice(){

q++;

switch(q){

case 0:
optionone = new Array('Jodie Foster','Brooke Shields','Kim Richards');
optiontwo = new Array('Quinn Cummings','Danielle Brisebois','Harvey Stephens');
optionthree = new Array('Dana Plato','Eve Plumb','Susan Olsen');
break;

case 1:
optionone = new Array('Brian de Palma','Martin Scorsese','Richard Donner');
optiontwo = new Array('Steven Spielberg','John Landis','Richard Attenborough');
optionthree = new Array('William Friedkin','Francis Ford Coppola','Robert Altman');
break;

case 2:
optionone = new Array('Richard Bach','Erich Segal','John Barth');
optiontwo = new Array('James Dickey','Robert Stone','Thomas Pynchon');
optionthree = new Array('Saul Bellow','John Updike','Kurt Vonnegut');
break;

case 3:
optionone = new Array('Robert Towne','Francis Ford Coppola','William Goldman');
optiontwo = new Array('Charlie Kaufman','Woody Allen','Ernest Lehman');
optionthree = new Array('Paul Schrader','Oliver Stone','Paddy Cheyefsky');
break;

case 4:
optionone = new Array('Laurence Olivier','Richard Burton','Peter OToole');
optiontwo = new Array('Jon Voight','Gig Young','Jack Nicholson');
optionthree = new Array('Rupert Crosse','Elliot Gould','Dustin Hoffman');
break;

case 5:
optionone = new Array('Chic','Abba','KC and the Sunshine Band');
optiontwo = new Array('Kool and the Gang','Heatwave','Earth,Wind and Fire');
optionthree = new Array('Sister Sledge','The Trammps','Lipps inc.');
break;

case 6:
optionone = new Array('Jan 25th 1976','Feb 1978','July 1980');
optiontwo = new Array('July 16th 1977','August 25th 1977','10th May 1977');
optionthree = new Array('7th May 1977','14th December 1977','1st December 1978');
break;

case 7:
optionone = new Array('Digital Domain','ILM','London Computer Company');
optiontwo = new Array('Tom Savini','John Dykstra','Brian Johnston');
optionthree = new Array('Ralph McQuarrie','Phil Tippett','Sony Digital');
break;

case 8:
optionone = new Array('Helen Ross','Kate Bush','Nico');
optiontwo = new Array('Brenda Lee','Gayle Crawford','Gloria Estefan');
optionthree = new Array('Debbie Harry','Cher','Stevie Nicks');
break;

case 9:
optionone = new Array('Diane Keaton','Carrie Fisher','Romy Schneider');
optiontwo = new Array('Liv Ullman','Ellen Burstyn','Faye Dunaway');
optionthree = new Array('Talia Shire','Madeline Kahn','Geraldine Chaplin');
break;

case 10:
optionone = new Array('George Gershwin','Nino Rota','Roy Budd');
optiontwo = new Array('Bill Conti','Krzysztof Penderecki','Bernard Herrmann');
optionthree = new Array('Elmer Bernstein','Ennio Morricone','John Barry');
break;

case 11:
optionone = new Array('Kenneth Branagh','Michael Caine','Daniel Day-Lewis');
optiontwo = new Array('Denholm Elliot','Rupert Everett','David Farrar');
optionthree = new Array('Roger Moore','Charles Dance','Malcom McDowell');
break;

case 12:
optionone = new Array('Sofia Coppola','Callie Khouri','Olivia Hetreed');
optiontwo = new Array('Kirsten Smith','Abi Morgan','Jane Goldman');
optionthree = new Array('Shonda Rhimes','Diana Ossana','Jane Campion');
break;

case 13:
optionone = new Array('Michael Jackson','David Bowie','Kool Moe Dee');
optiontwo = new Array('Nick Cave','Barry White','Ray Charles');
optionthree = new Array('Eddie Murphy','Prince','Tina Turner');
break;

case 14:
optionone = new Array('Texas','Nevada','Colorado');
optiontwo = new Array('California','Wyoming','Florida');
optionthree = new Array('Goa','Ibiza','Japan');
break;

case 15:
optionone = new Array('Alan Rickman','Paul Freeman','Charles Dance');
optiontwo = new Array('Richard Attenborough','Ian McKellen','Bill Paxton');
optionthree = new Array('David Warner','Anthony Hopkins','John Hurt');
break;

case 16:
optionone = new Array('Joan Aitken','Kate Atkinson','Hilary Bailey');
optiontwo = new Array('Beryl Bainbridge','Nina Bawden','Maeve Binchy');
optionthree = new Array('A.S Bayatt','Jenny Diski','Helen Dunmore');
break;

case 17:
optionone = new Array('Wes Anderson','Steven Spielberg','George Lucas');
optiontwo = new Array('David Lynch','Christopher Nolan','Steven Soderbergh');
optionthree = new Array('Ridley Scott','Roland Emmerich','David Fincher');
break;

case 18:
optionone = new Array('Jonathan Glazer','Ben Wheatley','Guy Ritchie');
optiontwo = new Array('Danny Boyle','Kenneth Branagh','Ridley Scott');
optionthree = new Array('Shane Meadows','Tom Hooper','Sam Mendes');
break;

case 19:
optionone = new Array('Universal','Columbia','Dreamworks');
optiontwo = new Array('Sony Pictures','Warner','Walt Disney');
optionthree = new Array('Paramount','Lionsgate','The Weinstein Company');
break;

}
}

If you open 'index.html' now and hit the 'next' button, you'll be able to start the quiz.

Conclusion

The great thing about this template is that you can use it with any content. So if you fancy creating a quiz on another favourite subject, this will be a useful starting point. I hope you've enjoyed the tutorial. I'll be back soon with more material as soon as I can. In the meantime, happy coding.