讨论

轴向漂移:移动端响应式物理迷宫游戏

来自 Wikiprompt,自由的提示词百科全书

loshu2000

2026年5月17日

轴向漂移:移动端响应式物理迷宫游戏 一个用于生成单文件HTML5迷宫游戏的全面提示,该游戏具有重力切换机制、移动倾斜控制和包豪斯视觉风格。

提示词内容收藏

🌐
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>Axial Drift · Bauhaus maze</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #1a1a1a; min-height: 100vh; display: flex; align-items: center; justify-content: center; font-family: 'Inter', 'Helvetica Neue', system-ui, sans-serif; touch-action: none; overflow: hidden; } .game-frame { background: #f5f0e6; padding: 12px; border-radius: 24px; box-shadow: 0 20px 40px rgba(0,0,0,0.6); } canvas { display: block; width: min(92vw, 92vh); height: min(92vw, 92vh); border-radius: 16px; box-shadow: inset 0 0 0 4px #000, 0 12px 24px rgba(0,0,0,0.7); background: #f5f0e6; touch-action: none; cursor: crosshair; } .hud { display: flex; justify-content: space-between; align-items: center; padding: 12px 8px 4px 8px; color: #000; font-weight: 800; letter-spacing: 1px; background: #f5f0e6; border-radius: 16px 16px 0 0; border-bottom: 4px solid #000; } .hud span { background: #ff4d00; padding: 6px 14px; border-radius: 40px; border: 2px solid #000; box-shadow: 3px 3px 0 #000; font-size: 0.9rem; } .hud .win-msg { background: #00c2a8; } .reset-btn { background: #ffcc00; border: 2px solid #000; border-radius: 40px; padding: 6px 16px; font-weight: 800; box-shadow: 3px 3px 0 #000; cursor: pointer; transition: 0.1s linear; font-size: 0.9rem; } .reset-btn:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 #000; } .controls-hint { font-size: 0.7rem; background: #fff; padding: 4px 10px; border-radius: 20px; border: 2px solid #000; } </style> </head> <body> <div style="display: flex; flex-direction: column;"> <div class="hud"> <span>⚡ AXIAL DRIFT</span> <span class="win-msg" id="statusDisplay">⚪ DRIFT</span> <button class="reset-btn" id="resetBtn">⟳ RESET</button> </div> <div class="game-frame"> <canvas id="mazeCanvas" width="800" height="800"></canvas> </div> <div style="display: flex; justify-content: space-between; padding-top: 8px; color: #000; font-weight: 600;"> <div class="controls-hint">🖱️ DRAG / 📱 TILT</div> <div class="controls-hint" id="gravityReadout">g: 0.0, 0.0</div> </div> </div> <script> (function(){ // ---------- BAUHAUS MAZE · SINGLE FILE ---------- const canvas = document.getElementById('mazeCanvas'); const ctx = canvas.getContext('2d'); const statusEl = document.getElementById('statusDisplay'); const gravityReadout = document.getElementById('gravityReadout'); // ---------- FIXED DIMENSIONS (logical) ---------- const W = 800, H = 800; canvas.width = W; canvas.height = H; // ---------- MAZE GEOMETRY (Bauhaus blocks) ---------- // walls as segments: {x1,y1,x2,y2} const wallSegments = [ // outer border (thick) {x1:40, y1:40, x2:760, y2:40}, {x1:760, y1:40, x2:760, y2:760}, {x1:760, y1:760, x2:40, y2:760}, {x1:40, y1:760, x2:40, y2:40}, // inner blocks – geometric composition {x1:160, y1:40, x2:160, y2:280}, {x1:160, y1:280, x2:360, y2:280}, {x1:360, y1:280, x2:360, y2:120}, {x1:280, y1:120, x2:280, y2:40}, {x1:520, y1:40, x2:520, y2:200}, {x1:520, y1:200, x2:680, y2:200}, {x1:680, y1:200, x2:680, y2:360}, {x1:680, y1:360, x2:520, y2:360}, {x1:520, y1:360, x2:520, y2:480}, {x1:200, y1:400, x2:200, y2:600}, {x1:200, y1:600, x2:400, y2:600}, {x1:400, y1:600, x2:400, y2:480}, {x1:400, y1:480, x2:280, y2:480}, {x1:280, y1:480, x2:280, y2:400}, {x1:600, y1:520, x2:600, y2:680}, {x1:600, y1:680, x2:720, y2:680}, {x1:720, y1:680, x2:720, y2:520}, {x1:720, y1:520, x2:640, y2:520}, {x1:120, y1:680, x2:120, y2:520}, {x1:120, y1:520, x2:240, y2:520}, {x1:240, y1:520, x2:240, y2:680}, // diagonal accent (trapdoor style) {x1:480, y1:120, x2:600, y2:240}, {x1:600, y1:240, x2:480, y2:240}, {x1:480, y1:240, x2:480, y2:120}, // dynamic trapdoor (kinetic) – will move {x1:80, y1:300, x2:80, y2:420}, {x1:80, y1:420, x2:160, y2:420}, {x1:160, y1:420, x2:160, y2:300}, // extra block {x1:320, y1:720, x2:320, y2:640}, {x1:320, y1:640, x2:460, y2:640}, {x1:460, y1:640, x2:460, y2:720}, ]; // dynamic kinetic trapdoor (moving wall) – will be updated let kineticWalls = [ {x1:80, y1:300, x2:80, y2:420, baseX:80, offset:0, speed:0.02, axis:'y'}, // vertical wall moving horizontally {x1:80, y1:420, x2:160, y2:420, baseY:420, offset:0, speed:0.015, axis:'x'}, // horizontal wall moving vertically {x1:160, y1:420, x2:160, y2:300, baseX:160, offset:0, speed:0.02, axis:'y'} ]; // merge static + kinetic (kinetic will be updated) function getAllWalls() { let walls = wallSegments.slice(); for (let k of kineticWalls) { walls.push({x1:k.x1, y1:k.y1, x2:k.x2, y2:k.y2}); } return walls; } // ---------- MARBLE ---------- let marble = { x: 120, y: 120, // start near top-left vx: 0, vy: 0, radius: 14, friction: 0.985, // damping angularVel: 0, angle: 0 }; // ---------- VORTEX (goal) ---------- const vortex = { x: 700, y: 700, radius: 28 }; // ---------- GRAVITY (global vector) ---------- let gravity = { x: 0, y: 0.4 }; // initial gentle downward let targetGravity = { x: 0, y: 0.4 }; // ---------- INPUT: mouse drag ---------- let isDragging = false; let lastMouse = { x: 0, y: 0 }; function handleDragStart(e) { e.preventDefault(); const rect = canvas.getBoundingClientRect(); const scaleX = canvas.width / rect.width; const scaleY = canvas.height / rect.height; const mouseX = (e.clientX - rect.left) * scaleX; const mouseY = (e.clientY - rect.top) * scaleY; isDragging = true; lastMouse = { x: mouseX, y: mouseY }; } function handleDragMove(e) { if (!isDragging) return; e.preventDefault(); const rect = canvas.getBoundingClientRect(); const scaleX = canvas.width / rect.width; const scaleY = canvas.height / rect.height; const mouseX = (e.clientX - rect.left) * scaleX; const mouseY = (e.clientY - rect.top) * scaleY; // delta from last position -> gravity vector (inverted: drag up -> gravity up) const dx = mouseX - lastMouse.x; const dy = mouseY - lastMouse.y; // sensitivity const sens = 0.02; targetGravity.x = Math.max(-1, Math.min(1, targetGravity.x + dx * sens)); targetGravity.y = Math.max(-1, Math.min(1, targetGravity.y + dy * sens)); lastMouse = { x: mouseX, y: mouseY }; } function handleDragEnd(e) { isDragging = false; } // ---------- DEVICE ORIENTATION (mobile tilt) ---------- function handleOrientation(e) { if (e.gamma === null || e.beta === null) return; // gamma: left/right (-90 to 90), beta: front/back (-180 to 180) let x = e.gamma / 45; // normalize let y = e.beta / 45; x = Math.max(-1, Math.min(1, x)); y = Math.max(-1, Math.min(1, y)); targetGravity.x = x * 0.8; targetGravity.y = y * 0.8; } // ---------- COLLISION & PHYSICS ---------- function closestPointOnSegment(px, py, x1, y1, x2, y2) { const dx = x2 - x1; const dy = y2 - y1; const len2 = dx*dx + dy*dy; let t = ((px - x1) * dx + (py - y1) * dy) / len2; t = Math.max(0, Math.min(1, t)); const projX = x1 + t * dx; const projY = y1 + t * dy; return { x: projX, y: projY }; } function resolveCollisions() { const walls = getAllWalls(); const r = marble.radius; for (let wall of walls) { const closest = closestPointOnSegment(marble.x, marble.y, wall.x1, wall.y1, wall.x2, wall.y2); const distX = marble.x - closest.x; const distY = marble.y - closest.y; const dist = Math.sqrt(distX*distX + distY*distY); if (dist < r) { // push out if (dist === 0) { // fallback marble.x += 0.1; continue; } const nx = distX / dist; const ny = distY / dist; marble.x = closest.x + nx * r; marble.y = closest.y + ny * r; // reflect velocity (with damping) const dot = marble.vx * nx + marble.vy * ny; if (dot < 0) { marble.vx -= 1.8 * dot * nx; marble.vy -= 1.8 * dot * ny; marble.vx *= 0.8; marble.vy *= 0.8; } } } } function updatePhysics() { // smooth gravity gravity.x += (targetGravity.x - gravity.x) * 0.08; gravity.y += (targetGravity.y - gravity.y) * 0.08; // apply gravity marble.vx += gravity.x * 0.5; marble.vy += gravity.y * 0.5; // friction / damping marble.vx *= marble.friction; marble.vy *= marble.friction; // integrate marble.x += marble.vx; marble.y += marble.vy; // angular velocity (visual) const speed = Math.sqrt(marble.vx*marble.vx + marble.vy*marble.vy); marble.angularVel = speed * 0.02; marble.angle += marble.angularVel; // collision resolveCollisions(); // boundary safety (extra) marble.x = Math.max(marble.radius+10, Math.min(W-marble.radius-10, marble.x)); marble.y = Math.max(marble.radius+10, Math.min(H-marble.radius-10, marble.y)); // update kinetic trapdoors (dynamic) for (let k of kineticWalls) { if (k.axis === 'y') { // vertical wall moves horizontally k.offset += k.speed; k.x1 = k.baseX + Math.sin(k.offset) * 25; k.x2 = k.baseX + Math.sin(k.offset) * 25; } else if (k.axis === 'x') { // horizontal wall moves vertically k.offset += k.speed; k.y1 = k.baseY + Math.cos(k.offset * 0.7) * 20; k.y2 = k.baseY + Math.cos(k.offset * 0.7) * 20; } } } // ---------- WIN CONDITION ---------- function checkWin() { const dx = marble.x - vortex.x; const dy = marble.y - vortex.y; const dist = Math.sqrt(dx*dx + dy*dy); if (dist < vortex.radius + marble.radius) { statusEl.innerText = '🌀 CAPTURED'; statusEl.style.background = '#00c2a8'; return true; } else { statusEl.innerText = '⚪ DRIFT'; statusEl.style.background = '#ff4d00'; return false; } } // ---------- RENDER (Bauhaus style) ---------- function draw() { ctx.clearRect(0, 0, W, H); // background ctx.fillStyle = '#f5f0e6'; ctx.fillRect(0, 0, W, H); // draw static walls (heavy black) ctx.lineWidth = 8; ctx.strokeStyle = '#000'; ctx.shadowColor = '#00000055'; ctx.shadowBlur = 12; ctx.shadowOffsetX = 4; ctx.shadowOffsetY = 4; // static walls for (let w of wallSegments) { ctx.beginPath(); ctx.moveTo(w.x1, w.y1); ctx.lineTo(w.x2, w.y2); ctx.stroke(); } // kinetic walls (red accent) ctx.strokeStyle = '#ff4d00'; ctx.lineWidth = 10; for (let k of kineticWalls) { ctx.beginPath(); ctx.moveTo(k.x1, k.y1); ctx.lineTo(k.x2, k.y2); ctx.stroke(); } // reset shadow for shapes ctx.shadowBlur = 16; ctx.shadowOffsetX = 6; ctx.shadowOffsetY = 6; // vortex (goal) – Bauhaus circle ctx.fillStyle = '#00c2a8'; ctx.shadowColor = '#00000088'; ctx.beginPath(); ctx.arc(vortex.x, vortex.y, vortex.radius, 0, Math.PI*2); ctx.fill(); ctx.strokeStyle = '#000'; ctx.lineWidth = 5; ctx.stroke(); // inner vortex ctx.fillStyle = '#ffcc00'; ctx.beginPath(); ctx.arc(vortex.x, vortex.y, vortex.radius*0.5, 0, Math.PI*2); ctx.fill(); ctx.stroke(); // marble (red with shadow) ctx.shadowColor = '#000000aa'; ctx.fillStyle = '#ff4d00'; ctx.beginPath(); ctx.arc(marble.x, marble.y, marble.radius, 0, Math.PI*2); ctx.fill(); ctx.strokeStyle = '#000'; ctx.lineWidth = 4; ctx.stroke(); // marble highlight ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.fillStyle = '#ffffffcc'; ctx.beginPath(); ctx.arc(marble.x-3, marble.y-3, 4, 0, Math.PI*2); ctx.fill(); // gravity vector indicator (arrow) ctx.shadowBlur = 8; ctx.shadowOffsetX = 2; ctx.shadowOffsetY = 2; ctx.strokeStyle = '#000'; ctx.lineWidth = 4; const gx = marble.x + gravity.x * 60; const gy = marble.y + gravity.y * 60; ctx.beginPath(); ctx.moveTo(marble.x, marble.y); ctx.lineTo(gx, gy); ctx.stroke(); // arrowhead const angle = Math.atan2(gy - marble.y, gx - marble.x); ctx.fillStyle = '#000'; ctx.beginPath(); ctx.moveTo(gx, gy); ctx.lineTo(gx - 12*Math.cos(angle-0.4), gy - 12*Math.sin(angle-0.4)); ctx.lineTo(gx - 12*Math.cos(angle+0.4), gy - 12*Math.sin(angle+0.4)); ctx.fill(); // reset shadow ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; // update HUD gravity gravityReadout.innerText = `g: ${gravity.x.toFixed(2)}, ${gravity.y.toFixed(2)}`; } // ---------- GAME LOOP ---------- function gameLoop() { updatePhysics(); checkWin(); draw(); requestAnimationFrame(gameLoop); } // ---------- RESET ---------- function resetGame() { marble.x = 120; marble.y = 120; marble.vx = 0; marble.vy = 0; targetGravity = { x: 0, y: 0.4 }; gravity = { x: 0, y: 0.4 }; statusEl.innerText = '⚪ DRIFT'; statusEl.style.background = '#ff4d00'; // reset kinetic offsets for (let k of kineticWalls) { k.offset = 0; if (k.axis === 'y') { k.x1 = k.baseX; k.x2 = k.baseX; } else { k.y1 = k.baseY; k.y2 = k.baseY; } } } // ---------- EVENT LISTENERS ---------- canvas.addEventListener('mousedown', handleDragStart); window.addEventListener('mousemove', handleDragMove); window.addEventListener('mouseup', handleDragEnd); canvas.addEventListener('touchstart', (e) => { const touch = e.touches[0]; const mouseEvent = new MouseEvent('mousedown', { clientX: touch.clientX, clientY: touch.clientY }); canvas.dispatchEvent(mouseEvent); e.preventDefault(); }, { passive: false }); canvas.addEventListener('touchmove', (e) => { const touch = e.touches[0]; const mouseEvent = new MouseEvent('mousemove', { clientX: touch.clientX, clientY: touch.clientY }); window.dispatchEvent(mouseEvent); e.preventDefault(); }, { passive: false }); canvas.addEventListener('touchend', (e) => { window.dispatchEvent(new MouseEvent('mouseup')); e.preventDefault(); }, { passive: false }); // device orientation if (window.DeviceOrientationEvent) { window.addEventListener('deviceorientation', handleOrientation, true); } document.getElementById('resetBtn').addEventListener('click', resetGame); // start resetGame(); gameLoop(); })(); </script> </body> </html>

登录以查看完整提示词

继续使用:

登录即表示你同意我们的 使用条款 和 隐私政策

用法

此提示词专为 coding 设计。复制上方内容并粘贴到你常用的 AI 工具中。

为获得最佳效果,可将占位符(方括号或大写字母标示)替换为你的具体需求。

参考资料

分类:coding| prompts.chat| game-development| html5

讨论