A simple game (intervals, listeners, arrow functions)
Click on the sub-window below. Move with the Arrow keys. Avoid the blue squares. Points increase each time an opponent is generated. Open the game in a different window if you'd like.
Intervals are used to repeatedly execute a function at specified time intervals, allowing us to schedule actions to be performed after a certain delay. The setInterval()
function sets up an interval to repeatedly call a function after a delay specified in milliseconds, while clearInterval()
is used to stop the interval from running further.
Event listeners are used to monitor and respond to specific events, such as clicks or key presses, e.g., on DOM elements. The addEventListener()
method attaches an event listener to an element, while removeEventListener()
is used to remove an event listener when it is no longer needed. Event listeners are asynchronous because they respond to events like clicks or inputs without blocking the execution of other code. When an event occurs, its associated callback function is queued in the event loop, which manages the event execution.
Arrow functions provide a concise syntax for writing functions. They are defined using the =>
sign and differ from regular functions by not having their own this
context, instead inheriting this
from the surrounding scope. The are similar to Lambda functions from other languages.
You can find all these concepts in the game code and the additional examples provided below. If you have any questions, contact me on my Discord server.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game</title>
</head>
<body>
<p id="pkt">Points: 0</p>
<div id="dino" class="obj"></div>
<script>
var pkt = 0 // score counter
const level = 10 // difficulty level, influences enemy speed
let gameActive = true // flag to control game state
const pressed = {} // tracking keys pressed by the player
// Player class, handling player object and actions
class Player {
constructor(element) {
this.element = element
this.position = {x: 200, y: 200} // initial position of the player
this.speed = 5 // movement speed
this.updatePosition() // setting the player's initial position
this.addEventListeners() // listening for key events to control movement
// Player's appearance
this.element.style.backgroundColor = "red"
this.element.style.width = "50px"
this.element.style.height = "50px"
this.element.style.position = "absolute"
}
// Updating the player's position based on x and y coordinates
updatePosition() {
this.element.style.left = this.position.x + "px"
this.element.style.top = this.position.y + "px"
}
// Moving the player based on key inputs (Arrow keys)
move() {
if (!gameActive) return // if the game is over, stop movement (empty return - it will work like the break instruction but for a function)
// Adjusting the player's position based on key inputs and prohibiting him from exiting the screen
if (pressed["ArrowUp"] && this.position.y > 0) // moving the player up if a key is pressed, its name is "ArrowUp," and the y coordinate is greater than 0
this.position.y -= this.speed
if (pressed["ArrowDown"] && this.position.y < window.innerHeight - 50) // the second condition specifies that the player can't be at the bottom "border" of the screen
this.position.y += this.speed
if (pressed["ArrowLeft"] && this.position.x > 0) // the (0,0) point is at the top-left corner of the screen, so when checking the top and left border, we address 0
this.position.x -= this.speed
if (pressed["ArrowRight"] && this.position.x < window.innerWidth - 50) // the second condition specifies that the player can't be at the right "border" of the screen
this.position.x += this.speed
this.updatePosition() // recalculating and updating the position on the screen
}
// Attaching key event listeners to detect when keys are pressed/released
addEventListeners() {
window.addEventListener("keydown", (event) => {
pressed[event.key] = true // indicating that a key is pressed
})
window.addEventListener("keyup", (event) => {
pressed[event.key] = false
})
}
// Checking for collisions with opponents using bounding box logic
checkCollision(opponent) {
const element1 = this.element.getBoundingClientRect()
const element2 = opponent.element.getBoundingClientRect()
// If the player's and opponent's bounding boxes intersect, it's a collision
return !(
element1.top > element2.bottom ||
element1.bottom < element2.top ||
element1.left > element2.right ||
element1.right < element2.left
)
}
}
// Opponent class, controlling the enemy's behavior and movement
class Opponent {
constructor(element) {
this.element = element
this.position = {x: Math.random() * (window.innerWidth - 50), y: Math.random() * (window.innerHeight - 50)}
this.speed = level // using the defined level to set speed
this.direction = {x: 1, y: 1} // direction of movement (initially set to move diagonally)
this.updatePosition() // setting the initial position
this.move() // starting movement towards the opponent
// Opponent's appearance
this.element.style.backgroundColor = "blue"
this.element.style.width = "50px"
this.element.style.height = "50px"
this.element.style.position = "absolute"
}
// Updating the opponent's position on the screen
updatePosition() {
this.element.style.left = this.position.x + "px"
this.element.style.top = this.position.y + "px"
}
// Moving the opponent around the screen, bouncing when hitting boundaries
move() {
setInterval(() => {
if (!gameActive) return // if the game is over, stop movement
// Adjusting the opponent's position based on its speed and direction
this.position.x += this.speed * this.direction.x
this.position.y += this.speed * this.direction.y
// Reversing direction when the opponent hits a screen boundary
if (this.position.x <= 0 || this.position.x >= window.innerWidth - 50) {
this.direction.x *= -1
}
if (this.position.y <= 0 || this.position.y >= window.innerHeight - 50) {
this.direction.y *= -1
}
this.updatePosition() // updating the opponent's position on screen
}, 1000 / 60) // moving at 60 FPS
}
}
// Geting the HTML player element and initializing it
const playerElement = document.getElementById("dino")
const player = new Player(playerElement)
const opponentList = [] // an array to keep track of opponents
// Function to create a new opponent
const createOpponent = () => {
if (!gameActive) return // don't create enemies if the game is over
const opponentElement = document.createElement("div") // Creating a new opponent element
opponentElement.className = "obj"
document.body.appendChild(opponentElement) // appending to body
const opponent = new Opponent(opponentElement) // initializing the opponent
opponentList.push(opponent) // adding to the array of opponents
pkt++ // incrementing points
document.getElementById("pkt").textContent = "Points: " + pkt // updating points display
}
// Calling the createOpponent() function every 3 seconds
setInterval(createOpponent, 3000)
// Checking for collisions between the player and all opponents every 100ms
setInterval(() => {
if (!gameActive) return // stop checking collisions if the game is over
opponentList.forEach(opponent => { // iterating over each opponent in the "opponentList" array
if (player.checkCollision(opponent)) { // checking if the player collides with the currently considered opponent
gameActive = false // ending the game if a collision occurs
}
})
}, 100)
// Moving the player every 1/60th of a second (60 FPS)
setInterval(() => {
player.move()
}, 1000 / 60)
</script>
</body>
</html>
Additional examples
The setTimeout()
function executes a function once after a delay specified in milliseconds (setTimeout(() => {console.log("Timeout")}, 1000)
).
Event listeners
Input event listener
Open the console and write something in the <input>
form control below. The updated value of the input field will be displayed in the console whenever the user types.
<input type="text" id="inputField" placeholder="Write something...">
<script>
const inputField = document.getElementById("inputField")
inputField.addEventListener("input", (event) => {
console.log("Current value:", event.target.value)
})
</script>
Mouse event listeners
Open the console and hover over the paragraph below. While the mouse moves over the paragraph, its coordinates will be displayed in the console.
<p id="paragraph">Hover over this paragraph and move your mouse!</p>
<script>
const paragraph = document.getElementById("paragraph")
paragraph.addEventListener("mousemove", (event) => {
console.log(`Mouse moved to X: ${event.clientX}, Y: ${event.clientY}`)
})
paragraph.addEventListener("mouseenter", () => { // event listeners can be attached to individual HTML elements, not just the entire webpage
paragraph.textContent = "Mouse entered the paragraph!"
})
paragraph.addEventListener("mouseleave", () => {
paragraph.textContent = "Mouse left the paragraph!"
})
</script>
Hover over this paragraph and move your mouse!
Click listener
Open the console and click on any code snippet or example on this page. Its value will be displayed in the console.
<script>
document.addEventListener("click", (event) => {console.log("click")})
const codeElements = document.querySelectorAll("code")
codeElements.forEach((codeElement) => {
codeElement.addEventListener("click", (event) => {
console.log("Clicked on:", event.target)
})
})
</script>