Diskussion

Axiale Drift: Mobil-responsives Physik-Labyrinth-Spiel

Von Wikiprompt, der freien Prompt-Enzyklopädie

loshu2000
Beigetragen vonloshu2000Quelle

17. Mai 2026

Axiale Drift: Mobil-responsives Physik-Labyrinth-Spiel Ein umfassender Prompt zur Erzeugung eines einseitigen HTML5-Labyrinthspiels mit Gravitationswechsel-Mechanik, mobilen Neigungssteuerungen und Bauhaus-Visualstil.

Prompt-InhaltSpeichern

🌐
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <title>Axial Drift</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; -webkit-user-select: none; user-select: none; touch-action: none; } body { background: #1a1a1a; overflow: hidden; font-family: 'Arial Black', 'Helvetica Neue', sans-serif; } #gameCanvas { display: block; width: 100vw; height: 100vh; background: #f4f4f4; } #ui-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 10; } #title { position: absolute; top: 20px; left: 20px; color: #ff3b30; font-size: 28px; font-weight: 900; letter-spacing: 4px; text-shadow: 3px 3px 0 #000; text-transform: uppercase; } #status { position: absolute; bottom: 20px; left: 20px; color: #000; font-size: 14px; font-weight: bold; background: #ffcc00; padding: 8px 12px; border: 3px solid #000; box-shadow: 4px 4px 0 #000; } #controls-hint { position: absolute; bottom: 20px; right: 20px; color: #fff; font-size: 12px; background: #007aff; padding: 6px 10px; border: 3px solid #000; box-shadow: 4px 4px 0 #000; text-align: right; } @media (max-width: 768px) { #title { font-size: 20px; top: 10px; left: 10px; } #status { font-size: 11px; bottom: 10px; left: 10px; } #controls-hint { font-size: 10px; bottom: 10px; right: 10px; max-width: 150px; } } </style> </head> <body> <canvas id="gameCanvas"></canvas> <div id="ui-overlay"> <div id="title">AXIAL DRIFT</div> <div id="status">GRAVITY: X:0.0 Y:0.0</div> <div id="controls-hint">DRAG / TILT TO SHIFT GRAVITY</div> </div> <script> (function() { 'use strict'; // ========== CANVAS SETUP ========== const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const statusEl = document.getElementById('status'); let W = window.innerWidth; let H = window.innerHeight; let DPR = Math.min(window.devicePixelRatio || 1, 2); function resizeCanvas() { W = window.innerWidth; H = window.innerHeight; DPR = Math.min(window.devicePixelRatio || 1, 2); canvas.width = W * DPR; canvas.height = H * DPR; canvas.style.width = W + 'px'; canvas.style.height = H + 'px'; ctx.setTransform(DPR, 0, 0, DPR, 0, 0); buildMaze(); } // ========== MAZE DEFINITION ========== // Grid-based maze: 0 = empty, 1 = wall, 2 = trapdoor (dynamic), 3 = vortex (goal) const GRID_SIZE = 20; // base grid cells let mazeGrid = []; let cellSize = 0; let mazeOffsetX = 0; let mazeOffsetY = 0; let vortexPos = { x: 0, y: 0 }; let trapdoors = []; // Marble physics let marble = { x: 0, y: 0, vx: 0, vy: 0, radius: 0, onGround: false }; // Gravity vector (normalized, -1 to 1) let gravity = { x: 0, y: 0 }; let targetGravity = { x: 0, y: 0 }; // Game state let gameWon = false; let gameLost = false; let winTimer = 0; // ========== MAZE GENERATION ========== function buildMaze() { // Calculate cell size based on viewport const cols = Math.floor(W / 40); const rows = Math.floor(H / 40); const gridCols = Math.max(12, Math.min(20, cols)); const gridRows = Math.max(12, Math.min(20, rows)); cellSize = Math.min(W / gridCols, H / gridRows); mazeOffsetX = (W - cellSize * gridCols) / 2; mazeOffsetY = (H - cellSize * gridRows) / 2; // Generate maze grid (simple procedural generation) mazeGrid = []; for (let r = 0; r < gridRows; r++) { mazeGrid[r] = []; for (let c = 0; c < gridCols; c++) { // Border walls if (r === 0 || c === 0 || r === gridRows - 1 || c === gridCols - 1) { mazeGrid[r][c] = 1; } else { // Random walls with some structure const rand = Math.random(); if (rand < 0.25) { mazeGrid[r][c] = 1; } else { mazeGrid[r][c] = 0; } } } } // Clear area around start (top-left) and vortex (center) const startR = 1, startC = 1; const vortexR = Math.floor(gridRows / 2); const vortexC = Math.floor(gridCols / 2); // Clear start area for (let r = startR; r <= startR + 1; r++) { for (let c = startC; c <= startC + 1; c++) { if (r < gridRows - 1 && c < gridCols - 1) mazeGrid[r][c] = 0; } } // Clear vortex area for (let r = vortexR - 1; r <= vortexR + 1; r++) { for (let c = vortexC - 1; c <= vortexC + 1; c++) { if (r > 0 && c > 0 && r < gridRows - 1 && c < gridCols - 1) mazeGrid[r][c] = 0; } } // Set vortex position vortexPos = { x: mazeOffsetX + (vortexC + 0.5) * cellSize, y: mazeOffsetY + (vortexR + 0.5) * cellSize }; // Place trapdoors (dynamic elements) trapdoors = []; const numTrapdoors = Math.floor(gridCols * gridRows * 0.05); for (let i = 0; i < numTrapdoors; i++) { const r = Math.floor(Math.random() * (gridRows - 2)) + 1; const c = Math.floor(Math.random() * (gridCols - 2)) + 1; if (mazeGrid[r][c] === 0 && !(r === startR && c === startC) && !(r === vortexR && c === vortexC)) { mazeGrid[r][c] = 2; trapdoors.push({ r: r, c: c, x: mazeOffsetX + (c + 0.5) * cellSize, y: mazeOffsetY + (r + 0.5) * cellSize, state: 'closed', // 'closed', 'open', 'closing' timer: 0, openTime: 0 }); } } // Place marble at start marble.x = mazeOffsetX + (startC + 0.5) * cellSize; marble.y = mazeOffsetY + (startR + 0.5) * cellSize; marble.radius = cellSize * 0.3; marble.vx = 0; marble.vy = 0; gameWon = false; gameLost = false; winTimer = 0; } // ========== PHYSICS ========== const FRICTION = 0.98; const DAMPING = 0.95; const MAX_SPEED = 8; const GRAVITY_FORCE = 0.5; function updatePhysics(dt) { if (gameWon || gameLost) return; // Smooth gravity transition gravity.x += (targetGravity.x - gravity.x) * 0.1; gravity.y += (targetGravity.y - gravity.y) * 0.1; // Apply gravity marble.vx += gravity.x * GRAVITY_FORCE * dt * 60; marble.vy += gravity.y * GRAVITY_FORCE * dt * 60; // Apply friction and damping marble.vx *= FRICTION; marble.vy *= FRICTION; marble.vx *= DAMPING; marble.vy *= DAMPING; // Clamp speed const speed = Math.sqrt(marble.vx * marble.vx + marble.vy * marble.vy); if (speed > MAX_SPEED) { marble.vx = (marble.vx / speed) * MAX_SPEED; marble.vy = (marble.vy / speed) * MAX_SPEED; } // Move marble marble.x += marble.vx * dt * 60; marble.y += marble.vy * dt * 60; // Collision detection with maze walls const gridCols = mazeGrid[0].length; const gridRows = mazeGrid.length; // Check collision with grid cells const minCol = Math.floor((marble.x - marble.radius - mazeOffsetX) / cellSize); const maxCol = Math.floor((marble.x + marble.radius - mazeOffsetX) / cellSize); const minRow = Math.floor((marble.y - marble.radius - mazeOffsetY) / cellSize); const maxRow = Math.floor((marble.y + marble.radius - mazeOffsetY) / cellSize); for (let r = Math.max(0, minRow); r <= Math.min(gridRows - 1, maxRow); r++) { for (let c = Math.max(0, minCol); c <= Math.min(gridCols - 1, maxCol); c++) { if (mazeGrid[r][c] === 1) { // Wall collision - resolve const wallLeft = mazeOffsetX + c * cellSize; const wallRight = wallLeft + cellSize; const wallTop = mazeOffsetY + r * cellSize; const wallBottom = wallTop + cellSize; // Find closest point on wall to marble center const closestX = Math.max(wallLeft, Math.min(marble.x, wallRight)); const closestY = Math.max(wallTop, Math.min(marble.y, wallBottom)); const dx = marble.x - closestX; const dy = marble.y - closestY; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < marble.radius) { // Push marble out if (dist === 0) { // Marble center is inside wall - push out based on penetration const overlapX = Math.min(marble.x - wallLeft, wallRight - marble.x); const overlapY = Math.min(marble.y - wallTop, wallBottom - marble.y); if (overlapX < overlapY) { marble.x = (marble.x < wallLeft + cellSize / 2) ? wallLeft - marble.radius : wallRight + marble.radius; } else { marble.y = (marble.y < wallTop + cellSize / 2) ? wallTop - marble.radius : wallBottom + marble.radius; } } else { const pushX = (dx / dist) * (marble.radius - dist); const pushY = (dy / dist) * (marble.radius - dist); marble.x += pushX; marble.y += pushY; } // Reflect velocity const normalX = dx / (dist || 1); const normalY = dy / (dist || 1); const dot = marble.vx * normalX + marble.vy * normalY; if (dot < 0) { marble.vx -= 2 * dot * normalX; marble.vy -= 2 * dot * normalY; marble.vx *= 0.8; marble.vy *= 0.8; } } } else if (mazeGrid[r][c] === 2) { // Trapdoor - check if open const trap = trapdoors.find(t => t.r === r && t.c === c); if (trap && trap.state === 'open') { // Check if marble is over the trapdoor const trapLeft = mazeOffsetX + c * cellSize; const trapRight = trapLeft + cellSize; const trapTop = mazeOffsetY + r * cellSize; const trapBottom = trapTop + cellSize; if (marble.x > trapLeft && marble.x < trapRight && marble.y > trapTop && marble.y < trapBottom) { // Marble falls through - game over gameLost = true; return; } } } } } // Check vortex collision (win condition) const dx = marble.x - vortexPos.x; const dy = marble.y - vortexPos.y; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < marble.radius + cellSize * 0.3) { gameWon = true; winTimer = 0; } // Update trapdoors for (const trap of trapdoors) { if (trap.state === 'closed') { trap.timer += dt; if (trap.timer > 3) { trap.state = 'open'; trap.openTime = 0; } } else if (trap.state === 'open') { trap.openTime += dt; if (trap.openTime > 1.5) { trap.state = 'closing'; trap.timer = 0; } } else if (trap.state === 'closing') { trap.timer += dt; if (trap.timer > 0.5) { trap.state = 'closed'; trap.timer = 0; } } } } // ========== RENDERING ========== function drawMaze() { ctx.clearRect(0, 0, W, H); // Background ctx.fillStyle = '#f4f4f4'; ctx.fillRect(0, 0, W, H); // Draw grid cells const gridCols = mazeGrid[0].length; const gridRows = mazeGrid.length; for (let r = 0; r < gridRows; r++) { for (let c = 0; c < gridCols; c++) { const x = mazeOffsetX + c * cellSize; const y = mazeOffsetY + r * cellSize; if (mazeGrid[r][c] === 1) { // Wall - Bauhaus style: bold primary color blocks ctx.fillStyle = '#007aff'; // Blue ctx.fillRect(x, y, cellSize, cellSize); ctx.strokeStyle = '#000'; ctx.lineWidth = 3; ctx.strokeRect(x, y, cellSize, cellSize); // Drop shadow ctx.shadowColor = 'rgba(0,0,0,0.3)'; ctx.shadowBlur = 8; ctx.shadowOffsetX = 4; ctx.shadowOffsetY = 4; ctx.fillStyle = '#007aff'; ctx.fillRect(x, y, cellSize, cellSize); ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; // Re-stroke for clean edges ctx.strokeStyle = '#000'; ctx.lineWidth = 3; ctx.strokeRect(x, y, cellSize, cellSize); } else if (mazeGrid[r][c] === 2) { // Trapdoor const trap = trapdoors.find(t => t.r === r && t.c === c); if (trap) { if (trap.state === 'closed') { ctx.fillStyle = '#ff3b30'; // Red ctx.fillRect(x, y, cellSize, cellSize); ctx.strokeStyle = '#000'; ctx.lineWidth = 3; ctx.strokeRect(x, y, cellSize, cellSize); // X pattern ctx.beginPath(); ctx.moveTo(x + 5, y + 5); ctx.lineTo(x + cellSize - 5, y + cellSize - 5); ctx.moveTo(x + cellSize - 5, y + 5); ctx.lineTo(x + 5, y + cellSize - 5); ctx.strokeStyle = '#000'; ctx.lineWidth = 2; ctx.stroke(); } else if (trap.state === 'open') { // Open - dark hole ctx.fillStyle = '#1a1a1a'; ctx.fillRect(x, y, cellSize, cellSize); ctx.strokeStyle = '#000'; ctx.lineWidth = 3; ctx.strokeRect(x, y, cellSize, cellSize); } else { // Closing - yellow warning ctx.fillStyle = '#ffcc00'; ctx.fillRect(x, y, cellSize, cellSize); ctx.strokeStyle = '#000'; ctx.lineWidth = 3; ctx.strokeRect(x, y, cellSize, cellSize); } } } } } // Draw vortex (goal) const vortexRadius = cellSize * 0.4; const pulse = 0.5 + 0.5 * Math.sin(Date.now() * 0.005); // Outer glow ctx.shadowColor = '#ffcc00'; ctx.shadowBlur = 20 + pulse * 20; ctx.fillStyle = '#ffcc00'; ctx.beginPath(); ctx.arc(vortexPos.x, vortexPos.y, vortexRadius, 0, Math.PI * 2); ctx.fill(); ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; // Inner circle ctx.fillStyle = '#ff3b30'; ctx.beginPath(); ctx.arc(vortexPos.x, vortexPos.y, vortexRadius * 0.6, 0, Math.PI * 2); ctx.fill(); ctx.strokeStyle = '#000'; ctx.lineWidth = 3; ctx.stroke(); // Spiral effect ctx.strokeStyle = '#000'; ctx.lineWidth = 2; for (let i = 0; i < 3; i++) { ctx.beginPath(); ctx.arc(vortexPos.x, vortexPos.y, vortexRadius * (0.2 + i * 0.2), i * 2, i * 2 + 1.5); ctx.stroke(); } // Draw marble ctx.shadowColor = 'rgba(0,0,0,0.4)'; ctx.shadowBlur = 10; ctx.shadowOffsetX = 3; ctx.shadowOffsetY = 3; // Marble gradient const gradient = ctx.createRadialGradient( marble.x - marble.radius * 0.3, marble.y - marble.radius * 0.3, marble.radius * 0.1, marble.x, marble.y, marble.radius ); gradient.addColorStop(0, '#ffffff'); gradient.addColorStop(0.5, '#cccccc'); gradient.addColorStop(1, '#666666'); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(marble.x, marble.y, marble.radius, 0, Math.PI * 2); ctx.fill(); ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.strokeStyle = '#000'; ctx.lineWidth = 2; ctx.stroke(); // Marble highlight ctx.fillStyle = 'rgba(255,255,255,0.6)'; ctx.beginPath(); ctx.arc(marble.x - marble.radius * 0.3, marble.y - marble.radius * 0.3, marble.radius * 0.2, 0, Math.PI * 2); ctx.fill(); // Draw gravity vector indicator const indicatorX = W - 60; const indicatorY = H - 60; ctx.strokeStyle = '#000'; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(indicatorX, indicatorY, 30, 0, Math.PI * 2); ctx.stroke(); ctx.beginPath(); ctx.moveTo(indicatorX, indicatorY); ctx.lineTo(indicatorX + gravity.x * 25, indicatorY + gravity.y * 25); ctx.strokeStyle = '#ff3b30'; ctx.lineWidth = 4; ctx.stroke(); // Arrowhead const angle = Math.atan2(gravity.y, gravity.x); const arrowLen = 10; ctx.beginPath(); ctx.moveTo(indicatorX + gravity.x * 25, indicatorY + gravity.y * 25); ctx.lineTo(indicatorX + gravity.x * 25 - arrowLen * Math.cos(angle - 0.4), indicatorY + gravity.y * 25 - arrowLen * Math.sin(angle - 0.4)); ctx.moveTo(indicatorX + gravity.x * 25, indicatorY + gravity.y * 25); ctx.lineTo(indicatorX + gravity.x * 25 - arrowLen * Math.cos(angle + 0.4), indicatorY + gravity.y * 25 - arrowLen * Math.sin(angle + 0.4)); ctx.stroke(); // Update status statusEl.textContent = 'GRAVITY: X:' + gravity.x.toFixed(1) + ' Y:' + gravity.y.toFixed(1); // Win/Lose overlays if (gameWon) { ctx.fillStyle = 'rgba(0,0,0,0.6)'; ctx.fillRect(0, 0, W, H); ctx.fillStyle = '#ffcc00'; ctx.font = 'bold 48px Arial Black'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.shadowColor = '#000'; ctx.shadowBlur = 10; ctx.fillText('VORTEX CAPTURED!', W / 2, H / 2 - 30); ctx.font = '20px Arial'; ctx.fillStyle = '#fff'; ctx.fillText('Click / tap to restart', W / 2, H / 2 + 30); ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; } else if (gameLost) { ctx.fillStyle = 'rgba(0,0,0,0.6)'; ctx.fillRect(0, 0, W, H); ctx.fillStyle = '#ff3b30'; ctx.font = 'bold 48px Arial Black'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.shadowColor = '#000'; ctx.shadowBlur = 10; ctx.fillText('TRAPPED!', W / 2, H / 2 - 30); ctx.font = '20px Arial'; ctx.fillStyle = '#fff'; ctx.fillText('Click / tap to restart', W / 2, H / 2 + 30); ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; } } // ========== INPUT HANDLING ========== let isDragging = false; let lastMouseX = 0; let lastMouseY = 0; function handleMouseDown(e) { if (gameWon || gameLost) { buildMaze(); return; } isDragging = true; lastMouseX = e.clientX; lastMouseY = e.clientY; } function handleMouseMove(e) { if (!isDragging) return; const dx = e.clientX - lastMouseX; const dy = e.clientY - lastMouseY; lastMouseX = e.clientX; lastMouseY = e.clientY; // Map mouse movement to gravity targetGravity.x = Math.max(-1, Math.min(1, targetGravity.x + dx * 0.02)); targetGravity.y = Math.max(-1, Math.min(1, targetGravity.y + dy * 0.02)); } function handleMouseUp() { isDragging = false; } // Touch events function handleTouchStart(e) { e.preventDefault(); const touch = e.touches[0]; if (gameWon || gameLost) { buildMaze(); return; } isDragging = true; lastMouseX = touch.clientX; lastMouseY = touch.clientY; } function handleTouchMove(e) { e.preventDefault(); if (!isDragging) return; const touch = e.touches[0]; const dx = touch.clientX - lastMouseX; const dy = touch.clientY - lastMouseY; lastMouseX = touch.clientX; lastMouseY = touch.clientY; targetGravity.x = Math.max(-1, Math.min(1, targetGravity.x + dx * 0.02)); targetGravity.y = Math.max(-1, Math.min(1, targetGravity.y + dy * 0.02)); } function handleTouchEnd(e) { e.preventDefault(); isDragging = false; } // Device orientation function handleOrientation(e) { if (e.gamma !== null && e.beta !== null) { // gamma: left/right tilt (-90 to 90) // beta: front/back tilt (-180 to 180) const x = Math.max(-1, Math.min(1, e.gamma / 45)); const y = Math.max(-1, Math.min(1, e.beta / 45)); targetGravity.x = x; targetGravity.y = y; } } // ========== GAME LOOP ========== let lastTime = 0; function gameLoop(timestamp) { const dt = Math.min((timestamp - lastTime) / 1000, 0.05); lastTime = timestamp; updatePhysics(dt); drawMaze(); requestAnimationFrame(gameLoop); } // ========== EVENT LISTENERS ========== window.addEventListener('resize', resizeCanvas); canvas.addEventListener('mousedown', handleMouseDown); window.addEventListener('mousemove', handleMouseMove); window.addEventListener('mouseup', handleMouseUp); canvas.addEventListener('touchstart', handleTouchStart, { passive: false }); canvas.addEventListener('touchmove', handleTouchMove, { passive: false }); canvas.addEventListener('touchend', handleTouchEnd, { passive: false }); // Request device orientation permission for iOS if (typeof DeviceOrientationEvent !== 'undefined' && typeof DeviceOrientationEvent.requestPermission === 'function') { DeviceOrientationEvent.requestPermission() .then(state => { if (state === 'granted') { window.addEventListener('deviceorientation', handleOrientation); } }) .catch(err => console.log('Orientation permission denied')); } else { window.addEventListener('deviceorientation', handleOrientation); } // ========== INIT ========== resizeCanvas(); requestAnimationFrame(gameLoop); })(); </script> </body> </html>

Melde dich an, um den vollständigen Prompt zu sehen

Weiter mit:

Mit der Anmeldung akzeptierst du unsere Nutzungsbedingungen und Datenschutz

Verwendung

Dieser Prompt ist für die Verwendung mit coding gedacht. Kopiere den Inhalt oben und füge ihn in dein bevorzugtes KI-Tool ein.

Für beste Ergebnisse passe die Platzhalter (eckige Klammern oder Großbuchstaben) an deine Anforderungen an.

Referenzen

Kategorien:coding| prompts.chat| game-development| html5

Diskussion