xxxxxxxxxx
189
let snake;
let fruit;
let GRID_SIZE = 20; // Size of each grid cell
let gameActive;
let WIDTH = 600; // Width of the canvas
let HEIGHT = 600; // Height of the canvas
let gameState; // Variable to track game state ('start', 'playing', 'gameOver')
// p5.js setup function: Initializes the game
function setup() {
createCanvas(WIDTH, HEIGHT); // Creates the canvas
frameRate(6); // Sets the frame rate to 6 frames per second (slow speed)
gameState = 'start'; // Set the initial state to 'start'
snake = new Snake(GRID_SIZE); // Initializes the snake object
fruit = new Fruit(WIDTH, HEIGHT, GRID_SIZE); // Initializes the fruit object
gameActive = true; // Sets the game to active
}
// p5.js draw function: Runs every frame, continuously updates the game
function draw() {
background(0); // Clears the screen with a black background
if (gameState === 'start') {
// Display start screen
fill(255);
textAlign(CENTER);
textSize(72);
text("Snake Game", WIDTH / 2, HEIGHT / 4); // Game title
textSize(36);
text("Press ENTER to Start", WIDTH / 2, HEIGHT / 2); // Instructions to start
}
else if (gameState === 'playing') {
if (gameActive) {
snake.update(); // Update the snake's position
snake.draw(); // Draw the snake
// Check if the snake eats the fruit
if (snake.x === fruit.x && snake.y === fruit.y) {
snake.grow(); // Make the snake grow
fruit.move(); // Move the fruit to a new position
}
fruit.draw(); // Draw the fruit
// Check if the game is over
if (gameOver()) {
gameState = 'gameOver'; // If game over, change state
}
}
}
else if (gameState === 'gameOver') {
// Display "Game Over" screen
fill(255);
textAlign(CENTER);
textSize(72);
text("Game Over", WIDTH / 2, HEIGHT / 4); // Display "Game Over" text
textSize(60);
text(snake.body.length + 1, WIDTH / 2, HEIGHT / 2); // Display the snake's length as score
textSize(36);
text("Press ENTER to Play Again", WIDTH / 2, HEIGHT * 0.75); // Instructions to replay
}
}
// p5.js keyPressed function: Handles key presses to control the snake
function keyPressed() {
if (gameState === 'start' && keyCode === ENTER) {
// Start the game when ENTER is pressed on the start screen
resetGame();
gameState = 'playing';
}
if (gameState === 'gameOver' && keyCode === ENTER) {
// Replay the game when ENTER is pressed on the game over screen
resetGame();
gameState = 'playing';
}
if (gameState === 'playing') {
snake.action(key); // Pass the key to the snake's action method
}
}
// Function to check if the game is over
function gameOver() {
// Check if the snake goes out of bounds
if (snake.x < 0 || snake.x >= WIDTH || snake.y < 0 || snake.y >= HEIGHT) {
return true;
}
// Check if the snake runs into its own body
for (let i = 0; i < snake.body.length; i++) {
if (snake.x === snake.body[i][0] && snake.y === snake.body[i][1]) {
return true;
}
}
return false;
}
// Function to reset the game
function resetGame() {
snake = new Snake(GRID_SIZE); // Reset the snake object
fruit = new Fruit(WIDTH, HEIGHT, GRID_SIZE); // Reset the fruit object
gameActive = true; // Reactivate the game
}
// Snake class to represent the snake in the game
class Snake {
constructor(size) {
this.x = 3 * size; // Initial x position of the snake
this.y = 3 * size; // Initial y position of the snake
this.vx = 1; // Horizontal velocity (moving right by default)
this.vy = 0; // Vertical velocity (not moving vertically by default)
this.size = size; // Size of each segment of the snake
// Initialize the body of the snake as an array of coordinates
this.body = [
[this.x - size, this.y], // First body segment
[this.x - size * 2, this.y] // Second body segment
];
}
// Method to handle the snake's direction based on key input
action(key) {
// Up key (w) - only change direction if not currently moving down
if (key === 'w' && this.vy !== 1) {
this.vx = 0;
this.vy = -1;
}
// Left key (a) - only change direction if not currently moving right
if (key === 'a' && this.vx !== 1) {
this.vx = -1;
this.vy = 0;
}
// Down key (s) - only change direction if not currently moving up
if (key === 's' && this.vy !== -1) {
this.vx = 0;
this.vy = 1;
}
// Right key (d) - only change direction if not currently moving left
if (key === 'd' && this.vx !== -1) {
this.vx = 1;
this.vy = 0;
}
}
// Method to update the snake's position
update() {
this.body.shift(); // Remove the last segment of the body
this.body.push([this.x, this.y]); // Add the current head position to the body
this.x += this.vx * this.size; // Update the x position based on velocity
this.y += this.vy * this.size; // Update the y position based on velocity
}
// Method to grow the snake by adding a new segment
grow() {
this.body.unshift(this.body[0]); // Add a new segment at the head's position
}
// Method to draw the snake on the canvas
draw() {
fill(255); // Set the snake color to white
rect(this.x, this.y, this.size, this.size); // Draw the snake's head
// Draw each body segment
for (let i = 0; i < this.body.length; i++) {
rect(this.body[i][0], this.body[i][1], this.size, this.size);
}
}
}
// Fruit class to represent the fruit in the game
class Fruit {
constructor(width, height, size) {
this.width = width; // Width of the canvas
this.height = height; // Height of the canvas
this.size = size; // Size of the fruit (matches snake's size)
this.move(); // Set the initial position of the fruit
}
// Method to move the fruit to a random position on the grid
move() {
this.x = floor(random(0, this.width - this.size) / this.size) * this.size;
this.y = floor(random(0, this.height - this.size) / this.size) * this.size;
}
// Method to draw the fruit on the canvas
draw() {
fill(200, 0, 0); // Set the fruit color to red
rect(this.x, this.y, this.size, this.size); // Draw the fruit
}
}