Deriva Axial: Jogo de Labirinto Físico Responsivo para Dispositivos Móveis
De Wikiprompt, a enciclopédia livre de prompts
Deriva Axial: Jogo de Labirinto Físico Responsivo para Dispositivos Móveis Um prompt abrangente para gerar um jogo de labirinto em HTML5 de arquivo único com mecânicas de mudança de gravidade, controles de inclinação para dispositivos móveis e estilo visual Bauhaus.
Conteúdo do PromptSalvar
🌐
<!doctype html>
<html lang="pt-BR">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Axial Drift</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
html, body { width:100%; height:100%; overflow:hidden; background:#1a1a1a; font-family:'Arial Black', Arial, sans-serif; }
#game-container { position:relative; width:100%; height:100%; display:flex; align-items:center; justify-content:center; }
canvas { display:block; background:#f0f0f0; box-shadow:0 0 40px rgba(0,0,0,0.8); border:4px solid #000; }
#ui-overlay { position:absolute; top:10px; left:10px; color:#000; font-size:14px; background:rgba(255,255,255,0.8); padding:8px 12px; border:2px solid #000; box-shadow:4px 4px 0 #000; pointer-events:none; }
#ui-overlay span { font-weight:bold; }
#win-screen { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); background:#ffcc00; border:4px solid #000; box-shadow:8px 8px 0 #000; padding:20px 40px; text-align:center; display:none; z-index:10; }
#win-screen h1 { font-size:32px; margin-bottom:10px; }
#win-screen button { background:#000; color:#fff; border:none; padding:10px 20px; font-size:16px; cursor:pointer; box-shadow:4px 4px 0 #ffcc00; }
#win-screen button:hover { background:#333; }
</style>
</head>
<body>
<div id="game-container">
<canvas id="gameCanvas"></canvas>
<div id="ui-overlay">Tempo: <span id="timer">0.0</span>s | Nível: <span id="level">1</span></div>
<div id="win-screen">
<h1>VÓRTICE ALCANÇADO!</h1>
<p>Tempo: <span id="final-time">0</span>s</p>
<button onclick="restartGame()">JOGAR NOVAMENTE</button>
</div>
</div>
<script>
(function() {
'use strict';
// ===== CONFIGURAÇÕES =====
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const uiTimer = document.getElementById('timer');
const uiLevel = document.getElementById('level');
const winScreen = document.getElementById('win-screen');
const finalTime = document.getElementById('final-time');
// Dimensões lógicas do jogo (escala fixa)
const GAME_WIDTH = 800;
const GAME_HEIGHT = 600;
// Física
const GRAVITY_MAX = 1500; // px/s²
const FRICTION = 0.98;
const DAMPING = 0.995;
const MARBLE_RADIUS = 12;
const VORTEX_RADIUS = 30;
// Estado do jogo
let marble = { x: 100, y: 100, vx: 0, vy: 0 };
let gravity = { x: 0, y: 800 }; // vetor gravidade inicial (aponta para baixo)
let mazeWalls = [];
let trapdoors = [];
let vortex = { x: 700, y: 500 };
let level = 1;
let startTime = 0;
let elapsedTime = 0;
let gameActive = true;
let lastTimestamp = 0;
// Controle de entrada
let isDragging = false;
let lastMouseX = 0, lastMouseY = 0;
let deviceTiltX = 0, deviceTiltY = 0;
let useDeviceOrientation = false;
// ===== GERAÇÃO DO LABIRINTO =====
function generateMaze(levelNum) {
mazeWalls = [];
trapdoors = [];
// Paredes externas
mazeWalls.push({ x: 20, y: 20, w: 760, h: 10 });
mazeWalls.push({ x: 20, y: 570, w: 760, h: 10 });
mazeWalls.push({ x: 20, y: 20, w: 10, h: 560 });
mazeWalls.push({ x: 770, y: 20, w: 10, h: 560 });
// Paredes internas baseadas no nível
if (levelNum === 1) {
// Nível 1 - labirinto simples
mazeWalls.push({ x: 200, y: 20, w: 10, h: 200 });
mazeWalls.push({ x: 200, y: 300, w: 10, h: 280 });
mazeWalls.push({ x: 400, y: 20, w: 10, h: 150 });
mazeWalls.push({ x: 400, y: 250, w: 10, h: 200 });
mazeWalls.push({ x: 600, y: 150, w: 10, h: 250 });
mazeWalls.push({ x: 600, y: 480, w: 10, h: 100 });
mazeWalls.push({ x: 300, y: 400, w: 200, h: 10 });
// Armadilhas
trapdoors.push({ x: 350, y: 250, w: 60, h: 60, active: true, timer: 0, interval: 2.0 });
trapdoors.push({ x: 550, y: 350, w: 50, h: 50, active: true, timer: 1.0, interval: 1.5 });
// Vórtice
vortex = { x: 700, y: 500 };
marble = { x: 100, y: 100, vx: 0, vy: 0 };
} else if (levelNum === 2) {
// Nível 2 - mais complexo
mazeWalls.push({ x: 150, y: 20, w: 10, h: 300 });
mazeWalls.push({ x: 150, y: 400, w: 10, h: 180 });
mazeWalls.push({ x: 300, y: 100, w: 10, h: 200 });
mazeWalls.push({ x: 300, y: 380, w: 10, h: 200 });
mazeWalls.push({ x: 450, y: 20, w: 10, h: 150 });
mazeWalls.push({ x: 450, y: 250, w: 10, h: 250 });
mazeWalls.push({ x: 600, y: 100, w: 10, h: 300 });
mazeWalls.push({ x: 600, y: 480, w: 10, h: 100 });
mazeWalls.push({ x: 250, y: 300, w: 150, h: 10 });
mazeWalls.push({ x: 500, y: 200, w: 150, h: 10 });
trapdoors.push({ x: 200, y: 200, w: 50, h: 50, active: true, timer: 0, interval: 1.5 });
trapdoors.push({ x: 400, y: 350, w: 60, h: 60, active: true, timer: 0.5, interval: 2.0 });
trapdoors.push({ x: 550, y: 150, w: 40, h: 40, active: true, timer: 1.5, interval: 1.0 });
vortex = { x: 700, y: 500 };
marble = { x: 100, y: 100, vx: 0, vy: 0 };
} else {
// Nível 3+ - aleatório
for (let i = 0; i < 8; i++) {
let x = 50 + Math.random() * 650;
let y = 50 + Math.random() * 450;
let w = 80 + Math.random() * 120;
let h = 10 + Math.random() * 20;
mazeWalls.push({ x, y, w, h });
}
for (let i = 0; i < 5; i++) {
let x = 50 + Math.random() * 650;
let y = 50 + Math.random() * 450;
let w = 10 + Math.random() * 20;
let h = 80 + Math.random() * 120;
mazeWalls.push({ x, y, w, h });
}
for (let i = 0; i < 4; i++) {
trapdoors.push({
x: 50 + Math.random() * 650,
y: 50 + Math.random() * 450,
w: 40 + Math.random() * 30,
h: 40 + Math.random() * 30,
active: true,
timer: Math.random() * 2,
interval: 1.0 + Math.random() * 2
});
}
vortex = { x: 700, y: 500 };
marble = { x: 100, y: 100, vx: 0, vy: 0 };
}
}
// ===== FÍSICA =====
function updatePhysics(dt) {
if (!gameActive) return;
// Aplica gravidade
marble.vx += gravity.x * dt;
marble.vy += gravity.y * dt;
// Amortecimento e fricção
marble.vx *= (FRICTION * DAMPING);
marble.vy *= (FRICTION * DAMPING);
// Atualiza posição
marble.x += marble.vx * dt;
marble.y += marble.vy * dt;
// Colisão com paredes
for (let wall of mazeWalls) {
// Colisão horizontal
if (marble.x + MARBLE_RADIUS > wall.x && marble.x - MARBLE_RADIUS < wall.x + wall.w &&
marble.y + MARBLE_RADIUS > wall.y && marble.y - MARBLE_RADIUS < wall.y + wall.h) {
// Determina lado da colisão
let overlapLeft = (marble.x + MARBLE_RADIUS) - wall.x;
let overlapRight = (wall.x + wall.w) - (marble.x - MARBLE_RADIUS);
let overlapTop = (marble.y + MARBLE_RADIUS) - wall.y;
let overlapBottom = (wall.y + wall.h) - (marble.y - MARBLE_RADIUS);
let minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom);
if (minOverlap === overlapLeft) {
marble.x = wall.x - MARBLE_RADIUS;
marble.vx *= -0.3;
} else if (minOverlap === overlapRight) {
marble.x = wall.x + wall.w + MARBLE_RADIUS;
marble.vx *= -0.3;
} else if (minOverlap === overlapTop) {
marble.y = wall.y - MARBLE_RADIUS;
marble.vy *= -0.3;
} else {
marble.y = wall.y + wall.h + MARBLE_RADIUS;
marble.vy *= -0.3;
}
}
}
// Limites do canvas
if (marble.x < MARBLE_RADIUS) { marble.x = MARBLE_RADIUS; marble.vx *= -0.5; }
if (marble.x > GAME_WIDTH - MARBLE_RADIUS) { marble.x = GAME_WIDTH - MARBLE_RADIUS; marble.vx *= -0.5; }
if (marble.y < MARBLE_RADIUS) { marble.y = MARBLE_RADIUS; marble.vy *= -0.5; }
if (marble.y > GAME_HEIGHT - MARBLE_RADIUS) { marble.y = GAME_HEIGHT - MARBLE_RADIUS; marble.vy *= -0.5; }
// Atualiza armadilhas
for (let trap of trapdoors) {
trap.timer += dt;
if (trap.timer >= trap.interval) {
trap.active = !trap.active;
trap.timer = 0;
}
// Colisão com armadilha ativa
if (trap.active) {
if (marble.x + MARBLE_RADIUS > trap.x && marble.x - MARBLE_RADIUS < trap.x + trap.w &&
marble.y + MARBLE_RADIUS > trap.y && marble.y - MARBLE_RADIUS < trap.y + trap.h) {
// Reinicia posição
marble.x = 100;
marble.y = 100;
marble.vx = 0;
marble.vy = 0;
}
}
}
// Verifica vórtice (vitória)
let dx = marble.x - vortex.x;
let dy = marble.y - vortex.y;
let dist = Math.sqrt(dx*dx + dy*dy);
if (dist < VORTEX_RADIUS) {
gameActive = false;
elapsedTime = (performance.now() - startTime) / 1000;
finalTime.textContent = elapsedTime.toFixed(1);
winScreen.style.display = 'block';
}
}
// ===== RENDERIZAÇÃO =====
function render() {
ctx.clearRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
// Fundo
ctx.fillStyle = '#f0f0f0';
ctx.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
// Sombra projetada
ctx.shadowColor = 'rgba(0,0,0,0.3)';
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
// Paredes (estilo Bauhaus)
for (let wall of mazeWalls) {
ctx.fillStyle = '#e63946'; // vermelho
ctx.fillRect(wall.x, wall.y, wall.w, wall.h);
ctx.strokeStyle = '#000';
ctx.lineWidth = 3;
ctx.strokeRect(wall.x, wall.y, wall.w, wall.h);
}
// Armadilhas
for (let trap of trapdoors) {
if (trap.active) {
ctx.fillStyle = '#2a9d8f'; // verde
ctx.fillRect(trap.x, trap.y, trap.w, trap.h);
ctx.strokeStyle = '#000';
ctx.lineWidth = 3;
ctx.strokeRect(trap.x, trap.y, trap.w, trap.h);
// Padrão de perigo
ctx.fillStyle = '#000';
ctx.font = 'bold 20px Arial';
ctx.fillText('!', trap.x + trap.w/2 - 8, trap.y + trap.h/2 + 7);
} else {
ctx.fillStyle = '#264653'; // azul escuro
ctx.fillRect(trap.x, trap.y, trap.w, trap.h);
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.strokeRect(trap.x, trap.y, trap.w, trap.h);
}
}
// Vórtice
ctx.shadowBlur = 20;
ctx.fillStyle = '#f4a261'; // laranja
ctx.beginPath();
ctx.arc(vortex.x, vortex.y, VORTEX_RADIUS, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#000';
ctx.lineWidth = 4;
ctx.stroke();
ctx.fillStyle = '#000';
ctx.font = 'bold 16px Arial';
ctx.fillText('V', vortex.x - 8, vortex.y + 6);
// Mármore
ctx.shadowBlur = 25;
ctx.fillStyle = '#264653';
ctx.beginPath();
ctx.arc(marble.x, marble.y, MARBLE_RADIUS, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#000';
ctx.lineWidth = 3;
ctx.stroke();
// Brilho
ctx.fillStyle = 'rgba(255,255,255,0.3)';
ctx.beginPath();
ctx.arc(marble.x - 3, marble.y - 3, MARBLE_RADIUS * 0.4, 0, Math.PI * 2);
ctx.fill();
// Reset sombra
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// Vetor de gravidade (indicador)
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(GAME_WIDTH - 80, 50);
ctx.lineTo(GAME_WIDTH - 80 + gravity.x * 0.03, 50 + gravity.y * 0.03);
ctx.stroke();
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.arc(GAME_WIDTH - 80 + gravity.x * 0.03, 50 + gravity.y * 0.03, 5, 0, Math.PI * 2);
ctx.fill();
ctx.font = '12px Arial';
ctx.fillText('GRAV', GAME_WIDTH - 110, 40);
}
// ===== LOOP PRINCIPAL =====
function gameLoop(timestamp) {
let dt = (timestamp - lastTimestamp) / 1000;
if (dt > 0.1) dt = 0.1; // proteção contra saltos
lastTimestamp = timestamp;
if (gameActive) {
elapsedTime = (timestamp - startTime) / 1000;
uiTimer.textContent = elapsedTime.toFixed(1);
}
updatePhysics(dt);
render();
requestAnimationFrame(gameLoop);
}
// ===== CONTROLES =====
function handleMouseDown(e) {
isDragging = true;
lastMouseX = e.clientX;
lastMouseY = e.clientY;
}
function handleMouseMove(e) {
if (!isDragging) return;
let dx = e.clientX - lastMouseX;
let dy = e.clientY - lastMouseY;
// Ajusta gravidade baseado no arrasto
gravity.x = dx * 15;
gravity.y = dy * 15;
// Limita magnitude
let mag = Math.sqrt(gravity.x * gravity.x + gravity.y * gravity.y);
if (mag > GRAVITY_MAX) {
gravity.x = (gravity.x / mag) * GRAVITY_MAX;
gravity.y = (gravity.y / mag) * GRAVITY_MAX;
}
lastMouseX = e.clientX;
lastMouseY = e.clientY;
}
function handleMouseUp() {
isDragging = false;
gravity.x = 0;
gravity.y = 800; // volta ao padrão
}
// Suporte a orientação do dispositivo
function handleOrientation(e) {
if (!useDeviceOrientation) return;
// gamma: inclinação esquerda/direita (-90 a 90)
// beta: inclinação frente/trás (-180 a 180)
let gamma = e.gamma || 0;
let beta = e.beta || 0;
// Converte para gravidade
gravity.x = (gamma / 90) * GRAVITY_MAX;
gravity.y = (beta / 90) * GRAVITY_MAX;
// Limita
let mag = Math.sqrt(gravity.x * gravity.x + gravity.y * gravity.y);
if (mag > GRAVITY_MAX) {
gravity.x = (gravity.x / mag) * GRAVITY_MAX;
gravity.y = (gravity.y / mag) * GRAVITY_MAX;
}
}
// ===== INICIALIZAÇÃO =====
function resizeCanvas() {
let container = document.getElementById('game-container');
let containerWidth = container.clientWidth;
let containerHeight = container.clientHeight;
let scale = Math.min(containerWidth / GAME_WIDTH, containerHeight / GAME_HEIGHT);
canvas.width = GAME_WIDTH;
canvas.height = GAME_HEIGHT;
canvas.style.width = (GAME_WIDTH * scale) + 'px';
canvas.style.height = (GAME_HEIGHT * scale) + 'px';
}
function restartGame() {
winScreen.style.display = 'none';
level = 1;
uiLevel.textContent = level;
generateMaze(level);
gameActive = true;
startTime = performance.now();
elapsedTime = 0;
gravity = { x: 0, y: 800 };
}
// Eventos
canvas.addEventListener('mousedown', handleMouseDown);
canvas.addEventListener('mousemove', handleMouseMove);
canvas.addEventListener('mouseup', handleMouseUp);
canvas.addEventListener('mouseleave', handleMouseUp);
// Touch support
canvas.addEventListener('touchstart', (e) => {
e.preventDefault();
let touch = e.touches[0];
handleMouseDown({ clientX: touch.clientX, clientY: touch.clientY });
});
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
let touch = e.touches[0];
handleMouseMove({ clientX: touch.clientX, clientY: touch.clientY });
});
canvas.addEventListener('touchend', (e) => {
e.preventDefault();
handleMouseUp();
});
// Device orientation
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', handleOrientation);
useDeviceOrientation = true;
}
window.addEventListener('resize', resizeCanvas);
// Inicia
resizeCanvas();
generateMaze(level);
startTime = performance.now();
lastTimestamp = performance.now();
requestAnimationFrame(gameLoop);
// Expor função de reinício
window.restartGame = restartGame;
})();
</script>
</body>
</html>
Entre para ver o prompt completo
Continuar com:
Ao entrar, você concorda com nossos Termos de uso e Política de privacidade
Uso
Este prompt foi projetado para uso com coding. Copie o conteúdo acima e cole na sua ferramenta de IA preferida.
Para melhores resultados, personalize os marcadores (indicados por colchetes ou maiúsculas) com seus requisitos específicos.
Discussão
0 comentários