const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); const scoreEl = document.getElementById('score'); const keys = new Set(); const gravity = 1900; const groundY = 420; const state = { running: true, lastTs: performance.now(), score: 0, stepCarry: 0, player: { x: 160, y: 0, width: 64, height: 76, standingHeight: 76, duckHeight: 48, vx: 0, vy: 0, speed: 300, jumpPower: 760, onGround: true, ducking: false } }; state.player.y = groundY - state.player.height; window.addEventListener('keydown', (e) => { if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) { e.preventDefault(); } keys.add(e.key); if (e.key === 'ArrowUp' && state.player.onGround) { state.player.vy = -state.player.jumpPower; state.player.onGround = false; } }); window.addEventListener('keyup', (e) => keys.delete(e.key)); function drawBackground() { ctx.fillStyle = '#8ddcff'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#88d34f'; ctx.fillRect(0, groundY, canvas.width, canvas.height - groundY); } function drawTRex(p) { ctx.fillStyle = '#35535f'; ctx.fillRect(p.x, p.y, p.width, p.height); ctx.fillStyle = '#27404a'; ctx.fillRect(p.x + p.width - 12, p.y + 14, 7, 7); // eye ctx.fillRect(p.x + 10, p.y + p.height - 8, 14, 8); // foot1 ctx.fillRect(p.x + p.width - 24, p.y + p.height - 8, 14, 8); // foot2 } function updatePlayer(dt) { const p = state.player; let move = 0; if (keys.has('ArrowLeft')) move -= 1; if (keys.has('ArrowRight')) move += 1; p.ducking = keys.has('ArrowDown') && p.onGround; const targetHeight = p.ducking ? p.duckHeight : p.standingHeight; if (targetHeight !== p.height) { p.y += p.height - targetHeight; p.height = targetHeight; } p.vx = move * p.speed; const oldX = p.x; p.x += p.vx * dt; p.x = Math.max(0, Math.min(canvas.width - p.width, p.x)); if (p.x > oldX) { state.stepCarry += p.x - oldX; while (state.stepCarry >= 8) { state.score += 1; state.stepCarry -= 8; } } p.vy += gravity * dt; p.y += p.vy * dt; if (p.y + p.height >= groundY) { p.y = groundY - p.height; p.vy = 0; p.onGround = true; } } function tick(ts) { if (!state.running) return; const dt = Math.min((ts - state.lastTs) / 1000, 0.05); state.lastTs = ts; updatePlayer(dt); ctx.clearRect(0, 0, canvas.width, canvas.height); drawBackground(); drawTRex(state.player); scoreEl.textContent = `Score: ${state.score}`; requestAnimationFrame(tick); } requestAnimationFrame((ts) => { state.lastTs = ts; requestAnimationFrame(tick); });