Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
31 views8 pages

Snake HTML

The document is an HTML file for a mobile-ready Snake game titled 'Snake — Growth Freeze'. It includes styles for the game interface, controls for gameplay, and JavaScript functions to manage game logic, such as scoring, food placement, and snake movement. The game features a 'Growth Freeze' mechanic where players can temporarily prevent the snake from growing while still earning points.

Uploaded by

gg7370273
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views8 pages

Snake HTML

The document is an HTML file for a mobile-ready Snake game titled 'Snake — Growth Freeze'. It includes styles for the game interface, controls for gameplay, and JavaScript functions to manage game logic, such as scoring, food placement, and snake movement. The game features a 'Growth Freeze' mechanic where players can temporarily prevent the snake from growing while still earning points.

Uploaded by

gg7370273
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 8

<!

doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-
fit=cover" />
<title>Snake — Growth Freeze (Mobile Ready)</title>
<style>
:root{
--bg:#071028;
--panel:#071a2b;
--accent:#22c55e;
--muted:#94a3b8;
--glass: rgba(255,255,255,0.03);
}
html,body{height:100%;margin:0;background:linear-
gradient(180deg,#071028,#041226);color:#e6eef8;font-family:system-ui,-apple-
system,Segoe UI,Roboto,Arial}
.wrap{max-width:1000px;margin:18px
auto;padding:12px;display:flex;gap:18px;align-items:flex-start;justify-
content:center;flex-wrap:wrap}
.panel{background:rgba(255,255,255,0.02);padding:12px;border-radius:12px;box-
shadow:0 8px 28px rgba(2,6,23,0.6);display:flex;flex-
direction:column;gap:12px;align-items:center}
canvas{border-radius:10px;background:linear-
gradient(180deg,#081b2a,#052033);display:block;touch-action:none}
.hud{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:14px}
.chip{background:var(--glass);padding:8px 10px;border-radius:8px;color:var(--
muted);}
.chip strong{display:block;color:var(--accent);font-size:16px}
.freeze{background:rgba(138,43,226,0.12);color:violet;padding:8px 10px;border-
radius:8px}
.controls{display:flex;gap:8px}
.btn{background:transparent;border:1px solid rgba(255,255,255,0.06);padding:8px
10px;border-radius:8px;color:#cfe7d3;cursor:pointer}
.meta{min-width:220px;max-width:320px;display:flex;flex-
direction:column;gap:10px}
.tip{font-size:13px;color:var(--muted);padding:10px;border-
radius:8px;background:rgba(255,255,255,0.02)}
.touch-area{display:none;gap:8px;flex-direction:column;align-
items:center;margin-top:6px}
.touch-row{display:flex;gap:8px}
.touch-btn{width:64px;height:64px;border-
radius:12px;background:rgba(255,255,255,0.03);display:flex;align-
items:center;justify-content:center;font-weight:700;color:#fff;user-
select:none;touch-action:none}
input[type=range]{width:100%}
select{width:100%;padding:8px;border-
radius:8px;background:transparent;color:#cfe7d3;border:1px solid
rgba(255,255,255,0.04)}
@media (max-width:760px){
.wrap{padding:8px}
.panel{width:94vw}
canvas{width:92vw;height:92vw;max-width:640px;max-height:640px}
.meta{width:94vw}
.touch-area{display:flex}
}
</style>
</head>
<body>
<div class="wrap">
<div class="panel" aria-label="game panel">
<canvas id="game" width="600" height="600"></canvas>
<div class="hud" role="status" aria-live="polite">
<div class="chip">Score <strong id="score">0</strong></div>
<div class="chip">High <strong id="highscore">0</strong></div>
<div class="freeze">Freeze <strong id="freezeTimer">0.0</strong>s</div>
<div style="width:8px"></div>
<button id="pauseBtn" class="btn">Pause (P)</button>
<button id="restartBtn" class="btn">Restart</button>
</div>

<div class="touch-area" id="touchControls" aria-hidden="true">


<div class="touch-row" style="justify-content:center">
<div class="touch-btn" data-dir="up" aria-label="up">▲</div>
</div>
<div class="touch-row">
<div class="touch-btn" data-dir="left" aria-label="left">◀</div>
<div class="touch-btn" data-dir="down" aria-label="down">▼</div>
<div class="touch-btn" data-dir="right" aria-label="right">▶</div>
</div>
</div>
</div>

<div class="meta">
<div class="tip">
Controls: Arrow keys / WASD on keyboard. On phone use the on-screen
buttons. Eat green apples for points. Eat purple flasks to get <strong>Growth
Freeze</strong> (5s) — you still get points but the snake won't grow.
</div>

<div>
<label style="font-size:13px;color:var(--muted)">Speed</label>
<input id="speedRange" type="range" min="6" max="20" value="12" />
</div>

<div>
<label style="font-size:13px;color:var(--muted)">Mode</label>
<select id="modeSelect">
<option value="classic">Classic (walls kill)</option>
<option value="wrap">Wrap-around</option>
</select>
</div>

<div style="display:flex;gap:8px">
<button id="saveBtn" class="btn">Save Highscore</button>
<button id="clearBtn" class="btn">Clear Highscore</button>
</div>

<div style="font-size:13px;color:var(--muted)">
Tip: rotate to landscape for a wider play area. If controls don’t appear,
reload the page.
</div>
</div>
</div>

<script>
(function(){
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d', { alpha: false });
const scoreEl = document.getElementById('score');
const highEl = document.getElementById('highscore');
const freezeEl = document.getElementById('freezeTimer');
const pauseBtn = document.getElementById('pauseBtn');
const restartBtn = document.getElementById('restartBtn');
const speedRange = document.getElementById('speedRange');
const modeSelect = document.getElementById('modeSelect');
const touchControls = document.getElementById('touchControls');
const saveBtn = document.getElementById('saveBtn');
const clearBtn = document.getElementById('clearBtn');

// grid
const baseGrid = 20;
const baseSize = 600;
const cols = baseSize / baseGrid;
const rows = baseSize / baseGrid;

// game state
let snake, dir, nextDir, food, freezePower;
let score = 0;
let highscore = parseInt(localStorage.getItem('snake_high') || '0', 10) || 0;
let freezeActive = false;
let freezeRemaining = 0.0; // seconds
let running = true;
let speed = parseInt(speedRange.value, 10);
let mode = modeSelect.value;
let tickTimer = null;

highEl.textContent = highscore;

// helper
const randCell = () => ({ x: Math.floor(Math.random() * cols), y:
Math.floor(Math.random() * rows) });

function newGame(){
const cx = Math.floor(cols/2);
const cy = Math.floor(rows/2);
snake = [
{x: cx+1, y: cy},
{x: cx, y: cy},
{x: cx-1, y: cy}
];
dir = {x:1,y:0};
nextDir = {x:1,y:0};
score = 0;
freezeActive = false;
freezeRemaining = 0;
placeFood();
placeFreeze();
running = true;
updateUI();
}

function placeFood(){
let c;
while(true){
c = randCell();
if (!snake.some(s => s.x===c.x && s.y===c.y) && !(freezePower &&
freezePower.x===c.x && freezePower.y===c.y)) break;
}
food = c;
}

function placeFreeze(){
// spawn freeze with modest chance (20%)
if (Math.random() < 0.2){
let c;
while(true){
c = randCell();
if (!snake.some(s => s.x===c.x && s.y===c.y) && !(food && food.x===c.x &&
food.y===c.y)) break;
}
freezePower = c;
} else {
freezePower = null;
}
}

function updateUI(){
scoreEl.textContent = score;
highEl.textContent = highscore;
freezeEl.textContent = freezeRemaining > 0 ? (freezeRemaining < 1 ?
freezeRemaining.toFixed(1) : freezeRemaining.toFixed(1)) : '0.0';
}

function gameOver(){
running = false;
clearInterval(tickTimer);
tickTimer = null;
if (score > highscore){
highscore = score;
localStorage.setItem('snake_high', String(highscore));
}
updateUI();
// draw overlay
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(0, canvas.height/2 - 24, canvas.width, 48);
ctx.fillStyle = '#fff';
ctx.font = '20px system-ui, Arial';
ctx.textAlign = 'center';
ctx.fillText('Game Over — Press Restart', canvas.width/2, canvas.height/2 +
6);
}

function tick(){
if (!running) return;
// ms for this tick (derived from speed)
const ms = Math.round(1000 / speed);
const dt = ms / 1000;

// apply queued direction


dir = nextDir;
const head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };

if (mode === 'wrap'){


if (head.x < 0) head.x = cols - 1;
if (head.x >= cols) head.x = 0;
if (head.y < 0) head.y = rows - 1;
if (head.y >= rows) head.y = 0;
} else {
if (head.x < 0 || head.x >= cols || head.y < 0 || head.y >= rows){
return gameOver();
}
}

// self collision
if (snake.some(s => s.x===head.x && s.y===head.y)) return gameOver();

// move
snake.unshift(head);

// eat food?
if (head.x === food.x && head.y === food.y){
score += 1;
placeFood();
placeFreeze();
if (freezeActive){
// negate growth by removing tail immediately (so length stays same)
snake.pop();
} else {
// grow naturally (we already unshifted head and do not pop)
}
} else if (freezePower && head.x === freezePower.x && head.y ===
freezePower.y){
// collect freeze
freezeActive = true;
freezeRemaining = 5.0;
freezePower = null;
} else {
// normal move (no growth)
snake.pop();
}

// decrement freeze timer


if (freezeActive){
freezeRemaining -= dt;
if (freezeRemaining <= 0){
freezeActive = false;
freezeRemaining = 0;
}
}

draw();
updateUI();
}

function draw(){
// background
ctx.fillStyle = '#061226';
ctx.fillRect(0, 0, canvas.width, canvas.height);

// subtle grid lines (optional)


ctx.strokeStyle = 'rgba(255,255,255,0.02)';
ctx.lineWidth = 1;
for (let x=0;x<=cols;x++){
ctx.beginPath();
ctx.moveTo(x*baseGrid+0.5,0);
ctx.lineTo(x*baseGrid+0.5,canvas.height);
ctx.stroke();
}
for (let y=0;y<=rows;y++){
ctx.beginPath();
ctx.moveTo(0,y*baseGrid+0.5);
ctx.lineTo(canvas.width,y*baseGrid+0.5);
ctx.stroke();
}

// food (green)
ctx.fillStyle = '#22c55e';
roundRect(food.x*baseGrid + 3, food.y*baseGrid + 3, baseGrid - 6, baseGrid -
6, 6);

// freeze power (purple glow)


if (freezePower){
ctx.save();
ctx.fillStyle = '#9b59b6';
ctx.shadowColor = 'rgba(155,89,182,0.9)';
ctx.shadowBlur = 12;
roundRect(freezePower.x*baseGrid + 3, freezePower.y*baseGrid + 3, baseGrid
- 6, baseGrid - 6, 6);
ctx.restore();
}

// snake
for (let i=snake.length-1;i>=0;i--){
const s = snake[i];
const x = s.x * baseGrid;
const y = s.y * baseGrid;
if (i === 0){
// head gradient
const g = ctx.createLinearGradient(x,y,x+baseGrid,y+baseGrid);
g.addColorStop(0,'#b7f5c7');
g.addColorStop(1,'#22c55e');
ctx.fillStyle = g;
roundRect(x+2,y+2,baseGrid-4,baseGrid-4,6);
} else {
ctx.fillStyle = '#2aa26b';
roundRect(x+3,y+3,baseGrid-6,baseGrid-6,5);
}
}
}

function roundRect(x,y,w,h,r){
ctx.beginPath();
ctx.moveTo(x+r,y);
ctx.arcTo(x+w,y,x+w,y+h,r);
ctx.arcTo(x+w,y+h,x,y+h,r);
ctx.arcTo(x,y+h,x,y,r);
ctx.arcTo(x,y,x+w,y,r);
ctx.closePath();
ctx.fill();
}

// Input handling
function trySetDir(nx, ny){
// prevent reverse
if (dir.x === -nx && dir.y === -ny) return;
nextDir = {x:nx,y:ny};
}

window.addEventListener('keydown', function(e){
const k = e.key.toLowerCase();
// prevent default for arrow keys to avoid scrolling
if
(["arrowup","arrowdown","arrowleft","arrowright"].includes(e.key.toLowerCase()))
e.preventDefault();
if (k === 'arrowup' || k === 'w') trySetDir(0,-1);
if (k === 'arrowdown' || k === 's') trySetDir(0,1);
if (k === 'arrowleft' || k === 'a') trySetDir(-1,0);
if (k === 'arrowright' || k === 'd') trySetDir(1,0);
if (k === 'p') togglePause();
if (k === 'r') restart();
}, {passive:false});

// Touch controls (buttons)


touchControls.querySelectorAll('.touch-btn').forEach(b=>{
b.addEventListener('touchstart', e=>{
e.preventDefault();
const d = b.dataset.dir;
if (d === 'up') trySetDir(0,-1);
if (d === 'down') trySetDir(0,1);
if (d === 'left') trySetDir(-1,0);
if (d === 'right') trySetDir(1,0);
}, {passive:false});
});

// Pause & restart


function togglePause(){
running = !running;
if (running && !tickTimer) startLoop();
if (!running && tickTimer) {
clearInterval(tickTimer);
tickTimer = null;
}
pauseBtn.textContent = running ? 'Pause (P)' : 'Resume (P)';
}

function restart(){
clearInterval(tickTimer);
tickTimer = null;
newGame();
draw();
startLoop();
}

pauseBtn.addEventListener('click', togglePause);
restartBtn.addEventListener('click', restart);

// Speed / Mode
speedRange.addEventListener('input', ()=>{
speed = parseInt(speedRange.value,10);
if (tickTimer){
clearInterval(tickTimer);
startLoop();
}
});
modeSelect.addEventListener('change', ()=> mode = modeSelect.value );

// Highscore buttons
saveBtn.addEventListener('click', ()=>{
if (score > highscore){
highscore = score;
localStorage.setItem('snake_high', String(highscore));
updateUI();
alert('Highscore saved!');
} else {
alert('Score is not higher than current highscore.');
}
});
clearBtn.addEventListener('click', ()=>{
if (confirm('Clear saved highscore?')){
localStorage.removeItem('snake_high');
highscore = 0;
updateUI();
}
});

// Start loop
function startLoop(){
if (tickTimer) clearInterval(tickTimer);
const ms = Math.round(1000 / speed);
tickTimer = setInterval(tick, ms);
}

// Show touch controls on small screens


function refreshTouchVisible(){
const small = window.matchMedia('(max-width:760px)').matches;
touchControls.style.display = small ? 'flex' : 'none';
}
refreshTouchVisible();
window.addEventListener('resize', refreshTouchVisible);

// Initialization
newGame();
draw();
startLoop();

// Prevent overscroll on canvas for iOS when touching controls


['touchstart','touchmove'].forEach(ev=>{
canvas.addEventListener(ev, e => e.preventDefault(), {passive:false});
});
})();
</script>
</body>
</html>

You might also like