In this article, we will make hangman game with JavaScript. Obviously, we will use some HTML and CSS for structure design purpose, but main work will be done in the JavaScript part. Nowadays, Hangman game is becoming popular and many of the developers making it in different languages. So let’s understand basic idea and goal about this game.
What is Hangman Game?
Hangman game is basically a word making game. In this game, we need to guess the correct alphabets, in order to make the correct word. If the guessed alphabet is correct, then black areas for word start to get filled, and you will get progression. And if the guessed alphabet is wrong, then a man start to hang, if the person hanged then you will lose the game. This is the basic idea and goal for this game is to guess the word before man gets hanged.
Pretty interesting project, right? So let’s make it step by step.
Pre-requisites to Make Hangman Game With JavaScript
- Basic knowledge of HTML.
- Basic knowledge of CSS.
- Good knowledge of JavaScript
Setting HTML Structure For The Game
For this project, we need to basically three files. First will be our index.html, in this we will add our elements, and you can simply say we will create the skeleton of the project using HTML file. Then for designing purpose we will be adding our style.css file, with this we will add some styles to our HTML, this is going to be purely based on you, like you can customize it any way. And lastly, our script.js file, this will be our main file because we will add list of words, button events, keyboard functionality etc. using the JavaScript file.
In HTML, we have added some links like Poppins font to use this font family in our project, we also added our style.css file to add custom styles to HTML elements. And at the end of the body we have added our JS file.
Now we have added a container <div>, in which we have option-container <div> to add options, then we have here letter container <div>, in which we will add our letters, as our keyboard. After that, we have added another <div> for the user input, in which we will add input using JavaScript. Here we have used canvas in which we will display hangman.
You can notice here, we didn’t actually do too much in our HTML like we didn’t even give other than <div> and button. So we will add the content dynamically using JavaScript to make it more interactive and good. We have added ID’s and classes with which we can access these elements to style and add functionality.
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hangman</title>
<!-- Google Fonts -->
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap"
rel="stylesheet"
/>
<!-- Stylesheet -->
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<div id="options-container"></div>
<div id="letter-container" class="letter-container hide"></div>
<div id="user-input-section"></div>
<canvas id="canvas"></canvas>
<div id="new-game-container" class="new-game-popup hide">
<div id="result-text"></div>
<button id="new-game-button">New Game</button>
</div>
</div>
<!-- Script -->
<script src="script.js"></script>
</body>
</html>
Setting up Configurable in JS
Now let’s add our JavaScript code to add functionalities, For that we have to add and fetch every required class in the JS, so we can apply functionalities on them. We have added some constants, in we have fetched letter-container, option-container, user-input-section, new-game-container, canvas, and finally result-text classes for each of the constants.
const letterContainer = document.getElementById("letter-container");
const optionsContainer = document.getElementById("options-container");
const userInputSection = document.getElementById("user-input-section");
const newGameContainer = document.getElementById("new-game-container");
const newGameButton = document.getElementById("new-game-button");
const canvas = document.getElementById("canvas");
const resultText = document.getElementById("result-text");
Adding Array of Words
Okay, here we just added some arrays like for fruits, animals, and countries. In these arrays, we have added some words which we are going to add for guessing. Basically, player need to guess these words.
let options = {
fruits: [
"Apple",
"Blueberry",
"Mandarin",
"Pineapple",
"Pomegranate",
"Watermelon",
],
animals: ["Hedgehog", "Rhinoceros", "Squirrel", "Panther", "Walrus", "Zebra"],
countries: [
"India",
"Hungary",
"Kyrgyzstan",
"Switzerland",
"Zimbabwe",
"Dominica",
],
};
Displaying Option Buttons
Now, we will add our option buttons, in this we have used innerHTML to display our <h3> tag in option-container class. Then we have created a <div> for the buttons, and we have added for loop, in which we looped the value till number of options. In this we have added a button for every option, here we have 3 options (fruits, animals, countries). In these buttons, we have added generateWord()
function, in this function, we will add functionalities later on. But for now, we will just fetch any of the word from the option. Lastly, we have appended this these options to the div.
const displayOptions = () => {
optionsContainer.innerHTML += `<h3>Please Select An Option</h3>`;
let buttonCon = document.createElement("div");
for (let value in options) {
buttonCon.innerHTML += `<button class="options" onclick="generateWord('${value}')">${value}</button>`;
}
optionsContainer.appendChild(buttonCon);
};
Generating The Word
After this, we will generate the word from the array. We will fetch the option class in which we have added the arrays. Now we will add a loop for these buttons, in this we are checking where button’s text is equals to optionvalue. If it matched with any of the button text then we will add class active to it. In active class we need to add some effect which will be done in CSS part. After this we will disable the button, so that it can’t be changed during the game.
Then we have to show the letter container or keyboard, for that we have remove hide class in which we have specified hide properties. And we have added userInputSection
to null string. After that, we need to choose the random word from option array, for that we have added a constant in which we have selected the array inputed by user using options[optionValue]
. We have used chosenWord = optionArray[Math.floor(Math.random() * optionArray.length)];
this line of code in to choose random word using array index.
Now we need user to guess word so that the word we need to replace with dashed(-). Also we have made this word to uppercase.
const generateWord = (optionValue) => {
let optionsButtons = document.querySelectorAll(".options");
//If optionValur matches the button innerText then highlight the button
optionsButtons.forEach((button) => {
if (button.innerText.toLowerCase() === optionValue) {
button.classList.add("active");
}
button.disabled = true;
//initially hide letters, clear previous word
letterContainer.classList.remove("hide");
userInputSection.innerText = "";
let optionArray = options[optionValue];
//choose random word
chosenWord = optionArray[Math.floor(Math.random() * optionArray.length)];
chosenWord = chosenWord.toUpperCase();
//replace every letter with span containing dash
let displayItem = chosenWord.replace(/./g, '<span class="dashes">_</span>');
//Display each element as span
userInputSection.innerHTML = displayItem;
});
Initializing The Game On Loading
Now we have added generation of the word, but we didn’t initialize the game, so let’s make it. For that we have added an initializer() function, in this we have added constants winCount
and count
with 0 value. Firstly, we have erased the all content and hid the letter container, new game container. Now for letter container we have looped, from 65 to 91 which is actually ASCII value for alphabets. In this loop, we have added a button for these letters, and we have used fromCharCode(i)
a method to make integer to letter.
Now we have added a click event listener, in which we have fetched the dash class, and replaced the dashed with letter when the letter will be in the word using this charArray.includes(button.innerText)
condition to check the letter in the word. We will increase the number of the winCount as soon as letter replace the dash.
We have lastly check if the word’s length is equals to winCount length, then we just print the message “you won”. Also, we will run blocker() function in which we will block the all buttons. Else, we will just increase increment the count value and call the drawMan
function which we will call add later, for now we will create the man in it which have total of 6 part. So if this function calls 6 times, then count also will be 6, which means man will be created completely., and we just print the message “you lose”.
Now we will call displayOption()
the show option, and again we will call the canvas function when we hit new game button or refresh the project.
//Initial Function (Called when page loads/user presses new game)
const initializer = () => {
winCount = 0;
count = 0;
//Initially erase all content and hide letteres and new game button
userInputSection.innerHTML = "";
optionsContainer.innerHTML = "";
letterContainer.classList.add("hide");
newGameContainer.classList.add("hide");
letterContainer.innerHTML = "";
//For creating letter buttons
for (let i = 65; i < 91; i++) {
let button = document.createElement("button");
button.classList.add("letters");
//Number to ASCII[A-Z]
button.innerText = String.fromCharCode(i);
//character button click
button.addEventListener("click", () => {
let charArray = chosenWord.split("");
let dashes = document.getElementsByClassName("dashes");
//if array contains clciked value replace the matched dash with letter else dram on canvas
if (charArray.includes(button.innerText)) {
charArray.forEach((char, index) => {
//if character in array is same as clicked button
if (char === button.innerText) {
//replace dash with letter
dashes[index].innerText = char;
//increment counter
winCount += 1;
//if winCount equals word lenfth
if (winCount == charArray.length) {
resultText.innerHTML = `<h2 class='win-msg'>You Win!!</h2><p>The word was <span>${chosenWord}</span></p>`;
//block all buttons
blocker();
}
}
});
} else {
//lose count
count += 1;
//for drawing man
drawMan(count);
//Count==6 because head,body,left arm, right arm,left leg,right leg
if (count == 6) {
resultText.innerHTML = `<h2 class='lose-msg'>You Lose!!</h2><p>The word was <span>${chosenWord}</span></p>`;
blocker();
}
}
//disable clicked button
button.disabled = true;
});
letterContainer.append(button);
}
displayOptions();
//Call to canvasCreator (for clearing previous canvas and creating initial canvas)
let { initialDrawing } = canvasCreator();
//initialDrawing would draw the frame
initialDrawing();
};
Adding Canvas
For the Canvas, we have added a constant context in which we have specified 2D context using canvas.getContext("2d")
method. To start drawing, we need to call beginPath()
method. Then we have added strokeStyle
, simply, the color of the line #000, and we have specified the width of the line of 2.
Now we have added drawLine()
, in which we have used to moveTo()
method to add starting point and lineTo()
method for ending point. We have applied stroke() method to paint these lines.
After that, we have added some functions of parts of the body, in which we have simply, called the drawLine()
with some specific pixels as an argument which will be helpful to create certain size of the parts. Then we have to initialize our canvas, for that we have cleared the canvas with this context.clearRect(0, 0, context.canvas.width, context.canvas.height);
line of code. And we have added some stroke to the border of the canvas.
//Canvas
const canvasCreator = () => {
let context = canvas.getContext("2d");
context.beginPath();
context.strokeStyle = "#000";
context.lineWidth = 2;
//For drawing lines
const drawLine = (fromX, fromY, toX, toY) => {
context.moveTo(fromX, fromY);
context.lineTo(toX, toY);
context.stroke();
};
const head = () => {
context.beginPath();
context.arc(70, 30, 10, 0, Math.PI * 2, true);
context.stroke();
};
const body = () => {
drawLine(70, 40, 70, 80);
};
const leftArm = () => {
drawLine(70, 50, 50, 70);
};
const rightArm = () => {
drawLine(70, 50, 90, 70);
};
const leftLeg = () => {
drawLine(70, 80, 50, 110);
};
const rightLeg = () => {
drawLine(70, 80, 90, 110);
};
//initial frame
const initialDrawing = () => {
//clear canvas
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
//bottom line
drawLine(10, 130, 130, 130);
//left line
drawLine(10, 10, 10, 131);
//top line
drawLine(10, 10, 70, 10);
//small top line
drawLine(70, 10, 70, 20);
};
return { initialDrawing, head, body, leftArm, rightArm, leftLeg, rightLeg };
};
Drawing The Man
For the man, we have called the canvasCreator()
in which we have created the parts of the man, this function was returning the man drawing, and we are just storing these in the constants. We have used here switch case with count reference, the count value was increasing when the guessing wrong letter. We will here call those function which are in canvasCreator()
to create body part.
const drawMan = (count) => {
let { head, body, leftArm, rightArm, leftLeg, rightLeg } = canvasCreator();
switch (count) {
case 1:
head();
break;
case 2:
body();
break;
case 3:
leftArm();
break;
case 4:
rightArm();
break;
case 5:
leftLeg();
break;
case 6:
rightLeg();
break;
default:
break;
}
};
newGameButton.addEventListener("click", initializer);
window.onload = initializer;
Lastly, we have added eventListener
to the new game button, in which we have called initializer()
function, and also we have called the function initializer when then window get loaded.
Adding Styles to The Project
Now we have made our project with added functionalities, but we can see all elements are still visible on the screen, and it doesn’t even look like a game as well. So we just need to add some CSS to make it more attractive and interactive. Let me just remind you real quick that this CSS is not necessary to copy and just pasting, you can add your own and cool CSS yourself. But you just have to hide some blocks and show them up on certain event. You can copy this CSS to get the same type of the effect, and we also provide you the download button to download this whole project.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
background-color: #f4c531;
}
.container {
font-size: 16px;
background-color: #ffffff;
width: 90vw;
max-width: 34em;
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
padding: 3em;
border-radius: 0.6em;
box-shadow: 0 1.2em 2.4em rgba(111, 85, 0, 0.25);
}
#options-container {
text-align: center;
}
#options-container div {
width: 100%;
display: flex;
justify-content: space-between;
margin: 1.2em 0 2.4em 0;
}
#options-container button {
padding: 0.6em 1.2em;
border: 3px solid #000000;
background-color: #ffffff;
color: #000000;
border-radius: 0.3em;
text-transform: capitalize;
}
#options-container button:disabled {
border: 3px solid #808080;
color: #808080;
background-color: #efefef;
}
#options-container button.active {
background-color: #f4c531;
border: 3px solid #000000;
color: #000000;
}
.letter-container {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.6em;
}
#letter-container button {
height: 2.4em;
width: 2.4em;
border-radius: 0.3em;
background-color: #ffffff;
}
.new-game-popup {
background-color: #ffffff;
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
border-radius: 0.6em;
}
#user-input-section {
display: flex;
justify-content: center;
font-size: 1.8em;
margin: 0.6em 0 1.2em 0;
}
canvas {
display: block;
margin: auto;
border: 1px solid #000000;
}
.hide {
display: none;
}
#result-text h2 {
font-size: 1.8em;
text-align: center;
}
#result-text p {
font-size: 1.25em;
margin: 1em 0 2em 0;
}
#result-text span {
font-weight: 600;
}
#new-game-button {
font-size: 1.25em;
padding: 0.5em 1em;
background-color: #f4c531;
border: 3px solid #000000;
color: #000000;
border-radius: 0.2em;
}
.win-msg {
color: #39d78d;
}
.lose-msg {
color: #fe5152;
}
Full Source Code of Hangman Game With JavaScript
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hangman</title>
<!-- Google Fonts -->
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap"
rel="stylesheet"
/>
<!-- Stylesheet -->
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<div id="options-container"></div>
<div id="letter-container" class="letter-container hide"></div>
<div id="user-input-section"></div>
<canvas id="canvas"></canvas>
<div id="new-game-container" class="new-game-popup hide">
<div id="result-text"></div>
<button id="new-game-button">New Game</button>
</div>
</div>
<!-- Script -->
<script src="script.js"></script>
</body>
</html>
style.css
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
background-color: #f4c531;
}
.container {
font-size: 16px;
background-color: #ffffff;
width: 90vw;
max-width: 34em;
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
padding: 3em;
border-radius: 0.6em;
box-shadow: 0 1.2em 2.4em rgba(111, 85, 0, 0.25);
}
#options-container {
text-align: center;
}
#options-container div {
width: 100%;
display: flex;
justify-content: space-between;
margin: 1.2em 0 2.4em 0;
}
#options-container button {
padding: 0.6em 1.2em;
border: 3px solid #000000;
background-color: #ffffff;
color: #000000;
border-radius: 0.3em;
text-transform: capitalize;
}
#options-container button:disabled {
border: 3px solid #808080;
color: #808080;
background-color: #efefef;
}
#options-container button.active {
background-color: #f4c531;
border: 3px solid #000000;
color: #000000;
}
.letter-container {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.6em;
}
#letter-container button {
height: 2.4em;
width: 2.4em;
border-radius: 0.3em;
background-color: #ffffff;
}
.new-game-popup {
background-color: #ffffff;
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
border-radius: 0.6em;
}
#user-input-section {
display: flex;
justify-content: center;
font-size: 1.8em;
margin: 0.6em 0 1.2em 0;
}
canvas {
display: block;
margin: auto;
border: 1px solid #000000;
}
.hide {
display: none;
}
#result-text h2 {
font-size: 1.8em;
text-align: center;
}
#result-text p {
font-size: 1.25em;
margin: 1em 0 2em 0;
}
#result-text span {
font-weight: 600;
}
#new-game-button {
font-size: 1.25em;
padding: 0.5em 1em;
background-color: #f4c531;
border: 3px solid #000000;
color: #000000;
border-radius: 0.2em;
}
.win-msg {
color: #39d78d;
}
.lose-msg {
color: #fe5152;
}
script.js
//Initial References
const letterContainer = document.getElementById("letter-container");
const optionsContainer = document.getElementById("options-container");
const userInputSection = document.getElementById("user-input-section");
const newGameContainer = document.getElementById("new-game-container");
const newGameButton = document.getElementById("new-game-button");
const canvas = document.getElementById("canvas");
const resultText = document.getElementById("result-text");
//Options values for buttons
let options = {
fruits: [
"Apple",
"Blueberry",
"Mandarin",
"Pineapple",
"Pomegranate",
"Watermelon",
],
animals: ["Hedgehog", "Rhinoceros", "Squirrel", "Panther", "Walrus", "Zebra"],
countries: [
"India",
"Hungary",
"Kyrgyzstan",
"Switzerland",
"Zimbabwe",
"Dominica",
],
};
//count
let winCount = 0;
let count = 0;
let chosenWord = "";
//Display option buttons
const displayOptions = () => {
optionsContainer.innerHTML += `<h3>Please Select An Option</h3>`;
let buttonCon = document.createElement("div");
for (let value in options) {
buttonCon.innerHTML += `<button class="options" onclick="generateWord('${value}')">${value}</button>`;
}
optionsContainer.appendChild(buttonCon);
};
//Block all the Buttons
const blocker = () => {
let optionsButtons = document.querySelectorAll(".options");
let letterButtons = document.querySelectorAll(".letters");
//disable all options
optionsButtons.forEach((button) => {
button.disabled = true;
});
//disable all letters
letterButtons.forEach((button) => {
button.disabled.true;
});
newGameContainer.classList.remove("hide");
};
//Word Generator
const generateWord = (optionValue) => {
let optionsButtons = document.querySelectorAll(".options");
//If optionValur matches the button innerText then highlight the button
optionsButtons.forEach((button) => {
if (button.innerText.toLowerCase() === optionValue) {
button.classList.add("active");
}
button.disabled = true;
});
//initially hide letters, clear previous word
letterContainer.classList.remove("hide");
userInputSection.innerText = "";
let optionArray = options[optionValue];
//choose random word
chosenWord = optionArray[Math.floor(Math.random() * optionArray.length)];
chosenWord = chosenWord.toUpperCase();
//replace every letter with span containing dash
let displayItem = chosenWord.replace(/./g, '<span class="dashes">_</span>');
//Display each element as span
userInputSection.innerHTML = displayItem;
};
//Initial Function (Called when page loads/user presses new game)
const initializer = () => {
winCount = 0;
count = 0;
//Initially erase all content and hide letteres and new game button
userInputSection.innerHTML = "";
optionsContainer.innerHTML = "";
letterContainer.classList.add("hide");
newGameContainer.classList.add("hide");
letterContainer.innerHTML = "";
//For creating letter buttons
for (let i = 65; i < 91; i++) {
let button = document.createElement("button");
button.classList.add("letters");
//Number to ASCII[A-Z]
button.innerText = String.fromCharCode(i);
//character button click
button.addEventListener("click", () => {
let charArray = chosenWord.split("");
let dashes = document.getElementsByClassName("dashes");
//if array contains clciked value replace the matched dash with letter else dram on canvas
if (charArray.includes(button.innerText)) {
charArray.forEach((char, index) => {
//if character in array is same as clicked button
if (char === button.innerText) {
//replace dash with letter
dashes[index].innerText = char;
//increment counter
winCount += 1;
//if winCount equals word lenfth
if (winCount == charArray.length) {
resultText.innerHTML = `<h2 class='win-msg'>You Win!!</h2><p>The word was <span>${chosenWord}</span></p>`;
//block all buttons
blocker();
}
}
});
} else {
//lose count
count += 1;
//for drawing man
drawMan(count);
//Count==6 because head,body,left arm, right arm,left leg,right leg
if (count == 6) {
resultText.innerHTML = `<h2 class='lose-msg'>You Lose!!</h2><p>The word was <span>${chosenWord}</span></p>`;
blocker();
}
}
//disable clicked button
button.disabled = true;
});
letterContainer.append(button);
}
displayOptions();
//Call to canvasCreator (for clearing previous canvas and creating initial canvas)
let { initialDrawing } = canvasCreator();
//initialDrawing would draw the frame
initialDrawing();
};
//Canvas
const canvasCreator = () => {
let context = canvas.getContext("2d");
context.beginPath();
context.strokeStyle = "#000";
context.lineWidth = 2;
//For drawing lines
const drawLine = (fromX, fromY, toX, toY) => {
context.moveTo(fromX, fromY);
context.lineTo(toX, toY);
context.stroke();
};
const head = () => {
context.beginPath();
context.arc(70, 30, 10, 0, Math.PI * 2, true);
context.stroke();
};
const body = () => {
drawLine(70, 40, 70, 80);
};
const leftArm = () => {
drawLine(70, 50, 50, 70);
};
const rightArm = () => {
drawLine(70, 50, 90, 70);
};
const leftLeg = () => {
drawLine(70, 80, 50, 110);
};
const rightLeg = () => {
drawLine(70, 80, 90, 110);
};
//initial frame
const initialDrawing = () => {
//clear canvas
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
//bottom line
drawLine(10, 130, 130, 130);
//left line
drawLine(10, 10, 10, 131);
//top line
drawLine(10, 10, 70, 10);
//small top line
drawLine(70, 10, 70, 20);
};
return { initialDrawing, head, body, leftArm, rightArm, leftLeg, rightLeg };
};
//draw the man
const drawMan = (count) => {
let { head, body, leftArm, rightArm, leftLeg, rightLeg } = canvasCreator();
switch (count) {
case 1:
head();
break;
case 2:
body();
break;
case 3:
leftArm();
break;
case 4:
rightArm();
break;
case 5:
leftLeg();
break;
case 6:
rightLeg();
break;
default:
break;
}
};
//New Game
newGameButton.addEventListener("click", initializer);
window.onload = initializer;
Check out video reference here: