16 KiB
Creating a game using events
Pre-Lecture Quiz
Event driven programming
When building a browser-based application, we provide a graphical user interface (GUI) for users to interact with. The most common ways users interact with the browser are by clicking and typing in various elements. The challenge for us as developers is that we don’t know when they’ll perform these actions!
Event-driven programming is the type of programming we use to create our GUI. If we break this term down, the key word here is event. According to Merriam-Webster, an event is "something which happens." This perfectly describes our situation. We know something will happen that we want to respond to with code, but we don’t know when it will occur.
To specify the code we want to execute, we create a function. In procedural programming, functions are called in a specific order. This is also true in event-driven programming, but the difference lies in how the functions are called.
To handle events (like button clicks or typing), we register event listeners. An event listener is a function that waits for an event to occur and executes in response. Event listeners can update the UI, make server calls, or perform any other necessary actions based on the user’s input. We add an event listener using addEventListener and provide a function to execute.
NOTE: There are many ways to create event listeners. You can use anonymous functions or create named ones. You can also use shortcuts, like setting the
click
property, or useaddEventListener
. In this exercise, we’ll focus onaddEventListener
and anonymous functions, as this is one of the most common techniques used by web developers. It’s also the most flexible, asaddEventListener
works for all events, and the event name can be passed as a parameter.
Common events
There are dozens of events you can listen to when building an application. Essentially, anything a user does on a page triggers an event, giving you a lot of power to create the desired user experience. Fortunately, you’ll typically only need a small subset of these events. Here are a few common ones (including the two we’ll use for our game):
- click: Triggered when the user clicks on something, usually a button or hyperlink.
- contextmenu: Triggered when the user right-clicks.
- select: Triggered when the user highlights text.
- input: Triggered when the user types text.
Creating the game
We’re going to create a game to explore how events work in JavaScript. Our game will test a player’s typing skills, which is one of the most underrated skills every developer should practice. The general flow of the game will be:
- The player clicks a start button and is presented with a quote to type.
- The player types the quote as quickly as possible in a textbox.
- As each word is completed, the next one is highlighted.
- If the player makes a typo, the textbox turns red.
- When the player completes the quote, a success message is displayed along with the elapsed time.
Let’s build the game and learn about events!
File structure
We’ll need three files: index.html, script.js, and style.css. Let’s set them up to make things easier.
- Create a new folder for your work by opening a console or terminal and running the following command:
# Linux or macOS
mkdir typing-game && cd typing-game
# Windows
md typing-game && cd typing-game
- Open Visual Studio Code:
code .
- Add three files to the folder in Visual Studio Code with the following names:
- index.html
- script.js
- style.css
Create the user interface
Based on the requirements, we know we’ll need a few elements on our HTML page. Think of this as a recipe where we need specific ingredients:
- A place to display the quote for the user to type.
- A place to display messages, like a success message.
- A textbox for typing.
- A start button.
Each of these elements will need IDs so we can interact with them in JavaScript. We’ll also add references to the CSS and JavaScript files we’re creating.
Create a new file named index.html and add the following HTML:
<!-- inside index.html -->
<html>
<head>
<title>Typing game</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Typing game!</h1>
<p>Practice your typing skills with a quote from Sherlock Holmes. Click **start** to begin!</p>
<p id="quote"></p> <!-- This will display our quote -->
<p id="message"></p> <!-- This will display any status messages -->
<div>
<input type="text" aria-label="current word" id="typed-value" /> <!-- The textbox for typing -->
<button type="button" id="start">Start</button> <!-- To start the game -->
</div>
<script src="script.js"></script>
</body>
</html>
Launch the application
It’s always a good idea to develop iteratively and check how things look. Let’s launch our application. There’s a great Visual Studio Code extension called Live Server that hosts your application locally and refreshes the browser whenever you save.
- Install Live Server by clicking Install on the linked page.
- Your browser will prompt you to open Visual Studio Code, and Visual Studio Code will prompt you to install the extension.
- Restart Visual Studio Code if prompted.
- Once installed, press Ctrl-Shift-P (or Cmd-Shift-P) in Visual Studio Code to open the command palette.
- Type Live Server: Open with Live Server.
- Live Server will start hosting your application.
- Open a browser and navigate to https://localhost:5500.
- You should now see the page you created!
Let’s add some functionality.
Add the CSS
With the HTML in place, let’s add CSS for basic styling. We’ll highlight the word the player should type and change the textbox color if the player types incorrectly. We’ll do this using two classes.
Create a new file named style.css and add the following syntax:
/* inside style.css */
.highlight {
background-color: yellow;
}
.error {
background-color: lightcoral;
border: red;
}
✅ Feel free to customize the CSS to make the page more visually appealing:
- Choose a different font.
- Add colors to the headers.
- Adjust the sizes of elements.
JavaScript
With the UI ready, let’s focus on the JavaScript logic. We’ll break this into a few steps:
First, create a new file named script.js.
Add the constants
We’ll need a few constants to simplify our programming. Think of these as the ingredients for our recipe:
- An array containing all the quotes.
- An empty array to store the words of the current quote.
- A variable to track the index of the word the player is typing.
- A variable to store the time when the player clicked start.
We’ll also need references to the UI elements:
- The textbox (typed-value).
- The quote display (quote).
- The message display (message).
// inside script.js
// all of our quotes
const quotes = [
'When you have eliminated the impossible, whatever remains, however improbable, must be the truth.',
'There is nothing more deceptive than an obvious fact.',
'I ought to know by this time that when a fact appears to be opposed to a long train of deductions it invariably proves to be capable of bearing some other interpretation.',
'I never make exceptions. An exception disproves the rule.',
'What one man can invent another can discover.',
'Nothing clears up a case so much as stating it to another person.',
'Education never ends, Watson. It is a series of lessons, with the greatest for the last.',
];
// store the list of words and the index of the word the player is currently typing
let words = [];
let wordIndex = 0;
// the starting time
let startTime = Date.now();
// page elements
const quoteElement = document.getElementById('quote');
const messageElement = document.getElementById('message');
const typedValueElement = document.getElementById('typed-value');
✅ Add more quotes to make your game more interesting.
NOTE: While we can retrieve elements in code using
document.getElementById
, we’ll use constants to avoid typos when referencing these elements repeatedly. Frameworks like Vue.js or React can help centralize your code for better management.
Take a moment to watch a video about using const
, let
, and var
:
🎥 Click the image above to watch the video.
Add start logic
The game begins when the player clicks the start button. Since we don’t know when they’ll click it, we’ll use an event listener. This listener will execute code when the user clicks start.
When the user clicks start, we’ll select a quote, set up the UI, and initialize tracking for the current word and timing. Add the following JavaScript, and we’ll explain it afterward:
// at the end of script.js
document.getElementById('start').addEventListener('click', () => {
// get a quote
const quoteIndex = Math.floor(Math.random() * quotes.length);
const quote = quotes[quoteIndex];
// Put the quote into an array of words
words = quote.split(' ');
// reset the word index for tracking
wordIndex = 0;
// UI updates
// Create an array of span elements so we can set a class
const spanWords = words.map(function(word) { return `<span>${word} </span>`});
// Convert into string and set as innerHTML on quote display
quoteElement.innerHTML = spanWords.join('');
// Highlight the first word
quoteElement.childNodes[0].className = 'highlight';
// Clear any prior messages
messageElement.innerText = '';
// Setup the textbox
// Clear the textbox
typedValueElement.value = '';
// set focus
typedValueElement.focus();
// set the event handler
// Start the timer
startTime = new Date().getTime();
});
Here’s what the code does:
- Word tracking setup:
- Use Math.floor and Math.random to randomly select a quote from the
quotes
array. - Convert the
quote
into an array ofwords
to track the player’s progress. - Set
wordIndex
to 0, as the player starts with the first word.
- Use Math.floor and Math.random to randomly select a quote from the
- UI setup:
- Create an array of
spanWords
, where each word is wrapped in aspan
element for highlighting. - Use
join
to create a string and update theinnerHTML
ofquoteElement
to display the quote. - Highlight the first word by setting its
className
tohighlight
. - Clear the
messageElement
by setting itsinnerText
to an empty string.
- Create an array of
- Textbox setup:
- Clear the
value
oftypedValueElement
. - Set focus to
typedValueElement
.
- Clear the
- Start the timer: Call
getTime
.
Add typing logic
As the player types, an input
event is triggered. This event listener will check if the player is typing correctly and handle the game’s current state. Add the following code to the end of script.js, and we’ll explain it afterward:
// at the end of script.js
typedValueElement.addEventListener('input', () => {
// Get the current word
const currentWord = words[wordIndex];
// get the current value
const typedValue = typedValueElement.value;
if (typedValue === currentWord && wordIndex === words.length - 1) {
// end of sentence
// Display success
const elapsedTime = new Date().getTime() - startTime;
const message = `CONGRATULATIONS! You finished in ${elapsedTime / 1000} seconds.`;
messageElement.innerText = message;
} else if (typedValue.endsWith(' ') && typedValue.trim() === currentWord) {
// end of word
// clear the typedValueElement for the new word
typedValueElement.value = '';
// move to the next word
wordIndex++;
// reset the class name for all elements in quote
for (const wordElement of quoteElement.childNodes) {
wordElement.className = '';
}
// highlight the new word
quoteElement.childNodes[wordIndex].className = 'highlight';
} else if (currentWord.startsWith(typedValue)) {
// currently correct
// highlight the next word
typedValueElement.className = '';
} else {
// error state
typedValueElement.className = 'error';
}
});
Here’s what the code does:
- Quote completion: If
typedValue
matchescurrentWord
andwordIndex
is the last word inwords
:- Calculate
elapsedTime
by subtractingstartTime
from the current time. - Convert
elapsedTime
from milliseconds to seconds. - Display a success message.
- Calculate
- Word completion: If
typedValue
ends with a space and matchescurrentWord
:- Clear the
value
oftypedElement
for the next word. - Increment
wordIndex
to move to the next word. - Reset the
className
of allchildNodes
inquoteElement
to default. - Highlight the next word by setting its
className
tohighlight
.
- Clear the
- Correct typing: If
currentWord
starts withtypedValue
:- Clear the
className
oftypedValueElement
to display it normally.
- Clear the
- Error: If none of the above conditions are met:
- Set the
className
oftypedValueElement
toerror
.
- Set the
Test your application
You’ve reached the end! The final step is to test your application. Try it out! Don’t worry if there are errors—all developers encounter them. Read the error messages and debug as needed.
Click start and begin typing! It should look similar to the animation shown earlier.
🚀 Challenge
Add more features:
- Disable the
input
event listener when the game is complete, and re-enable it when the button is clicked. - Disable the textbox after the player completes the quote.
- Display a modal dialog box with the success message.
- Save high scores using localStorage
Post-Lecture Quiz
Review & Self Study
Learn about all the events available to developers through the web browser, and think about situations where each one would be useful.
Assignment
Disclaimer:
This document has been translated using the AI translation service Co-op Translator. While we aim for accuracy, please note that automated translations may include errors or inaccuracies. The original document in its native language should be regarded as the authoritative source. For critical information, professional human translation is advised. We are not responsible for any misunderstandings or misinterpretations resulting from the use of this translation.