JavaScript Catch the Fish Game
Tags: javascript, beginners, programming, tutorial
Published: 2024-06-06 11:20:30

**Intro:** A small game inspired by a chapter of the Foundation Game Design with HTML5 and JavaScript Book by Rex van der Spuy. I've commented on each line so it's basically for complete beginners.

**Game Demo:**[https://youtube.com/shorts/hYimZgPLHcA?feature=share](https://youtube.com/shorts/hYimZgPLHcA?feature=share)

**Note:** You can use this code to create your version of games. I drew the pictures of the fish, hook, dynamite and background myself on Microsoft Paint.

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="catch_fish.css">
  <title></title>
</head>
<body>
	<div id="game">
	<h1>Catch the Fish</h1>
	<div id="stage">
	<div id="background"></div>
	<div class="box" id="fish"></div>
	<div class="box" id="dynamite"></div>
	<div id="hook"></div>
	<div id="explosion"></div>
	</div>
	<br>
	<br>
	<p id="output">Enter the X and Y position (0–300), then click fire.</p>
	<input id="inputX" type="text" placeholder="X...">
	<input id="inputY" type="text" placeholder="Y...">
	<button>Catch!</button>
	</div>
	<script src="catch_fish.js"></script>
</body>
</html>
```

```css
*
{
	font-family: sans-serif;
	text-align: center;
}

p{
	font-weight: bold;
	font-size: 22px;
	margin: 0px, auto;
}

input, button{
	font-size: 18px;
}

#game
{
	margin: 0px auto;
	width: 600px;
	height: 630px;
	padding: 15px;
	border: black;
	background: lightblue;
	box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
	border-radius: 10px;
}


#stage
{
	width: 400px;
	height: 400px;
	margin: 0px auto;
	position: relative;
	border-color: blue;
	text-align: center;
}

.box{
	position: absolute;
	height: 100px;
	width: 100px;
	margin: 5px;
}

#background
{
	width: 520px;
	height: 430px;
	left: -55px;
	position: absolute;
	background-image: url('C:/Users/petix/OneDrive/Desktop//my_javascript_games/catch_fish/background.png');
}


#dynamite
{
	width: 60px;
	height: 60px;
	background-image: url('C:/Users/petix/OneDrive/Desktop/my_javascript_games/catch_fish/dynamite.png');
}

#hook
{
	width: 40px;
	height: 40px;
	top: 380px;
	left: 160px;
	position: absolute;
	background-image: url('C:/Users/petix/OneDrive/Desktop/my_javascript_games/catch_fish/hook.png');
}

#fish
{
	width: 80px;
	height: 50px;
	top: 70px;
	left: 100px;
	background-image: url('C:/Users/petix/OneDrive/Desktop//my_javascript_games/catch_fish/fish.png');
}

#explosion
{
	display: block;
	width: 60px;
	height: 60px;
	background-image: url('C:/Users/petix/OneDrive/Desktop/my_javascript_games/catch_fish/explosion.png');
}
```

```javascript
//Game variables
//the position of the fish on the horizontal axis 
var fishX = Math.floor(Math.random() * 350);
//the position of the fish on the vertical axis 
var fishY = Math.floor(Math.random() * 100);
//the players input for the horizontal axis
var guessX = 0;
//the players input for the vertical axis
var guessY = 0;
//the amount of chances the player has
var shotsRemaining = 3;
//the amount of chances the player used
var shotsMade = 0;
//message to tell the player the game state
var gameState = "";
//whether the game is won or not
var gameWon = false;
//whether the hook is destroyed or not
var hookDestroyed = false;
//the spa
var tolerance = 10;


//The game objects the html
//access the div ids on  
var hook = document.querySelector("#hook");
var explosion = document.querySelector("#explosion");
var fish = document.querySelector("#fish");
var dynamite = document.querySelector("#dynamite");

//The input and output fields
var inputX = document.querySelector("#inputX");
var inputY = document.querySelector("#inputY");
var output = document.querySelector("#output");

//The button
var button = document.querySelector("button");
button.style.cursor = "pointer";
button.addEventListener("click", clickHandler, false);

//Add 50 to fishY and dynamiteY to stop them 
//from going out the background
fishY = fishY + 50;

//Position the fish when the game starts
fish.style.left = fishX + "px";
fish.style.top = fishY + "px";

//Position the dynamite when the game starts
//the offsets are there to stop the fish div
//and the dynamite div from overlapping each other
var dynamiteX = fish.offsetLeft + fishX;
var dynamiteY = (fish.offsetTop + fish.offsetHeight + 30);

//this if-else statement is to stop the dynamite from
//going out of the background when the game starts
if(dynamiteX > 400){
	console.log("higher than 400");
	dynamiteX = dynamiteX - 350;
	dynamite.style.left = dynamiteX + 'px';
	dynamite.style.top = dynamiteY + 'px';
}else{
	dynamite.style.left = dynamiteX + 'px';
	dynamite.style.top = dynamiteY + 'px';
}

//this to print on the console
//this is optional 
x = dynamite.style.left;
y = dynamite.style.top;
console.log(x);
console.log(y);
console.log(fishX);
console.log(fishY);


//repositions the dynamite and fish
//whenever the button is clicked
function render(){
	//Position the fish
	fish.style.left = fishX + "px";
	fish.style.top = fishY + "px";

	//Position the hook
	hook.style.left = guessX + "px";
	hook.style.top = guessY + "px";
	
	if(gameWon){
		//remove the fish and hook
		fish.style.display = "none";
		hook.style.display = "none";
		
	}
}

//the button function to call the 
//validateInput()
function clickHandler(){
	validateInput();
}

//this functions checks the input of the 
//player
function validateInput(){
	//changes the string input into numbers
	guessX = parseInt(inputX.value);
	guessY = parseInt(inputY.value);

	//if input is not a number then display bottom message
	if(isNaN(guessX) || isNaN(guessY)){
		output.innerHTML = "Please enter a number.";
	}
	//if both inputs are more than 400 then display message
	else if(guessX > 400 || guessY > 400){
		output.innerHTML = "Please enter a number less than 400";
	}
	//if the Y input is less than 50 then display message
	else if(guessY < 50){
		output.innerHTML = "For Y, enter a number more than 50";
	}
	//if all above are not the case then call playGame() functionqqq
	else{
		playGame()
	}
}

function playGame(){
	//decrease the value of shotRemaining by 1
	shotsRemaining = shotsRemaining - 1;
	//increase the value of shotsMade by 1
	shotsMade = shotsMade + 1;
	//the variable gameState gets this message
	gameState = " Shots: " + shotsMade + ", Remaining: " + shotsRemaining;
	//the variable guessX gets the players inputX value turned to integer
	guessX = parseInt(inputX.value);
	//the variable guessY gets the players inputX value turned to integer
	guessY = parseInt(inputY.value);
	//Find out whether the player's x and y guesses are inside
	//The fish's area
	
	//this if statement checks if the player's guess is within the fish div
	//horizontal range
	if(guessX >= (fishX - tolerance) && guessX <= (fishX + 20 + tolerance))
	{
		//Yes, it's within the X range, so now let's
		//check the Y range

		//this if statement checks if the player's guess is within the fish div
		//vertical range
		if(guessY >= (fishY - tolerance) && guessY <= fishY + 20 + tolerance)
		{
			//It's in both the X and Y range, so it's a hit!
			gameWon = true;
			endGame();
		}
	//this if statement checks if the player's guess is within the dynamite div
	//horizontal range
	} else if(guessX >= (dynamiteX - tolerance) && guessX <= (dynamiteX + 20 + tolerance))
	{
		//Yes, it's within the X range, so now let's
		//check the Y range

		//this if statement checks if the player's guess is within the fish div
		//vertical range
		if(guessY >= (dynamiteY -  tolerance) && guessY <= (dynamiteY + 20 + tolerance))
		{
			//It's in both the X and Y range, so it's a hit!
			hookDestroyed = true;
			
			//remove the dynamite from the game
			dynamite.style.display = 'none';
			
			//display the explosion in the dynamite position
			explosion.style.display = "block";
			explosion.style.position = "absolute";
			explosion.style.left = dynamiteX + "px";
			explosion.style.top = dynamiteY + "px";
			endGame();
			
		}
	}
	//if the hook is out of the dynamite and the hook
	//range
	else{
		output.innerHTML = "Miss!" + gameState;

		//set a timer
		setTimeout(() => {
			//the hook moves back to its original position
			//after 300 miliseconds
			hook.style.top = 380 + "px";
			hook.style.left = 160 + "px";
		}, 300);
		
		//if the value of shotsRemaining is zero
		if (shotsRemaining < 1)
		{
			//then call endGame() function
			endGame();
		}	
	}
	//Update the alien's position if the
	//game hasn't yet been won
	if(!gameWon)
	{
		//Update the fish's X position
		fishX = Math.floor(Math.random() * 300);
		fishY = Math.floor(Math.random() * 300);
		
		fishY += 50;
		}
		
	//Render the new game state
	render();
	//console.log("X: " + alienX);
	//console.log("Y: " + alienY);
}	

//this function checks whether the game is won
function endGame(){
	//if the game is won
	if(gameWon){
		//if the value of shotsMade is less than 2
		//display this message
		if(shotsMade < 2){
			output.innerHTML = "Hooray! You caught the fish!" + "<br>"
			 + "It only took you " + shotsMade + " shot.";
		}
		//this is for aesthetic purposes. It's not necessary
		else{
			output.innerHTML = "Hooray! You caught the fish!" + "<br>"
					 + "It only took you " + shotsMade + " tries.";
		}
	} 
	//if the hook is destroyed by the dynamite
	//display this message
	else if(hookDestroyed){
		output.innerHTML = "Boom!! You hit a dynamite!" + "<br>"
						+ "Your hook is destroyed. :("
	}
	//if the game is lost and the hook is not destroyed
	//display this message
	else{
		output.innerHTML = "You lost!" + "<br>"
		+ "The fish got away!";
		}
		
	//Disable the button
	button.removeEventListener("click", clickHandler, false);
	button.disabled = true;
	
	//Disable the enter key 
	//window.removeEventListener("keydown", keydownHandler, false);
	
	//Disable the input fields
	inputY.disabled = true;
	inputX.disabled = true;
	
	//hide hook and fish
	hook.style.display = "none";
	fish.style.display = "none";
}
```