Discussion

Axial Drift : Jeu de labyrinthe physique adapté aux mobiles

De Wikiprompt, l’encyclopédie libre de prompts

loshu2000
Contribué parloshu2000Source

17 mai 2026

Axial Drift : Jeu de labyrinthe physique adapté aux mobiles Une invite complète pour générer un jeu de labyrinthe HTML5 en fichier unique avec des mécaniques de changement de gravité, des contrôles d'inclinaison mobile et un style visuel Bauhaus.

Contenu du PromptEnregistrer

🌐
<!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-tap-highlight-color: transparent; } body { background: #1a1a1a; overflow: hidden; touch-action: none; font-family: 'Courier New', monospace; } canvas { display: block; margin: 0 auto; background: #f5f0e8; box-shadow: 0 0 40px rgba(0,0,0,0.8); } #ui { position: fixed; top: 10px; left: 50%; transform: translateX(-50%); color: #ff4500; font-size: 14px; font-weight: bold; letter-spacing: 2px; text-shadow: 2px 2px 0 #000; z-index: 10; background: rgba(0,0,0,0.6); padding: 6px 16px; border: 2px solid #ff4500; border-radius: 4px; pointer-events: none; } #win { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #ffd700; font-size: 28px; font-weight: bold; text-shadow: 3px 3px 0 #000; z-index: 20; display: none; background: rgba(0,0,0,0.8); padding: 20px 40px; border: 4px solid #ffd700; border-radius: 8px; text-align: center; pointer-events: none; } #restart { position: fixed; bottom: 20px; right: 20px; background: #ff4500; color: #fff; border: 3px solid #000; padding: 10px 20px; font-size: 16px; font-weight: bold; cursor: pointer; z-index: 30; border-radius: 4px; box-shadow: 4px 4px 0 #000; } #restart:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0 #000; } </style> </head> <body> <div id="ui">AXIAL DRIFT - TILT TO NAVIGATE</div> <div id="win">VORTEX REACHED!<br>YOU WIN</div> <button id="restart">RESTART</button> <canvas id="gameCanvas"></canvas> <script> (function() { const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const ui = document.getElementById('ui'); const winDiv = document.getElementById('win'); const restartBtn = document.getElementById('restart'); // Game state let W, H, DPR; let marble = { x: 0, y: 0, vx: 0, vy: 0, radius: 12 }; let gravity = { x: 0, y: 0.5 }; let targetGravity = { x: 0, y: 0.5 }; let mazeWalls = []; let trapdoors = []; let vortex = { x: 0, y: 0, radius: 20 }; let gameWon = false; let lastTime = 0; let shakeTimer = 0; // Physics constants const FRICTION = 0.985; const DAMPING = 0.95; const MAX_SPEED = 8; const GRAVITY_STRENGTH = 0.35; const TILT_SENSITIVITY = 0.15; // Maze layout (grid-based, 20x20 cells) const GRID_SIZE = 20; const CELL_SIZE = 40; const mazeLayout = [ "####################", "#S........#........#", "#.#####...#...####.#", "#.#...#...#...#..#.#", "#.#.#.#.#####.#..#.#", "#.#.#.#.....#.#..#.#", "#.#.#####.#.#.#..#.#", "#.#.....#.#.#.#..#.#", "#.#####.#.#.#.#..#.#", "#.....#.#.#.#.#..#.#", "#####.#.#.#.#.#..#.#", "#.....#.#.#.#.#..#.#", "#.#####.#.#.#.#..#.#", "#.#.....#.#.#.#..#.#", "#.#.#####.#.#.#..#.#", "#.#.....#.#.#.#..#.#", "#.#####.#.#.#.#..#.#", "#.....#.#.#.#.#..#.#", "#.....#...V.....#..#", "####################" ]; function initMaze() { mazeWalls = []; trapdoors = []; const rows = mazeLayout.length; const cols = mazeLayout[0].length; for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { const char = mazeLayout[row][col]; const x = col * CELL_SIZE + CELL_SIZE / 2; const y = row * CELL_SIZE + CELL_SIZE / 2; if (char === '#') { mazeWalls.push({ x: x, y: y, w: CELL_SIZE, h: CELL_SIZE, type: 'wall' }); } else if (char === 'S') { marble.x = x; marble.y = y; marble.vx = 0; marble.vy = 0; } else if (char === 'V') { vortex.x = x; vortex.y = y; } else if (char === 'T') { trapdoors.push({ x: x, y: y, w: CELL_SIZE * 0.8, h: CELL_SIZE * 0.8, active: true, timer: 0, phase: Math.random() * Math.PI * 2 }); } } } // Add dynamic trapdoors at strategic positions trapdoors.push( { x: 5 * CELL_SIZE + CELL_SIZE/2, y: 8 * CELL_SIZE + CELL_SIZE/2, w: CELL_SIZE*0.7, h: CELL_SIZE*0.7, active: true, timer: 0, phase: 0 }, { x: 14 * CELL_SIZE + CELL_SIZE/2, y: 12 * CELL_SIZE + CELL_SIZE/2, w: CELL_SIZE*0.7, h: CELL_SIZE*0.7, active: true, timer: 0, phase: Math.PI }, { x: 8 * CELL_SIZE + CELL_SIZE/2, y: 15 * CELL_SIZE + CELL_SIZE/2, w: CELL_SIZE*0.7, h: CELL_SIZE*0.7, active: true, timer: 0, phase: Math.PI/2 }, { x: 12 * CELL_SIZE + CELL_SIZE/2, y: 5 * CELL_SIZE + CELL_SIZE/2, w: CELL_SIZE*0.7, h: CELL_SIZE*0.7, active: true, timer: 0, phase: Math.PI*1.5 } ); } function resizeCanvas() { DPR = window.devicePixelRatio || 1; const maxWidth = window.innerWidth; const maxHeight = window.innerHeight; const mazeWidth = GRID_SIZE * CELL_SIZE; const mazeHeight = GRID_SIZE * CELL_SIZE; const scale = Math.min(maxWidth / mazeWidth, maxHeight / mazeHeight); W = mazeWidth * scale; H = mazeHeight * scale; 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); // Scale marble and vortex positions const scaleFactor = scale; marble.radius = 12 * scaleFactor; vortex.radius = 20 * scaleFactor; // Scale all maze elements mazeWalls.forEach(wall => { wall.x *= scaleFactor; wall.y *= scaleFactor; wall.w *= scaleFactor; wall.h *= scaleFactor; }); trapdoors.forEach(td => { td.x *= scaleFactor; td.y *= scaleFactor; td.w *= scaleFactor; td.h *= scaleFactor; }); marble.x *= scaleFactor; marble.y *= scaleFactor; vortex.x *= scaleFactor; vortex.y *= scaleFactor; } function handleMouse(e) { if (gameWon) return; const rect = canvas.getBoundingClientRect(); const mouseX = e.clientX - rect.left; const mouseY = e.clientY - rect.top; // Map mouse position to gravity direction const centerX = W / 2; const centerY = H / 2; const dx = (mouseX - centerX) / (W / 2); const dy = (mouseY - centerY) / (H / 2); targetGravity.x = dx * GRAVITY_STRENGTH; targetGravity.y = dy * GRAVITY_STRENGTH; } function handleMouseUp() { targetGravity.x = 0; targetGravity.y = 0.5; } function handleOrientation(e) { if (gameWon) return; const gamma = e.gamma; // left/right tilt (-90 to 90) const beta = e.beta; // front/back tilt (-180 to 180) if (gamma !== null && beta !== null) { // Normalize to -1 to 1 range const xTilt = Math.max(-1, Math.min(1, gamma / 45)); const yTilt = Math.max(-1, Math.min(1, (beta - 45) / 45)); targetGravity.x = xTilt * GRAVITY_STRENGTH * 1.5; targetGravity.y = yTilt * GRAVITY_STRENGTH * 1.5; } } function checkCollisions() { // Wall collisions for (const wall of mazeWalls) { const closestX = Math.max(wall.x - wall.w/2, Math.min(marble.x, wall.x + wall.w/2)); const closestY = Math.max(wall.y - wall.h/2, Math.min(marble.y, wall.y + wall.h/2)); const dx = marble.x - closestX; const dy = marble.y - closestY; const dist = Math.sqrt(dx*dx + dy*dy); if (dist < marble.radius) { if (dist === 0) { // Push out marble.x = wall.x + wall.w/2 + marble.radius; } else { const overlap = marble.radius - dist; const nx = dx / dist; const ny = dy / dist; marble.x += nx * overlap; marble.y += ny * overlap; // Reflect velocity const dot = marble.vx * nx + marble.vy * ny; marble.vx -= 2 * dot * nx; marble.vy -= 2 * dot * ny; marble.vx *= 0.8; marble.vy *= 0.8; } } } // Trapdoor collisions for (const td of trapdoors) { if (!td.active) continue; const closestX = Math.max(td.x - td.w/2, Math.min(marble.x, td.x + td.w/2)); const closestY = Math.max(td.y - td.h/2, Math.min(marble.y, td.y + td.h/2)); const dx = marble.x - closestX; const dy = marble.y - closestY; const dist = Math.sqrt(dx*dx + dy*dy); if (dist < marble.radius) { // Bounce off trapdoor if (dist === 0) { marble.x = td.x + td.w/2 + marble.radius; } else { const overlap = marble.radius - dist; const nx = dx / dist; const ny = dy / dist; marble.x += nx * overlap; marble.y += ny * overlap; const dot = marble.vx * nx + marble.vy * ny; marble.vx -= 2 * dot * nx; marble.vy -= 2 * dot * ny; marble.vx *= 0.5; marble.vy *= 0.5; } } } // Boundary check if (marble.x < marble.radius) { marble.x = marble.radius; marble.vx *= -0.5; } if (marble.x > W - marble.radius) { marble.x = W - marble.radius; marble.vx *= -0.5; } if (marble.y < marble.radius) { marble.y = marble.radius; marble.vy *= -0.5; } if (marble.y > H - marble.radius) { marble.y = H - marble.radius; marble.vy *= -0.5; } // Vortex check 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) { gameWon = true; winDiv.style.display = 'block'; } } function updatePhysics(dt) { if (gameWon) 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 * dt * 60; marble.vy += gravity.y * dt * 60; // Apply friction and damping marble.vx *= FRICTION; marble.vy *= FRICTION; // 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; } // Update position marble.x += marble.vx * dt * 60; marble.y += marble.vy * dt * 60; // Update trapdoors const time = performance.now() / 1000; trapdoors.forEach(td => { td.timer += dt; const cycle = Math.sin(time * 2 + td.phase); td.active = cycle > 0; }); checkCollisions(); } function drawBauhausBackground() { // Background ctx.fillStyle = '#f5f0e8'; ctx.fillRect(0, 0, W, H); // Bauhaus geometric pattern ctx.strokeStyle = '#000'; ctx.lineWidth = 2; // Diagonal lines for (let i = -H; i < W; i += 80) { ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i + H, H); ctx.stroke(); } // Circles ctx.fillStyle = '#ff4500'; ctx.beginPath(); ctx.arc(W * 0.1, H * 0.1, 30, 0, Math.PI * 2); ctx.fill(); ctx.stroke(); ctx.fillStyle = '#0047ab'; ctx.beginPath(); ctx.arc(W * 0.9, H * 0.9, 25, 0, Math.PI * 2); ctx.fill(); ctx.stroke(); // Triangles ctx.fillStyle = '#ffd700'; ctx.beginPath(); ctx.moveTo(W * 0.85, H * 0.1); ctx.lineTo(W * 0.95, H * 0.1); ctx.lineTo(W * 0.9, H * 0.2); ctx.closePath(); ctx.fill(); ctx.stroke(); } function drawMaze() { // Draw walls ctx.fillStyle = '#0047ab'; ctx.strokeStyle = '#000'; ctx.lineWidth = 3; ctx.shadowColor = 'rgba(0,0,0,0.5)'; ctx.shadowBlur = 10; ctx.shadowOffsetX = 4; ctx.shadowOffsetY = 4; mazeWalls.forEach(wall => { ctx.fillRect(wall.x - wall.w/2, wall.y - wall.h/2, wall.w, wall.h); ctx.strokeRect(wall.x - wall.w/2, wall.y - wall.h/2, wall.w, wall.h); }); // Draw trapdoors trapdoors.forEach(td => { if (td.active) { ctx.fillStyle = '#ff4500'; ctx.shadowColor = 'rgba(255,69,0,0.5)'; ctx.shadowBlur = 15; ctx.fillRect(td.x - td.w/2, td.y - td.h/2, td.w, td.h); ctx.strokeRect(td.x - td.w/2, td.y - td.h/2, td.w, td.h); // Warning stripes ctx.fillStyle = '#000'; for (let i = 0; i < 3; i++) { ctx.fillRect(td.x - td.w/2, td.y - td.h/2 + i * td.h/3, td.w, 2); } } }); // Draw vortex ctx.shadowColor = 'rgba(255,215,0,0.8)'; ctx.shadowBlur = 20; ctx.fillStyle = '#ffd700'; ctx.beginPath(); ctx.arc(vortex.x, vortex.y, vortex.radius, 0, Math.PI * 2); ctx.fill(); ctx.strokeStyle = '#000'; ctx.lineWidth = 3; ctx.stroke(); // Vortex spiral ctx.strokeStyle = '#000'; ctx.lineWidth = 2; for (let i = 0; i < 3; i++) { ctx.beginPath(); ctx.arc(vortex.x, vortex.y, vortex.radius * (0.3 + i * 0.2), 0, Math.PI * 1.5); ctx.stroke(); } ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; } function drawMarble() { // Marble shadow ctx.shadowColor = 'rgba(0,0,0,0.6)'; ctx.shadowBlur = 15; ctx.shadowOffsetX = 5; ctx.shadowOffsetY = 5; // Marble body 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, '#e0e0e0'); gradient.addColorStop(1, '#808080'); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(marble.x, marble.y, marble.radius, 0, Math.PI * 2); ctx.fill(); // Marble outline ctx.strokeStyle = '#000'; ctx.lineWidth = 2; ctx.stroke(); // Highlight ctx.fillStyle = 'rgba(255,255,255,0.8)'; 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(); ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; } function drawGravityIndicator() { // Gravity direction indicator const centerX = W / 2; const centerY = H / 2; const indicatorX = centerX + gravity.x * 100; const indicatorY = centerY + gravity.y * 100; ctx.strokeStyle = '#000'; ctx.lineWidth = 2; ctx.setLineDash([5, 5]); ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo(indicatorX, indicatorY); ctx.stroke(); ctx.setLineDash([]); // Arrow head const angle = Math.atan2(indicatorY - centerY, indicatorX - centerX); ctx.fillStyle = '#000'; ctx.beginPath(); ctx.moveTo(indicatorX, indicatorY); ctx.lineTo(indicatorX - 10 * Math.cos(angle - 0.4), indicatorY - 10 * Math.sin(angle - 0.4)); ctx.lineTo(indicatorX - 10 * Math.cos(angle + 0.4), indicatorY - 10 * Math.sin(angle + 0.4)); ctx.closePath(); ctx.fill(); } function draw() { ctx.clearRect(0, 0, W, H); drawBauhausBackground(); drawMaze(); drawMarble(); drawGravityIndicator(); // UI text ctx.fillStyle = '#000'; ctx.font = 'bold 12px Courier New'; ctx.fillText('AXIAL DRIFT', 10, 20); ctx.fillText('TILT TO NAVIGATE', 10, 35); } function gameLoop(timestamp) { const dt = Math.min((timestamp - lastTime) / 1000, 0.05); lastTime = timestamp; updatePhysics(dt); draw(); requestAnimationFrame(gameLoop); } // Event listeners canvas.addEventListener('mousedown', handleMouse); canvas.addEventListener('mousemove', (e) => { if (e.buttons === 1) handleMouse(e); }); canvas.addEventListener('mouseup', handleMouseUp); canvas.addEventListener('touchstart', (e) => { e.preventDefault(); const touch = e.touches[0]; handleMouse({ clientX: touch.clientX, clientY: touch.clientY }); }); canvas.addEventListener('touchmove', (e) => { e.preventDefault(); const touch = e.touches[0]; handleMouse({ clientX: touch.clientX, clientY: touch.clientY }); }); canvas.addEventListener('touchend', handleMouseUp); if (window.DeviceOrientationEvent) { window.addEventListener('deviceorientation', handleOrientation, true); } restartBtn.addEventListener('click', () => { gameWon = false; winDiv.style.display = 'none'; initMaze(); resizeCanvas(); gravity = { x: 0, y: 0.5 }; targetGravity = { x: 0, y: 0.5 }; }); // Initialize initMaze(); resizeCanvas(); window.addEventListener('resize', () => { // Re-initialize with new scale const oldScale = W / (GRID_SIZE * CELL_SIZE); const newScale = Math.min(window.innerWidth / (GRID_SIZE * CELL_SIZE), window.innerHeight / (GRID_SIZE * CELL_SIZE)); const ratio = newScale / oldScale; marble.x *= ratio; marble.y *= ratio; marble.radius *= ratio; vortex.x *= ratio; vortex.y *= ratio; vortex.radius *= ratio; mazeWalls.forEach(wall => { wall.x *= ratio; wall.y *= ratio; wall.w *= ratio; wall.h *= ratio; }); trapdoors.forEach(td => { td.x *= ratio; td.y *= ratio; td.w *= ratio; td.h *= ratio; }); resizeCanvas(); }); lastTime = performance.now(); requestAnimationFrame(gameLoop); })(); </script> </body> </html>

Connectez-vous pour voir le prompt complet

Continuer avec:

En vous connectant, vous acceptez nos Conditions et Confidentialité

Utilisation

Ce prompt est conçu pour être utilisé avec coding. Copiez le contenu ci-dessus et collez-le dans votre outil d’IA préféré.

Pour de meilleurs résultats, personnalisez les espaces réservés (indiqués par des crochets ou des majuscules) selon vos besoins.

Références

Catégories :coding| prompts.chat| game-development| html5

Discussion