xxxxxxxxxx
427
let scl; // Grid scale (calculated dynamically)
let cols, rows;
let playerSnake, computerSnake;
let food;
let obstacles = [];
let obstacleTimer = 0; // Timer to track when to change obstacles
let obstacleInterval = 300; // Minimum frames before obstacles relocate
let help = "Press 'f' (possibly twice) to toggle fullscreen";
let gameState = 'idle'; // 'idle', 'playing', or 'gameOver'
let hasEnded = false;
function setup() {
createCanvas(windowWidth, windowHeight);
frameRate(10); // Control the game speed
print(help);
updateGridDimensions(); // Calculate grid dimensions and scale
// Initialize snakes
playerSnake = new Snake(color(0, 0, 255)); // Blue snake for the player
computerSnake = new Snake(color(255, 0, 0)); // Red snake for the computer
computerSnake.chaseState = "food"; // Initial chase state
// Place food and obstacles
placeFood();
placeObstacles();
}
function draw() {
if (gameState === 'idle') {
drawStartScreen();
} else if (gameState === 'playing') {
runGame();
} else if (gameState === 'gameOver') {
drawGameOverScreen();
}
}
function runGame() {
background(220);
// Update obstacles at random intervals
if (frameCount > obstacleTimer + obstacleInterval) {
placeObstacles();
obstacleTimer = frameCount; // Reset the timer
}
// Draw the grid
drawGrid();
// Update the chase state
if (computerSnake.body.length > 0 && playerSnake.body.length > 0) {
if (computerSnake.len >= playerSnake.len * 3) {
computerSnake.chaseState = "user"; // Switch to chasing the user
} else {
computerSnake.chaseState = "food"; // Chase food
}
}
// Update and show the snakes
if (playerSnake.body.length > 0) {
playerSnake.update();
playerSnake.show();
}
if (computerSnake.body.length > 0) {
computerSnake.update();
computerSnake.show();
}
// Handle computer snake logic
if (computerSnake.body.length > 0 && computerSnake.chaseState === "food") {
computerSnake.chase(food); // Chase food
} else if (
computerSnake.body.length > 0 &&
playerSnake.body.length > 0 &&
computerSnake.chaseState === "user"
) {
computerSnake.chase(playerSnake.body[playerSnake.body.length - 1]); // Chase player's head
if (snakeCollidesWithSnake(computerSnake, playerSnake)) {
playerSnake.body.shift(); // Remove one cell from the player's snake
playerSnake.len--; // Decrease player's snake length
// check if player snake is engulfed completely
if (playerSnake.len <= 0) {
gameState = 'gameOver';
drawGameOverScreen();
fill(255, 255, 0);
textSize(32);
textAlign(CENTER, CENTER);
text("YOU WERE ENGULFED BY THE COMPUTER SNAKE!", width / 2, (2 * height) / 3);
return; // Exit the function immediately
}
}
}
// Check if the player snake eats the food
if (playerSnake.body.length > 0 && playerSnake.eat(food)) {
placeFood();
}
// Check if the computer snake eats the food
if (computerSnake.body.length > 0 && computerSnake.eat(food)) {
placeFood();
}
// Check for collisions with obstacles (only for the player snake)
if (playerSnake.body.length > 0 && snakeCollidesWithObstacles(playerSnake)) {
gameState = 'gameOver';
drawGameOverScreen();
return; // Exit the function immediately
}
// Draw the food
fill(0, 255, 0);
rect(food.x * scl, food.y * scl, scl, scl);
// Draw the obstacles
fill(100); // Gray obstacles
for (let obs of obstacles) {
rect(obs.x * scl, obs.y * scl, scl, scl);
}
// Check for game over conditions
if (playerSnake.body.length > 0 && playerSnake.isDead()) {
gameState = 'gameOver';
drawGameOverScreen();
return;
}
if (computerSnake.body.length > 0 && computerSnake.isDead()) {
gameState = 'gameOver';
drawGameOverScreen();
return;
}
}
function drawStartScreen() {
background(0);
fill(255, 255, 0); // Bright yellow color for arcade-like feel
textFont('monospace'); // Arcade-style font
textSize(48); // Large text size
textAlign(CENTER, CENTER);
// Title
text("SNAKE: SURVIVAL OF THE FITTEST", width / 2, height / 4);
// Instructions section
fill(0, 255, 0); // Green color for instructions
textSize(24); // Smaller text size for instructions
text("Instructions:", width / 2, height / 2.5); // Instruction header
// Individual instructions with proper spacing
textSize(20);
text("1. Use the arrow keys to control the snake.", width / 2, height / 2.2);
text("2. Eat the green food to grow longer.", width / 2, height / 2);
text("3. Avoid the gray obstacles.", width / 2, height / 1.85);
text(
"4. If the computer snake becomes 3x your size, it will chase you!",
width / 2,
height / 1.7
);
// Help message at the bottom
fill(255, 0, 0); // Red color for help
textSize(18);
text(help, width / 2, height / 1.3);
// Start game message
fill(255); // White color for "Press Space to Start"
textSize(24);
text("PRESS SPACE TO START", width / 2, height / 1.15);
}
function drawGameOverScreen() { // UPDATED FUNCTION
background(0);
fill(255, 0, 0); // Red for game over message
textFont('monospace'); // Arcade-style font
textSize(48);
textAlign(CENTER, CENTER);
text("GAME OVER!", width / 2, height / 3);
fill(0, 255, 0); // Green for restart instructions
textSize(24);
text("PRESS SPACE TO RESTART", width / 2, height / 2);
noLoop(); // Stop the game loop
}
function updateGridDimensions() {
// Set desired number of columns and rows
cols = 40;
rows = 30;
// Calculate scale to fit the window size
scl = min(floor(windowWidth / cols), floor(windowHeight / rows));
// Adjust cols and rows to fill the screen exactly
cols = floor(windowWidth / scl);
rows = floor(windowHeight / scl);
// Resize the canvas to match the new grid
resizeCanvas(cols * scl, rows * scl);
}
function windowResized() {
// Update grid and canvas dimensions when the window is resized
updateGridDimensions();
// Reposition snakes, food, and obstacles to ensure they are within the new bounds
playerSnake.reposition();
computerSnake.reposition();
placeFood();
placeObstacles();
}
function resetGame() {
playerSnake = new Snake(color(0, 0, 255)); // Reset player snake
computerSnake = new Snake(color(255, 0, 0)); // Reset computer snake
computerSnake.chaseState = "food"; // Reset chase state
placeFood();
placeObstacles();
loop(); // Start the game loop // FIX
}
function keyTyped() {
if (key === 'f') {
toggleFullscreen(); // Toggle fullscreen mode
}
}
function toggleFullscreen() {
let fs = fullscreen();
fullscreen(!fs); // Flip fullscreen state
}
function keyPressed() {
if (gameState === 'idle' && key === ' ') {
gameState = 'playing';
resetGame();
} else if (gameState === 'gameOver' && key === ' ') {
gameState = 'playing';
resetGame();
} else if (gameState === 'playing') {
switch (keyCode) {
case UP_ARROW:
if (playerSnake.ydir !== 1) playerSnake.setDir(0, -1);
break;
case DOWN_ARROW:
if (playerSnake.ydir !== -1) playerSnake.setDir(0, 1);
break;
case LEFT_ARROW:
if (playerSnake.xdir !== 1) playerSnake.setDir(-1, 0);
break;
case RIGHT_ARROW:
if (playerSnake.xdir !== -1) playerSnake.setDir(1, 0);
break;
}
}
}
function drawGrid() {
stroke(200);
for (let i = 0; i <= cols; i++) {
line(i * scl, 0, i * scl, rows * scl);
}
for (let j = 0; j <= rows; j++) {
line(0, j * scl, cols * scl, j * scl);
}
}
function placeFood() {
// Place food at a random position, avoiding obstacles and snakes
food = createVector(
floor(random(1, cols - 1)), // Avoid edges
floor(random(1, rows - 1))
);
// Ensure food does not overlap with obstacles or snakes
while (
obstacles.some(obs => obs.x === food.x && obs.y === food.y) ||
playerSnake.body.some(part => part.x === food.x && part.y === food.y) ||
computerSnake.body.some(part => part.x === food.x && part.y === food.y)
) {
food = createVector(
floor(random(1, cols - 1)),
floor(random(1, rows - 1))
);
}
}
function placeObstacles() {
// Place random obstacles
obstacles = []; // Clear existing obstacles
let numObstacles = floor(random(7, 17)); // Random number of obstacles between 4 and 8
for (let i = 0; i < numObstacles; i++) {
let obs = createVector(floor(random(cols)), floor(random(rows)));
// Ensure obstacles do not overlap with food or snakes
while (
(food && food.x === obs.x && food.y === obs.y) ||
playerSnake.body.some(part => part.x === obs.x && part.y === obs.y) ||
computerSnake.body.some(part => part.x === obs.x && part.y === obs.y)
) {
obs = createVector(floor(random(cols)), floor(random(rows)));
}
obstacles.push(obs);
}
}
function snakeCollidesWithObstacles(snake) {
// Check if the snake's head collides with any obstacle
if (snake === playerSnake) {
let head = snake.body[snake.body.length - 1];
return obstacles.some(obs => head.x === obs.x && head.y === obs.y);
}
return false; // Obstacles do not affect the computer snake
}
function snakeCollidesWithSnake(snake1, snake2) {
// Check if snake1's head collides with any part of snake2
let head1 = snake1.body[snake1.body.length - 1];
return snake2.body.some(part => part.x === head1.x && part.y === head1.y);
}
function endGame(message) {
// End the game and display a message
noLoop();
fill(0); // Black color for text
textSize(32);
textAlign(CENTER, CENTER);
text(message, width / 2, height / 2);
}
class Snake {
constructor(snakeColor) {
// Initialize snake properties
this.body = [createVector(floor(cols / 2), floor(rows / 2))];
this.xdir = 0;
this.ydir = 0;
this.len = 1;
this.dead = false;
this.snakeColor = snakeColor;
}
setDir(x, y) {
// Set snake's movement direction
this.xdir = x;
this.ydir = y;
}
update() {
// Update snake's position
let head = this.body[this.body.length - 1].copy();
head.x += this.xdir;
head.y += this.ydir;
// Check for wall collision
if (head.x < 0 || head.x >= cols || head.y < 0 || head.y >= rows) {
this.dead = true;
}
this.body.push(head);
// Remove the tail if the snake has not grown
if (this.body.length > this.len) {
this.body.shift();
}
}
eat(pos) {
// Check if the snake's head is at the same position as the food
let head = this.body[this.body.length - 1];
if (head.x === pos.x && head.y === pos.y) {
this.len++;
return true;
}
return false;
}
isDead() {
// Check if the snake runs into itself
let head = this.body[this.body.length - 1];
for (let i = 0; i < this.body.length - 1; i++) {
let part = this.body[i];
if (part.x === head.x && part.y === head.y) {
return true;
}
}
return this.dead;
}
show() {
// Display the snake on the canvas
fill(this.snakeColor);
for (let part of this.body) {
rect(part.x * scl, part.y * scl, scl, scl);
}
}
chase(target) {
// Chase a target (food or player's head)
let head = this.body[this.body.length - 1];
if (target.x > head.x && this.xdir !== -1) {
this.setDir(1, 0); // Move right
} else if (target.x < head.x && this.xdir !== 1) {
this.setDir(-1, 0); // Move left
} else if (target.y > head.y && this.ydir !== -1) {
this.setDir(0, 1); // Move down
} else if (target.y < head.y && this.ydir !== 1) {
this.setDir(0, -1); // Move up
}
}
reposition() {
// Reposition the snake if the window is resized
for (let part of this.body) {
part.x = constrain(part.x, 0, cols - 1);
part.y = constrain(part.y, 0, rows - 1);
}
}
}