Join Community
Get in touch
Admin
January 14, 2024
Demo URL: https://snake-game-self.vercel.app/
Let's engage an discussion about JavaScript for a more organized code structure. The project comprises five main JavaScript files: game.js, food.js, snake.js, grid.js and input.js. We've designed it this way for better modularity and maintainability, but feel free to expand by adding more files to suit your specific needs.
Explore the demo to see these files in action and join the conversation. Share your insights, ask questions, and let's collaboratively learn and enhance our understanding of JavaScript and game development together!"
import {
SNAKE_SPEED,
update as updateSnake,
draw as drawSnake,
getSnakeHead,
snakeIntersection,
} from "./snake.js";
import {
update as updateFood,
draw as drawFood,
} from "./food.js";
import { oustideGrid } from "./grid.js";
let LAST_RENDER_TIME = 0;
let BOARD = document.getElementById("board");
let gameOver = false;
function main(CURRENT_TIME) {
if (gameOver) {
if (confirm('You lost. Press ok to restart.')) {
window.location = '/'
}
return
}
window.requestAnimationFrame(main);
const SECOND_LAST_RENDER_TIME = (CURRENT_TIME - LAST_RENDER_TIME) / 1000;
if (SECOND_LAST_RENDER_TIME < 1 / SNAKE_SPEED) return;
console.log("Render ...");
LAST_RENDER_TIME = CURRENT_TIME;
update();
draw();
}
window.requestAnimationFrame(main);
function update() {
updateSnake();
updateFood();
checkGameOver();
}
function draw() {
BOARD.innerHTML = "";
drawSnake(BOARD);
drawFood(BOARD)
}
function checkGameOver() {
gameOver = oustideGrid(getSnakeHead()) || snakeIntersection()
}
import { getInputDirection } from "./input.js";
export const SNAKE_SPEED = 5;
let SNAKE_ARRAY = [
{ x: 15, y: 15 }
];
let newSegment = 0;
export function update() {
addSegement();
const inputDirection = getInputDirection();
for (let i = SNAKE_ARRAY.length - 2; i >= 0; i--) {
SNAKE_ARRAY[i + 1] = { ...SNAKE_ARRAY[i] };
}
SNAKE_ARRAY[0].x += inputDirection.x;
SNAKE_ARRAY[0].y += inputDirection.y;
}
export function draw(BOARD) {
SNAKE_ARRAY.forEach((coordinate, index) => {
let SNAKE_ELEMENT = document.createElement("div");
SNAKE_ELEMENT.style.gridRowStart = coordinate.y;
SNAKE_ELEMENT.style.gridColumnStart = coordinate.x;
SNAKE_ELEMENT.classList.add("food");
BOARD.appendChild(SNAKE_ELEMENT);
});
}
export function expandSnake(amount) {
newSegment += amount;
}
export function onSnake(position, { ignoreHead = false } = {}) {
return SNAKE_ARRAY.some((segement, index) => {
if (ignoreHead && index === 0) return false;
return equalPositions(segement, position);
});
}
export function getSnakeHead() {
return SNAKE_ARRAY[0];
}
export function snakeIntersection() {
return onSnake(SNAKE_ARRAY[0], { ignoreHead: true });
}
export function equalPositions(pos1, pos2) {
return pos1.x === pos2.x && pos1.y === pos2.y;
}
function addSegement() {
for (let i = 0; i < newSegment; i++) {
SNAKE_ARRAY.push({ ...SNAKE_ARRAY[SNAKE_ARRAY.length - 1] });
}
newSegment = 0;
}
import { onSnake, expandSnake } from "./snake.js"
import {randomGridPosition } from "./grid.js"
let food = getRandomFoodPosition()
const EXPENSION_RATE = 1
export function update() {
if (onSnake(food)) {
expandSnake(EXPENSION_RATE)
food = getRandomFoodPosition()
}
}
export function draw(BOARD) {
const FOOD_ELEMENT = document.createElement("div")
FOOD_ELEMENT.style.gridRowStart = food.y
FOOD_ELEMENT.style.gridColumnStart = food.x
FOOD_ELEMENT.classList.add('head')
BOARD.appendChild(FOOD_ELEMENT)
}
export function getRandomFoodPosition () {
let newFoodPosition;
while (newFoodPosition == null || onSnake(newFoodPosition) ) {
newFoodPosition = randomGridPosition()
}
return newFoodPosition
}
const GRID_SIZE = 30;
export function randomGridPosition() {
return {
x: Math.floor(Math.random() * GRID_SIZE) + 1,
y: Math.floor(Math.random() * GRID_SIZE) + 1,
};
}
export function oustideGrid(position) {
return (
position.x < 1 ||
position.x > GRID_SIZE ||
position.y < 1 ||
position.y > GRID_SIZE
);
}
The code listens for keyboard and mouse click events to determine the input direction and updates the DIRECTION variable accordingly @returns The "getInputDirection" function returns the "DIRECTION" object.
import { MOVEMENT } from "./media.js";
let DIRECTION = { x: 0, y: 0 };
let LAST_INPUT_DIRECTION = { x: 0, y: 0 };
window.addEventListener("keydown", (e) => {
MOVEMENT.play();
switch (e.key) {
case "ArrowUp":
if (LAST_INPUT_DIRECTION.y !== 0) break;
DIRECTION = { x: 0, y: -1 };
break;
case "ArrowDown":
if (LAST_INPUT_DIRECTION.y !== 0) break;
DIRECTION = { x: 0, y: 1 };
break;
case "ArrowLeft":
if (LAST_INPUT_DIRECTION.x !== 0) break;
DIRECTION = { x: -1, y: 0 };
break;
case "ArrowRight":
if (LAST_INPUT_DIRECTION.x !== 0) break;
DIRECTION = { x: 1, y: 0 };
break;
default:
break;
}
});
window.addEventListener("click", (e) => {
const {id} = e.target
MOVEMENT.play();
switch (id) {
case "ArrowUp":
if (LAST_INPUT_DIRECTION.y !== 0) break;
DIRECTION = { x: 0, y: -1 };
break;
case "ArrowDown":
if (LAST_INPUT_DIRECTION.y !== 0) break;
DIRECTION = { x: 0, y: 1 };
break;
case "ArrowLeft":
if (LAST_INPUT_DIRECTION.x !== 0) break;
DIRECTION = { x: -1, y: 0 };
break;
case "ArrowRight":
if (LAST_INPUT_DIRECTION.x !== 0) break;
DIRECTION = { x: 1, y: 0 };
break;
default:
break;
}
});
export function getInputDirection() {
LAST_INPUT_DIRECTION = DIRECTION;
return DIRECTION;
}
Congratulations! You've successfully understand the core logic a Snake Game. Now you can enjoy a fast and efficient development workflow. If you have any doubt, Feel free to ask through MAIL.
“Unlock Next-Level Web Development: Dive into Next.js 15’s Exciting Features!” +1
React Native Expo vs. React JS (Next.js): A Comprehensive Guide for Choosing the Right
Next.js: React's Next Evolution
Meet Devin , The World's First Software Engineer!
Python and Stock Market: A Simple and Brief Overview
Python Mastery Quest: 50 Engaging Challenges to Level Up Your Coding Skills
A Guide to ESLint: Enhancing JavaScript Code Quality
GitHub for Beginners: A Step-by-Step Guide to Pushing Your Code - Mastering the Basics and Essential Commands
Python Beginning: Simple Calculator
Snake Game Code: A Beginner's Guide
Easy Setup: Vite, React, TypeScript, and Tailwind Project Guide
Why you should prefer Zustand over Redux Toolkit?
Google launches Imagen 2, better than DALL.E 2?
Decoding the New AI Era: Is Gemini by Google the Ultimate ChatGPT Alternative?