赛博网格链接:HTML5画布贪吃蛇游戏提示
来自 Wikiprompt,自由的提示词百科全书
赛博网格链接:HTML5画布贪吃蛇游戏提示 一个用于生成完整单文件HTML5画布游戏的详细提示,包含赛博朋克贪吃蛇机制,涵盖渲染、控制和视觉风格规格。
提示词内容收藏
🌐
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Cyber Grid Link</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #0b0e1a;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Courier New', monospace;
}
.game-wrapper {
background: #101624;
padding: 20px;
border-radius: 24px;
box-shadow: 0 0 40px rgba(0, 255, 255, 0.2);
border: 1px solid #2a3a6a;
}
canvas {
display: block;
margin: 0 auto;
width: 800px;
height: 800px;
border-radius: 16px;
box-shadow: inset 0 0 30px rgba(0, 180, 255, 0.3);
background: #0d1225;
cursor: default;
}
.status-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 16px;
color: #b0e0ff;
text-shadow: 0 0 8px #2f9fff;
font-size: 1.3rem;
letter-spacing: 2px;
padding: 0 10px;
}
.status-bar span {
background: #1a2240;
padding: 6px 18px;
border-radius: 40px;
border: 1px solid #3f6bb0;
backdrop-filter: blur(2px);
}
.restart-btn {
background: #1f2b4a;
border: 1px solid #5f8ad0;
color: #b0e0ff;
padding: 6px 20px;
border-radius: 40px;
font-size: 1.1rem;
font-weight: bold;
letter-spacing: 1px;
transition: 0.2s;
box-shadow: 0 0 12px #2f6faf;
cursor: pointer;
}
.restart-btn:hover {
background: #2f4080;
box-shadow: 0 0 20px #4f9fff;
color: white;
transform: scale(1.02);
}
.restart-btn:active {
transform: scale(0.96);
}
@media (max-width: 840px) {
canvas {
width: 100%;
height: auto;
aspect-ratio: 1/1;
}
.game-wrapper {
padding: 12px;
}
}
</style>
</head>
<body>
<div class="game-wrapper">
<canvas id="gameCanvas" width="800" height="800"></canvas>
<div class="status-bar">
<span>⚡ 链长 <span id="scoreDisplay">3</span></span>
<button class="restart-btn" id="restartButton">⟳ 重启</button>
</div>
</div>
<script>
(function() {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreSpan = document.getElementById('scoreDisplay');
// ---------- 尺寸常量 ----------
const GRID_SIZE = 20; // 20x20 逻辑网格
const CELL_SIZE = 800 / GRID_SIZE; // 40px
const HALF_CELL = CELL_SIZE / 2;
// ---------- 游戏状态 ----------
let snake = []; // 坐标数组 {x, y} (逻辑网格)
let food = { x: 8, y: 10 };
let barriers = []; // 防火墙 {x, y}
let direction = { dx: 1, dy: 0 }; // 当前移动方向
let nextDirection = { dx: 1, dy: 0 };
let gameOver = false;
let winFlag = false;
let score = 3; // 初始长度3
// 插值相关 (平滑移动)
let moveProgress = 0; // 0..1 每帧累加
const MOVE_SPEED = 0.035; // 每帧增量 (约30帧完成一格)
// 网格扭曲参数 (靠近蛇头)
let warpOffset = { x: 0, y: 0 };
// 帧率节流 (防止delta爆炸)
let lastTimestamp = 0;
// ---------- 初始化 ----------
function initGame() {
// 蛇: 初始3节水平
snake = [
{ x: 9, y: 10 },
{ x: 8, y: 10 },
{ x: 7, y: 10 }
];
direction = { dx: 1, dy: 0 };
nextDirection = { dx: 1, dy: 0 };
gameOver = false;
winFlag = false;
score = 3;
moveProgress = 0;
barriers = [];
// 生成食物 & 初始屏障
generateFood();
generateBarriers(4); // 4个移动防火墙
updateScore();
}
// ---------- 生成食物 (避开蛇身和屏障) ----------
function generateFood() {
const occupied = new Set();
snake.forEach(seg => occupied.add(`${seg.x},${seg.y}`));
barriers.forEach(b => occupied.add(`${b.x},${b.y}`));
const freeCells = [];
for (let i = 0; i < GRID_SIZE; i++) {
for (let j = 0; j < GRID_SIZE; j++) {
if (!occupied.has(`${i},${j}`)) {
freeCells.push({ x: i, y: j });
}
}
}
if (freeCells.length === 0) {
// 胜利: 所有格子占满
winFlag = true;
gameOver = true;
return;
}
const rand = Math.floor(Math.random() * freeCells.length);
food = freeCells[rand];
}
// ---------- 生成屏障 (移动防火墙) ----------
function generateBarriers(count) {
barriers = [];
const occupied = new Set();
snake.forEach(seg => occupied.add(`${seg.x},${seg.y}`));
occupied.add(`${food.x},${food.y}`);
for (let i = 0; i < count; i++) {
let attempts = 0;
let pos;
while (attempts < 200) {
const x = Math.floor(Math.random() * GRID_SIZE);
const y = Math.floor(Math.random() * GRID_SIZE);
if (!occupied.has(`${x},${y}`) && !(x === food.x && y === food.y)) {
// 避免与蛇头太近 (至少距离2)
const head = snake[0];
if (Math.abs(x - head.x) + Math.abs(y - head.y) > 2) {
pos = { x, y };
break;
}
}
attempts++;
}
if (pos) {
barriers.push(pos);
occupied.add(`${pos.x},${pos.y}`);
}
}
}
// ---------- 移动屏障 (每帧更新) ----------
function moveBarriers() {
if (gameOver) return;
const head = snake[0];
// 每个屏障尝试向蛇头方向移动一步 (曼哈顿距离)
for (let i = 0; i < barriers.length; i++) {
const b = barriers[i];
const dx = Math.sign(head.x - b.x);
const dy = Math.sign(head.y - b.y);
// 随机选择优先轴 (增加变化)
let newX = b.x;
let newY = b.y;
if (Math.random() < 0.5) {
if (dx !== 0) newX = b.x + dx;
else if (dy !== 0) newY = b.y + dy;
} else {
if (dy !== 0) newY = b.y + dy;
else if (dx !== 0) newX = b.x + dx;
}
// 边界约束
newX = Math.min(GRID_SIZE-1, Math.max(0, newX));
newY = Math.min(GRID_SIZE-1, Math.max(0, newY));
// 不能与蛇身重叠 (除了蛇头? 但防火墙碰到蛇头即游戏结束)
const collideSnake = snake.some(seg => seg.x === newX && seg.y === newY);
const collideOtherBarrier = barriers.some((other, idx) => idx !== i && other.x === newX && other.y === newY);
if (!collideSnake && !collideOtherBarrier && !(newX === food.x && newY === food.y)) {
barriers[i] = { x: newX, y: newY };
} else {
// 尝试另一轴
let altX = b.x;
let altY = b.y;
if (dx !== 0 && dy !== 0) {
if (Math.random() < 0.5) {
altX = b.x + dx;
} else {
altY = b.y + dy;
}
} else if (dx !== 0) {
altX = b.x + dx;
} else if (dy !== 0) {
altY = b.y + dy;
}
altX = Math.min(GRID_SIZE-1, Math.max(0, altX));
altY = Math.min(GRID_SIZE-1, Math.max(0, altY));
const collideSnake2 = snake.some(seg => seg.x === altX && seg.y === altY);
const collideOtherBarrier2 = barriers.some((other, idx) => idx !== i && other.x === altX && other.y === altY);
if (!collideSnake2 && !collideOtherBarrier2 && !(altX === food.x && altY === food.y)) {
barriers[i] = { x: altX, y: altY };
}
// 否则保持不动
}
}
}
// ---------- 碰撞检测 (蛇头 vs 屏障/自身/边界) ----------
function checkCollisions(headPos) {
const { x, y } = headPos;
// 边界
if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE) {
return true;
}
// 自身 (除头部)
for (let i = 1; i < snake.length; i++) {
if (snake[i].x === x && snake[i].y === y) {
return true;
}
}
// 防火墙
for (let b of barriers) {
if (b.x === x && b.y === y) {
return true;
}
}
return false;
}
// ---------- 核心更新 (逻辑步进) ----------
function stepGame() {
if (gameOver) return;
// 1. 应用方向
direction = { dx: nextDirection.dx, dy: nextDirection.dy };
// 2. 计算新蛇头
const head = snake[0];
const newHead = {
x: head.x + direction.dx,
y: head.y + direction.dy
};
// 3. 检测是否吃到食物
const ate = (newHead.x === food.x && newHead.y === food.y);
// 4. 执行移动 (先加头)
snake.unshift(newHead);
if (!ate) {
snake.pop(); // 没吃到移除尾
} else {
score++;
updateScore();
// 生成新食物 & 屏障
generateFood();
if (gameOver) return; // 胜利时gameOver置true
// 增加一个屏障 (动态)
if (barriers.length < 8) {
const occupied = new Set();
snake.forEach(seg => occupied.add(`${seg.x},${seg.y}`));
barriers.forEach(b => occupied.add(`${b.x},${b.y}`));
occupied.add(`${food.x},${food.y}`);
let freeCells = [];
for (let i = 0; i < GRID_SIZE; i++) {
for (let j = 0; j < GRID_SIZE; j++) {
if (!occupied.has(`${i},${j}`)) freeCells.push({x:i, y:j});
}
}
if (freeCells.length > 0) {
const rand = Math.floor(Math.random() * freeCells.length);
barriers.push(freeCells[rand]);
}
}
}
// 5. 碰撞检测 (蛇头)
if (checkCollisions(snake[0])) {
gameOver = true;
return;
}
// 6. 移动屏障 (在蛇移动后)
moveBarriers();
// 额外碰撞: 蛇头与移动后的屏障
for (let b of barriers) {
if (b.x === snake[0].x && b.y === snake[0].y) {
gameOver = true;
break;
}
}
}
// ---------- 更新分数显示 ----------
function updateScore() {
scoreSpan.textContent = score;
}
// ---------- 重置游戏 ----------
function resetGame() {
initGame();
}
// ---------- 键盘控制 ----------
function handleKey(e) {
if (gameOver) return;
const key = e.key;
e.preventDefault();
if (key === 'ArrowUp' || key === 'w' || key === 'W') {
if (direction.dy !== 1) nextDirection = { dx: 0, dy: -1 };
} else if (key === 'ArrowDown' || key === 's' || key === 'S') {
if (direction.dy !== -1) nextDirection = { dx: 0, dy: 1 };
} else if (key === 'ArrowLeft' || key === 'a' || key === 'A') {
if (direction.dx !== 1) nextDirection = { dx: -1, dy: 0 };
} else if (key === 'ArrowRight' || key === 'd' || key === 'D') {
if (direction.dx !== -1) nextDirection = { dx: 1, dy: 0 };
}
}
// ---------- 渲染 (带插值 + 扭曲) ----------
function draw() {
ctx.clearRect(0, 0, 800, 800);
// 背景网格 (暗)
ctx.strokeStyle = '#1f2f5a';
ctx.lineWidth = 1.2;
for (let i = 0; i <= GRID_SIZE; i++) {
ctx.beginPath();
ctx.moveTo(i * CELL_SIZE, 0);
ctx.lineTo(i * CELL_SIZE, 800);
ctx.strokeStyle = '#1f2f5a';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, i * CELL_SIZE);
ctx.lineTo(800, i * CELL_SIZE);
ctx.stroke();
}
// 扭曲偏移 (基于蛇头)
const head = snake[0];
if (head) {
const headPx = head.x * CELL_SIZE + HALF_CELL;
const headPy = head.y * CELL_SIZE + HALF_CELL;
warpOffset.x = Math.sin(Date.now() / 600) * 3;
warpOffset.y = Math.cos(Date.now() / 700) * 3;
}
// 绘制食物 (能量晶体)
if (food && !winFlag) {
const fx = food.x * CELL_SIZE + HALF_CELL + warpOffset.x * 0.3;
const fy = food.y * CELL_SIZE + HALF_CELL + warpOffset.y * 0.3;
const gradient = ctx.createRadialGradient(fx-4, fy-4, 2, fx, fy, 16);
gradient.addColorStop(0, '#b0ffff');
gradient.addColorStop(0.5, '#2fc0ff');
gradient.addColorStop(1, '#004488');
ctx.shadowColor = '#2fc0ff';
ctx.shadowBlur = 24;
ctx.beginPath();
ctx.arc(fx, fy, 12, 0, Math.PI*2);
ctx.fillStyle = gradient;
ctx.fill();
ctx.shadowBlur = 0;
// 内部菱形
ctx.fillStyle = '#e0f0ff';
ctx.shadowBlur = 12;
ctx.beginPath();
ctx.moveTo(fx, fy-6);
ctx.lineTo(fx+6, fy);
ctx.lineTo(fx, fy+6);
ctx.lineTo(fx-6, fy);
ctx.closePath();
ctx.fill();
ctx.shadowBlur = 0;
}
// 绘制防火墙 (移动屏障)
ctx.shadowBlur = 18;
ctx.shadowColor = '#ff4a6a';
for (let b of barriers) {
const bx = b.x * CELL_SIZE + HALF_CELL + warpOffset.x * 0.2;
const by = b.y * CELL_SIZE + HALF_CELL + warpOffset.y * 0.2;
ctx.fillStyle = '#ff3a5a';
ctx.beginPath();
ctx.arc(bx, by, 14, 0, Math.PI*2);
ctx.fill();
ctx.fillStyle = '#ff8a9a';
ctx.beginPath();
ctx.arc(bx-2, by-2, 6, 0, Math.PI*2);
ctx.fill();
}
ctx.shadowBlur = 0;
// 绘制蛇 (链式粒子 + 插值)
if (snake.length === 0) return;
const headPos = snake[0];
// 计算插值偏移 (基于moveProgress)
let lerpX = 0, lerpY = 0;
if (direction.dx !== 0 || direction.dy !== 0) {
lerpX = direction.dx * CELL_SIZE * moveProgress;
lerpY = direction.dy * CELL_SIZE * moveProgress;
}
// 绘制每个segment (从尾到头)
for (let i = snake.length - 1; i >= 0; i--) {
const seg = snake[i];
let segX = seg.x * CELL_SIZE + HALF_CELL;
let segY = seg.y * CELL_SIZE + HALF_CELL;
// 头部应用插值
if (i === 0) {
segX += lerpX + warpOffset.x * 0.5;
segY += lerpY + warpOffset.y * 0.5;
} else {
segX += warpOffset.x * 0.2;
segY += warpOffset.y * 0.2;
}
// 脉冲渐变 (根据时间)
const pulse = Math.sin(Date.now() / 200 + i * 0.8) * 0.3 + 0.7;
const gradient = ctx.createRadialGradient(segX-4, segY-4, 2, segX, segY, 18);
gradient.addColorStop(0, `rgba(100, 220, 255, ${pulse})`);
gradient.addColorStop(0.6, `rgba(20, 120, 255, ${pulse*0.8})`);
gradient.addColorStop(1, `rgba(10, 40, 120, 0.2)`);
ctx.shadowColor = '#2fc0ff';
ctx.shadowBlur = 22;
ctx.beginPath();
ctx.arc(segX, segY, 14, 0, Math.PI*2);
ctx.fillStyle = gradient;
ctx.fill();
// 内圈高光
ctx.shadowBlur = 10;
ctx.beginPath();
ctx.arc(segX-2, segY-2, 6, 0, Math.PI*2);
ctx.fillStyle = `rgba(180, 240, 255, ${pulse*0.7})`;
ctx.fill();
}
ctx.shadowBlur = 0;
// 游戏结束/胜利信息
if (gameOver) {
ctx.font = 'bold 44px "Courier New", monospace';
ctx.fillStyle = winFlag ? '#aaffaa' : '#ff6a7a';
ctx.shadowColor = winFlag ? '#2fcf2f' : '#ff2f4f';
ctx.shadowBlur = 30;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(winFlag ? '⚡ 矩阵链接 ⚡' : '⛔ 链接断裂', 400, 400);
ctx.shadowBlur = 0;
}
}
// ---------- 游戏循环 (requestAnimationFrame) ----------
function gameLoop(timestamp) {
const delta = Math.min((timestamp - lastTimestamp) / 16.667, 4); // 限制最大delta
lastTimestamp = timestamp;
if (!gameOver) {
// 累积移动进度
moveProgress += MOVE_SPEED * delta;
if (moveProgress >= 1.0) {
moveProgress -= 1.0;
stepGame(); // 逻辑步进
}
}
draw();
requestAnimationFrame(gameLoop);
}
// ---------- 事件绑定 ----------
window.addEventListener('keydown', (e) => {
const arrows = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'w', 'W', 's', 'S', 'a', 'A', 'd', 'D'];
if (arrows.includes(e.key)) {
handleKey(e);
}
});
document.getElementById('restartButton').addEventListener('click', resetGame);
// 启动
initGame();
requestAnimationFrame(gameLoop);
})();
</script>
</body>
</html>
用法
此提示词专为 coding 设计。复制上方内容并粘贴到你常用的 AI 工具中。
为获得最佳效果,可将占位符(方括号或大写字母标示)替换为你的具体需求。
讨论
0 条评论