Turn ★ into ⭐ (top-right corner) if you like the project!
snakes2-extended-demo.mp4
👉 Get the Snake Game with Two Snakes and Extra Features
- Extended Version from itch.io or buymeacoffee.com
This is a modern take on the classic Snake game, built using p5.js. The game features two snakes (one player-controlled and one AI-controlled or both AI-controlled), dynamic obstacles, a central cannon, various food types, and power-ups. It supports both desktop (keyboard controls) and mobile (on-screen buttons) gameplay, with customizable settings and sound effects. The game is designed to be engaging with strategic elements, such as score penalties for collisions, temporary boosts from power-ups, and a cannon that interacts with the snakes.
Play the Snake Game with Two Snakes
👉 Tip: Right-click the link and choose "Open link in new tab", or hold Ctrl (Windows/Linux) or Cmd (Mac) while clicking to open in a new tab.
👉 Watch the Demo
Okay, based on the detailed analysis:
Functionality & Feature Completeness: Very high. Implements a wide range of complex features beyond a basic Snake game.
Code Quality & Structure: High. Good use of classes, generally readable, well-commented. Minor points on magic numbers and globals.
UI/UX & Customization: High. Good feedback, mobile support, settings persistence.
Robustness: Good. Handles collisions, invincibility frames, attempts safe obstacle placement.
Overall Complexity & Effort: Clearly significant effort went into this feature-rich version.
Considering all these aspects, I would give this project a score of:
9 / 10
It's a highly impressive and well-executed implementation with a vast feature set. The minor areas for potential refinement don't significantly detract from the overall quality and functionality. It's a strong piece of work.
- Objective: Eat food to grow your snake and earn points. The first snake to reach the winning score (default: 1000 points) wins.
- Snakes:
- Player Snake (Human): Blue, controlled via arrow keys (desktop) or on-screen buttons (mobile).
- AI Snake (AI): Red, moves automatically to chase food or power-ups.
- Game Modes:
- Player vs AI: You control Human against the AI-controlled AI snake.
- AI vs AI: Watch Human and AI, both AI-controlled, compete.
- Controls:
- Desktop: Use arrow keys (↑, ↓, ←, →) to move Human.
- Mobile: Use on-screen buttons (↑, ↓, ←, →) displayed in Player vs AI mode.
- Starting the Game:
- Select a game mode, AI speed, game speed, number of obstacles, and winning score via the controls at the top.
- Click New Game to start.
- Use Restart Game to reset with current settings or Reset to reload the page (saves settings).
- Sound: Toggle sound on/off with the Sound On/Muted button. Sound settings persist across sessions.
- Grid-Based Movement: The game is played on a 20x20 grid, with each tile representing a potential position for snakes, food, obstacles, or the cannon.
- Wrapping: Snakes wrap around the screen edges (e.g., moving off the right edge reappears on the left).
- Scoring:
- Regular Food: Red apple, grants +1 point and grows the snake by one segment. Plays "eat" sound.
- Super Food: Golden, pulsing item, grants +5 points, grows the snake, and slows game speed by 2 units. Disappears after 5 seconds. Plays "ding" sound.
- Shrink Food: Pink item, grants +2 points, shrinks the snake to 3 segments, and slows game speed by 1 unit. Disappears after 8 seconds. Plays "ding" and "shrink" sounds if shrunk.
- Mystery Food: White square with "?", randomly grants either:
- Super Effect: +5 points, growth, slows game speed by 2 units. Plays "ding" sound.
- Shrink Effect: +2 points, shrinks to 3 segments, slows game speed by 1 unit. Plays "ding" and "shrink" sounds if shrunk.
- Disappears after 8 seconds.
- Collisions: Hitting obstacles, yourself, or the other snake results in score penalties, a 30-frame invincibility period, and specific sounds:
- Self-Collision: Lose half your score (rounded down), other snake gains it. Plays "hit" sound.
- Snake Collision: Lose all your score, other snake gains it. Plays "hit" sound.
- Obstacle Collision: Lose 80% of your score (rounded down), other snake gains it. Plays "hit" sound.
- Obstacles: Black blocks (5–100, configurable) that move every 30 seconds. Colliding with them incurs a score penalty.
- Cannon: A moving cannon ("The Cannon") chases the closest snake, with its barrel facing its movement direction. It shoots projectiles every 30 frames. If hit, the snake grows by 1 segment, loses 1 point (if score > 0), and the cannon gains 1 point. The cannon’s score is displayed as "The Cannon: $X". Plays no sound on hit.
- Power-Ups: Temporary boosts that spawn randomly and disappear after 8 seconds. Plays "ding" sound with a pop-up message:
- Speed Boost: Yellow lightning bolt, increases speed by 50% for ~100 frames (5 seconds at 20 FPS). Shows "Speed Up!"
- Invincibility: Blue shield, prevents collisions for ~100 frames (5 seconds at 20 FPS). Shows "Invincible!"
- Score Multiplier: Purple star, doubles points from food for ~200 frames (10 seconds at 20 FPS). Shows "x2 Points!"
- Dynamic Game Speed:
- Base speed is set via the Game Speed selector (1–40).
- Speed increases by 1 unit for every 150 points (combined score of both snakes), capped at 40.
- Super and Shrink foods reduce speed temporarily.
- Visual Feedback:
- Point pop-ups display score changes or events (e.g., "+5", "Human Crashed!"), limited to the last 10 for performance.
- Invincibility is indicated by a black outline around snake segments.
- The cannon glows red when about to fire (within 15 frames).
- Settings Persistence: Game mode, AI speed, game speed, number of obstacles, winning score, and sound settings are saved to
localStorageand persist across page reloads.
- Controls Table:
- Mode: Select Player vs AI or AI vs AI.
- AI Speed: Adjust AI snake's update interval (0–6, lower is faster: Faster, Fast, Normal, Slower, Slowest, Stoned, Zombi).
- Game Speed: Set base frame rate (1–40).
- Obstacles: Choose number of obstacles (5–100, in increments of 5).
- Winning Score: Set the score needed to win (default: 1000, minimum 1).
- Buttons:
- New Game: Start a game with current settings.
- Restart Game: Reset the game with current settings.
- Reset: Reload the page, saving settings (useful for fixing lag).
- Sound On/Muted: Toggle sound effects.
- Help: Show/hide the rules section.
- Mobile Controls: On-screen buttons for ↑, ↓, ←, → appear in Player vs AI mode on mobile devices.
Below is a detailed description of the key functions in the game, grouped by category. These functions are defined in the main <script> section of snakes.html.
preload():- Loads sound files (
eat.mp3,hit.mp3,ding.mp3,shrink.mp3,gameover.mp3,finale.mp3) for use in the game. - Supports
.mp3and.wavformats viasoundFormats('mp3', 'wav').
- Loads sound files (
setup():- Initializes the game canvas (size based on 90% of window dimensions, max 400x400, aligned to 20x20 grid).
- Sets the default frame rate (
defaultRate, default 2). - Retrieves DOM elements (e.g.,
startButton,modeSelect) for interaction. - Calls
initializeGame()to set up game objects.
initializeGame():- Creates game objects:
playerSnake(at 5,5),aiSnake(at 15,15),food,superFood,shrinkFood,mysteryFood,powerUp,obstacles,cannon. - Generates initial obstacles based on
numObstacles(default 15). - Resets
speedDecrease,pointPopups, andisAnySoundPlaying. - Calls
loadSettings()to restore saved settings.
- Creates game objects:
WinScoreInput.addEventListener('change', ...):- Saves settings when the winning score input changes.
draw():- Main game loop, runs every frame.
- Updates the dynamic frame rate:
min(defaultRate + floor((playerSnake.score + aiSnake.score) / 150) + speedDecrease, 40). - If the game is started and not over:
- Shows and updates food, obstacles, special foods, power-ups, and the cannon.
- Updates
playerSnake(player-controlled in Player vs AI, AI-controlled in AI vs AI) andaiSnake(everyaiUpdateIntervalframes). - Checks for collisions and cannon hits.
- Shows mobile controls in Player vs AI mode on mobile devices.
- If game over, displays the game over message and shows the reset button.
- If not started, prompts to select a mode and start the game.
- Displays scores (Human, AI, Cannon) and current speed in the top-left corner.
- Spawns new
shrinkFood(0.4% chance),mysteryFood(0.3% chance), orpowerUp(0.3% chance) if inactive. - Updates and shows point pop-ups, removing expired ones.
checkCannonHits():- Checks if cannon projectiles hit a snake’s segments.
- If hit and not invincible, grows the snake by 1 segment, deducts 1 point from the snake (if > 0), adds 1 point to the cannon, and shows a pop-up (e.g., "Human -1, Cannon +1").
keyPressed():- Handles arrow key inputs for the player snake in Player vs AI mode when the game is started and not over.
- Calls
setDirectionFromKey(keyCode)to updateplayerSnake.dir.
setDirectionFromKey(keyCode):- Maps arrow keys to direction vectors (e.g.,
UP_ARROW→[0, -1]). - Prevents reversing direction (e.g., can't move up if going down).
- Maps arrow keys to direction vectors (e.g.,
setDirection(dx, dy):- Sets the player snake’s direction based on mobile button inputs (
ontouchstartevents). - Prevents reversing direction, only active in Player vs AI mode when the game is started and not over.
- Sets the player snake’s direction based on mobile button inputs (
startGame():- Initializes a new game with current settings (mode, win score, obstacles, AI speed, game speed).
- Saves settings, starts audio via
userStartAudio(), setsgameStartedtotrue, and callsinitializeGame(). - Hides the restart button.
restartGame():- Resets the game with current settings, similar to
startGame(). - Hides the restart button.
- Resets the game with current settings, similar to
resetGame():- Prompts for confirmation, saves settings, and reloads the page to fix lag or reset the game state.
saveSettings():- Saves game settings (
gameMode,aiSpeed,gameSpeed,numObstacles,winScore,soundEnabled) tolocalStorageas JSON.
- Saves game settings (
loadSettings():- Loads settings from
localStorage, applying defaults if not present (gameMode: "playerVsAI",aiSpeed: "2",gameSpeed: "2",numObstacles: "15",winScore: "1000",soundEnabled: true). - Updates game state via
updateGameMode(),updateAISpeed(),updateGameSpeed(),updateObstacles(), and setsmuteButtontext.
- Loads settings from
toggleSound():- Toggles
soundEnabled, updatesmuteButtontext ("Sound On" or "Muted"), and saves settings.
- Toggles
playSoundIfNotPlaying(sound):- Plays a sound if
soundEnabledistrueand the sound isn’t already playing (usessound.isPlaying()).
- Plays a sound if
checkCollisions():- Checks if either snake reaches
winScore, ending the game with a winner (e.g., "Human Wins!"). - For each snake, if not invincible:
- Self-Collision: Halves score (rounded down), gives it to the other snake, sets 30-frame invincibility, shows pop-up (e.g., "Human Crashed into itself!").
- Snake Collision: Loses all score to the other snake, sets 30-frame invincibility, shows pop-up (e.g., "Human Crashed into AI!").
- Obstacle Collision: Loses 80% of score (rounded down) to the other snake, sets 30-frame invincibility, shows pop-up (e.g., "Human Crashed into Obstacle!").
- Checks if either snake reaches
clearPointPopupsKeepRecent():- Limits point pop-ups to the last 10 to prevent performance issues.
updateGameMode():- Sets
gameModebased onmodeSelect.value("playerVsAI" or "AIVsAI"), removes focus, and saves settings.
- Sets
updateAISpeed():- Sets
aiUpdateIntervalbased onAIspeedSelect.value(0–6), removes focus, and saves settings.
- Sets
updateGameSpeed():- Sets
defaultRatebased onGameSpeedSelect.value(1–40), updates frame rate, removes focus, and saves settings.
- Sets
updateObstacles():- Sets
numObstaclesbased onNumberOfObstaclesSelect.value(5–100), regenerates obstacles, removes focus, and saves settings.
- Sets
Snake:- Constructor: Initializes position (
x,y), direction (dir), color, score (0), name, and power-up states (speedBoost,speedTimer,invincibilityTimer,scoreMultiplier,multiplierTimer). update(): Moves the snake bydir * speedBoost, wraps around edges, checks for collisions with food/power-ups, applies effects (e.g., +5 points for super food), and pops tail if no food is eaten. Adjusts distance threshold for food collision based onspeedBoost.updateAI(): AI logic to chase targets (power-up > mystery food > shrink food > super food > regular food), selects valid directions, and callsupdate().getValidDirections(head): Returns valid movement directions that avoid collisions.isValidMove(dir): Checks if a direction avoids collisions with self, other snake, obstacles, cannon, or projectiles (unless invincible).show(): Draws the snake with a triangular head (rotated bydirToAngle) and square body segments. Adds a black outline if invincible.dirToAngle(dir): Converts direction to rotation angle (e.g.,[1, 0]→HALF_PIfor right).
- Constructor: Initializes position (
Cannon:- Constructor: Places cannon at grid center (10,10), initializes empty
projectiles,shootInterval(30 frames),frameCounter,lastAngle,moveAngle,isFiringSoon,speed(0.1), andscore(0). update(): Moves toward the closest snake atspeed, updatesmoveAngle, fires everyshootIntervalframes viaaimAndShoot(), removes off-screen projectiles, and limits to 5 projectiles.show(): Draws the cannon as a gray circle with a rotating barrel (red whenisFiringSoon), and projectiles as black circles.aimAndShoot(): Targets the closest snake, calculates direction, and adds a projectile with normalized velocity.
- Constructor: Places cannon at grid center (10,10), initializes empty
Food:- Constructor: Spawns at a random grid position.
show(): Draws a red apple (ellipse) with a brown stem (line).
SuperFood:- Constructor: Initializes as inactive with
duration(300 frames),timer,x,y, andpulseTime. maybeSpawn(): Spawns with 0.5% chance if inactive.update(): Decrementstimer, deactivates iftimer≤ 0, attempts to spawn if inactive, and updatespulseTimefor animation.show(): Draws a pulsing golden circle if active.
- Constructor: Initializes as inactive with
ShrinkFood:- Constructor: Spawns randomly with
lifetime(8000 ms), setstimerto currentmillis(), and setsactivetotrue. spawn(): Picks a new random position.update(): Deactivates ifmillis() - timer > lifetime.show(): Draws a pink circle with a darker outline if active.
- Constructor: Spawns randomly with
MysteryFood:- Constructor: Spawns randomly with
duration(8000 ms), setsspawnTimeto currentmillis(), and setsactivetotrue. update(): Deactivates ifmillis() - spawnTime > duration.show(): Draws a white square with a purple "?" if active.
- Constructor: Spawns randomly with
PowerUp:- Constructor: Picks a random type (
speed,invincibility,multiplier), spawns randomly, setsduration(8000 ms),spawnTime,activetotrue, andpulseTime. update(): Deactivates ifmillis() - spawnTime > duration, updatespulseTimefor animation.show(): Draws type-specific shapes if active: yellow triangle for speed, blue circle for invincibility, purple star for multiplier.applyEffect(snake): Applies the power-up effect: speed (speedBoost = 1.5,speedTimer = 100), invincibility (invincibilityTimer = 100), or multiplier (scoreMultiplier = 2,multiplierTimer = 200). Shows a pop-up (e.g., "Human Speed Up!").
- Constructor: Picks a random type (
Obstacles:- Constructor: Initializes an empty
positionslist andlastMoved(0). generate(numObstacles): SpawnsnumObstaclesobstacles, avoiding snakes, food, power-ups, and cannon. Limits attempts to prevent infinite loops.move(): Regenerates obstacles everymoveObstaclesAfter(30000 ms) based onmillis().show(): Draws black squares for each obstacle.
- Constructor: Initializes an empty
PointPopup:- Constructor: Initializes position (
x,y),text,color,opacity(250), andlifetime(20 frames). update(): Moves upward (-0.4 pixels), reducesopacity(-4.5), decrementslifetime.show(): Draws a white rectangle with rounded corners and colored text.isDone(): Returnstrueiflifetime≤ 0.
- Constructor: Initializes position (
isMobileDevice():- Detects mobile devices via
navigator.userAgentregex (/Mobi|Android|iPhone|iPad|iPod/i) to show on-screen controls.
- Detects mobile devices via
clamp(min, val, max):- Limits a value between
minandmaxfor text sizing (e.g.,textSize(clamp(12, 3 * tileSize, 16))).
- Limits a value between
toggleRules():- Toggles the visibility of the rules section (
display: noneorblock).
- Toggles the visibility of the rules section (
- Framework: Built with p5.js (v1.4.2) and p5.sound for audio.
- Canvas: Dynamically sized (90% of window width/height, max 400px, aligned to 20x20 grid).
- Storage: Uses
localStorageto save settings as JSON. - Sound: Supports multiple sound effects (
eat,hit,ding,shrink,gameover,finale), toggled viasoundEnabled. - Responsive Design: Adapts to desktop and mobile with CSS media queries (e.g., grid layout for mobile controls at
max-width: 600px) and touch-friendly buttons (touch-action: manipulation). - Dependencies:
p5.min.js: Core p5.js library (CDN: Cloudflare).p5.sound.min.js: For sound effects (CDN: Cloudflare).
- Open Graph Meta Tags: Included for social sharing (title, description, image, URL, type).
- Clone the Repository:
git clone https://github.com/pazoff/Snake-Game-with-Two-Snakes
- Host the Game:
- Use a local server (e.g.,
python -m http.serveror VS Code Live Server) to servesnakes.html. - Ensure the
sounds/folder with.mp3files (eat.mp3,hit.mp3,ding.mp3,shrink.mp3,gameover.mp3,finale.mp3) is in the same directory.
- Use a local server (e.g.,
- Open in Browser:
- Navigate to
http://localhost:<port>/snakes.html. - The game runs in any modern browser (Chrome, Firefox, Safari).
- Navigate to
- No Sound: Ensure sound files are in the
sounds/folder,soundEnabledistrue, and browser audio permissions are granted. Check console for loading errors. - Lag: Click Reset to reload the page, which clears memory and preserves settings via
localStorage. - Mobile Controls Not Showing: Verify
isMobileDevice()detects your device (testnavigator.userAgent); ensure Player vs AI mode is selected. - Settings Not Saving: Check if
localStorageis enabled in your browser (e.g., not in private mode). - Obstacles Not Spawning Fully: If
numObstaclesis high, limited grid space may prevent all obstacles from spawning. Console warns if fewer are placed.
- Balance the speed boost power-up to prevent unfair advantages.
- Add difficulty presets (e.g., Easy, Hard) combining AI speed, game speed, and obstacles.
- Implement leaderboards using a backend service for high scores.
- Support multiplayer mode for two player-controlled snakes via WebSockets.
- Add new power-up types (e.g., reverse controls, teleport) or food effects (e.g., score steal).
- Optimize obstacle generation for high counts to reduce failed attempts.
Check out the detailed Project Roadmap for planned features and future development phases.
This project is open-source under the MIT License. Feel free to fork, modify, and distribute.
- Developed by: Pazoff
- Framework: p5.js by the Processing Foundation
- Sound Effects: [Public Domain]
- Background Image: Designed by brgfx / Freepik
For bug reports or feature requests, open an issue on the GitHub repository.
Last Updated: April 26, 2025

