yuanbao-game · 提交 PgOCxNMNMU

返回历史
ybnb 提交于 2026-10-16 15:16:30 · 分支 main · 父提交 paxQB88Y
新增 index.html
--- a/index.html
+++ b/index.html
@@ -0,0 +1,237 @@
+<!DOCTYPE html>
+<html lang="zh">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>🐍 贪吃蛇</title>
+<style>
+ * { margin: 0; padding: 0; box-sizing: border-box; }
+ body {
+ background: #0f0f1a;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 100vh;
+ font-family: 'Courier New', monospace;
+ color: #e0e0e0;
+ user-select: none;
+ }
+ h1 { color: #e11d48; margin-bottom: 10px; font-size: 1.8rem; }
+ .score-board {
+ display: flex;
+ gap: 30px;
+ margin-bottom: 12px;
+ font-size: 1.1rem;
+ }
+ .score-board span { color: #f59e0b; }
+ #gameCanvas {
+ border: 2px solid #e11d48;
+ border-radius: 8px;
+ background: #1a1a2e;
+ box-shadow: 0 0 20px rgba(225,29,72,0.3);
+ }
+ .controls {
+ margin-top: 14px;
+ display: flex;
+ gap: 10px;
+ }
+ button {
+ background: #e11d48;
+ color: white;
+ border: none;
+ padding: 8px 20px;
+ border-radius: 6px;
+ font-size: 1rem;
+ cursor: pointer;
+ font-family: inherit;
+ transition: background 0.2s;
+ }
+ button:hover { background: #be123c; }
+ .tip {
+ margin-top: 10px;
+ font-size: 0.85rem;
+ color: #888;
+ }
+ .overlay {
+ position: fixed;
+ inset: 0;
+ background: rgba(0,0,0,0.7);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ z-index: 10;
+ }
+ .overlay h2 { color: #e11d48; font-size: 2rem; margin-bottom: 10px; }
+ .overlay p { color: #f59e0b; font-size: 1.2rem; margin-bottom: 20px; }
+ .hidden { display: none !important; }
+</style>
+</head>
+<body>
+<h1>🐍 贪吃蛇</h1>
+<div class="score-board">
+ <div>得分: <span id="score">0</span></div>
+ <div>最高: <span id="best">0</span></div>
+</div>
+<canvas id="gameCanvas" width="400" height="400"></canvas>
+<div class="controls">
+ <button onclick="startGame()">开始游戏</button>
+</div>
+<p class="tip">方向键 / WASD 控制方向 &nbsp;|&nbsp; 手机请用下方按钮</p>
+<div style="margin-top:10px; display:flex; gap:6px; flex-wrap:wrap; justify-content:center; max-width:200px;">
+ <button onclick="setDir('up')">⬆️</button>
+ <button onclick="setDir('left')">⬅️</button>
+ <button onclick="setDir('down')">⬇️</button>
+ <button onclick="setDir('right')">➡️</button>
+</div>
+
+<div class="overlay" id="overlay">
+ <h2 id="overlayTitle">🐍 贪吃蛇</h2>
+ <p id="overlayMsg">准备开始!</p>
+ <button onclick="startGame()">开始游戏</button>
+</div>
+
+<script>
+const canvas = document.getElementById('gameCanvas');
+const ctx = canvas.getContext('2d');
+const GRID = 20;
+const COLS = canvas.width / GRID;
+const ROWS = canvas.height / GRID;
+
+let snake, dir, nextDir, food, score, best, gameLoop, running;
+
+best = parseInt(localStorage.getItem('snakeBest') || '0');
+document.getElementById('best').textContent = best;
+
+function init() {
+ snake = [{x:10,y:10}];
+ dir = {x:1,y:0};
+ nextDir = {x:1,y:0};
+ score = 0;
+ document.getElementById('score').textContent = 0;
+ spawnFood();
+}
+
+function spawnFood() {
+ do {
+ food = {x: Math.floor(Math.random()*COLS), y: Math.floor(Math.random()*ROWS)};
+ } while (snake.some(s => s.x===food.x && s.y===food.y));
+}
+
+function draw() {
+ ctx.fillStyle = '#1a1a2e';
+ ctx.fillRect(0,0,canvas.width,canvas.height);
+
+ // grid
+ ctx.strokeStyle = '#22223a';
+ for(let i=0;i<=COLS;i++) {
+ ctx.beginPath(); ctx.moveTo(i*GRID,0); ctx.lineTo(i*GRID,canvas.height); ctx.stroke();
+ }
+ for(let i=0;i<=ROWS;i++) {
+ ctx.beginPath(); ctx.moveTo(0,i*GRID); ctx.lineTo(canvas.width,i*GRID); ctx.stroke();
+ }
+
+ // food
+ ctx.fillStyle = '#e11d48';
+ ctx.shadowColor = '#e11d48';
+ ctx.shadowBlur = 10;
+ ctx.beginPath();
+ ctx.arc(food.x*GRID+GRID/2, food.y*GRID+GRID/2, GRID/2-2, 0, Math.PI*2);
+ ctx.fill();
+ ctx.shadowBlur = 0;
+
+ // snake
+ snake.forEach((seg, i) => {
+ const brightness = 1 - i * 0.03;
+ ctx.fillStyle = `rgba(${Math.floor(34*brightness)},${Math.floor(197*brightness)},${Math.floor(94*brightness)},1)`;
+ ctx.shadowColor = '#22c55e';
+ ctx.shadowBlur = i===0 ? 12 : 4;
+ ctx.beginPath();
+ ctx.roundRect(seg.x*GRID+1, seg.y*GRID+1, GRID-2, GRID-2, 4);
+ ctx.fill();
+ });
+ ctx.shadowBlur = 0;
+}
+
+function step() {
+ dir = {...nextDir};
+ const head = {x: snake[0].x + dir.x, y: snake[0].y + dir.y};
+
+ // 穿墙
+ head.x = (head.x+COLS)%COLS;
+ head.y = (head.y+ROWS)%ROWS;
+
+ // 撞自己
+ if (snake.some(s => s.x===head.x && s.y===head.y)) {
+ gameOver(); return;
+ }
+
+ snake.unshift(head);
+
+ if (head.x===food.x && head.y===food.y) {
+ score += 10;
+ document.getElementById('score').textContent = score;
+ spawnFood();
+ // 加速
+ clearInterval(gameLoop);
+ const speed = Math.max(80, 150 - Math.floor(score/30)*5);
+ gameLoop = setInterval(step, speed);
+ } else {
+ snake.pop();
+ }
+ draw();
+}
+
+function gameOver() {
+ running = false;
+ clearInterval(gameLoop);
+ if (score > best) {
+ best = score;
+ localStorage.setItem('snakeBest', best);
+ document.getElementById('best').textContent = best;
+ }
+ document.getElementById('overlayTitle').textContent = '💀 游戏结束';
+ document.getElementById('overlayMsg').textContent = `得分: ${score} 分`;
+ document.getElementById('overlay').classList.remove('hidden');
+}
+
+function startGame() {
+ document.getElementById('overlay').classList.add('hidden');
+ clearInterval(gameLoop);
+ init();
+ running = true;
+ draw();
+ gameLoop = setInterval(step, 150);
+}
+
+function setDir(d) {
+ if (!running) return;
+ const map = {
+ up: {x:0,y:-1},
+ down: {x:0,y:1},
+ left: {x:-1,y:0},
+ right: {x:1,y:0}
+ };
+ const nd = map[d];
+ if (nd && !(nd.x===-dir.x && nd.y===-dir.y)) {
+ nextDir = nd;
+ }
+}
+
+document.addEventListener('keydown', e => {
+ const map = {
+ ArrowUp:'up', w:'up', W:'up',
+ ArrowDown:'down', s:'down', S:'down',
+ ArrowLeft:'left', a:'left', A:'left',
+ ArrowRight:'right', d:'right', D:'right',
+ };
+ if (map[e.key]) { e.preventDefault(); setDir(map[e.key]); }
+});
+
+// init
+init();
+draw();
+</script>
+</body>
+</html>
扫码访问