إنشاء لعبة المتاهة على بلوجر وربطها بالإعلانات هو مشروع مربح يجمع بين البرمجة البسيطة والتسويق الإلكتروني. يمكنك رفع اللعبة كصفحة HTML داخل مدونتك، ثم دمج إعلانات مثل Google AdSense أو شبكات بديلة مثل Adsterra لزيادة الأرباح.🕹️ خطوات إنشاء لعبة المتاهة على بلوجر
💰 ربط اللعبة بالإعلانات والربح منها
Google AdSense
بعد نشر عدة ألعاب ومحتوى حصري، قدّم طلبًا للانضمام إلى AdSense. ستظهر الإعلانات بجانب اللعبة أو أسفلها.
شبكات بديلة مثل Adsterra
إذا لم يقبل AdSense مدونتك، يمكنك استخدام شبكات مثل Adsterra أو EonAds التي تقبل مواقع الألعاب بسهولة.
إعلانات داخل اللعبة
يمكنك إدراج بانرات إعلانية أعلى وأسفل اللعبة (720x90) أو على الجوانب (350x250) لزيادة معدل النقرات.
📈 استراتيجيات زيادة الأرباح
تحسين السيو
استخدم كلمات مفتاحية مثل "لعبة المتاهة أونلاين" و"ألعاب ذكاء مجانية".
التسويق عبر السوشيال ميديا
شارك روابط اللعبة على فيسبوك، يوتيوب، وتيك توك لجذب الزوار.
تحديث مستمر
أضف ألعاب جديدة بانتظام للحفاظ على تفاعل الجمهور.
كود اللعبة
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🌀 لعبة المتاهة</title>
<link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700;900&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0a0a12;
--panel: #0f0f1e;
--neon: #00f5ff;
--neon2: #ff006e;
--neon3: #aaff00;
--wall: #1a1a3e;
--wall-glow: #2a2a6e;
--path: #0a0a18;
--player: #00f5ff;
--exit: #aaff00;
--gold: #ffd700;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: var(--bg);
font-family: 'Tajawal', sans-serif;
color: #fff;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
user-select: none;
}
body::before {
content: '';
position: fixed;
inset: 0;
background:
radial-gradient(ellipse at 20% 50%, rgba(0,245,255,0.04) 0%, transparent 60%),
radial-gradient(ellipse at 80% 30%, rgba(255,0,110,0.04) 0%, transparent 60%),
radial-gradient(ellipse at 50% 80%, rgba(170,255,0,0.03) 0%, transparent 60%);
pointer-events: none;
z-index: 0;
}
/* Grid noise texture */
body::after {
content: '';
position: fixed;
inset: 0;
background-image:
linear-gradient(rgba(0,245,255,0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(0,245,255,0.03) 1px, transparent 1px);
background-size: 40px 40px;
pointer-events: none;
z-index: 0;
}
.container {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
padding: 20px;
}
.title {
font-size: clamp(28px, 5vw, 48px);
font-weight: 900;
letter-spacing: 4px;
text-transform: uppercase;
background: linear-gradient(90deg, var(--neon), var(--neon2), var(--neon3));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-shadow: none;
animation: titlePulse 3s ease-in-out infinite;
filter: drop-shadow(0 0 20px rgba(0,245,255,0.4));
}
@keyframes titlePulse {
0%, 100% { filter: drop-shadow(0 0 20px rgba(0,245,255,0.4)); }
50% { filter: drop-shadow(0 0 40px rgba(0,245,255,0.8)); }
}
.hud {
display: flex;
gap: 20px;
align-items: center;
flex-wrap: wrap;
justify-content: center;
}
.hud-item {
background: rgba(0,245,255,0.05);
border: 1px solid rgba(0,245,255,0.2);
border-radius: 8px;
padding: 8px 18px;
font-size: 15px;
font-weight: 700;
display: flex;
align-items: center;
gap: 8px;
color: #fff;
backdrop-filter: blur(10px);
}
.hud-item span.val {
color: var(--neon);
font-size: 20px;
min-width: 30px;
text-align: center;
}
.hud-item.timer span.val { color: var(--neon2); }
.hud-item.score span.val { color: var(--gold); }
#maze-wrapper {
position: relative;
}
#maze-canvas {
display: block;
border-radius: 12px;
border: 2px solid rgba(0,245,255,0.3);
box-shadow:
0 0 30px rgba(0,245,255,0.15),
0 0 80px rgba(0,245,255,0.05),
inset 0 0 30px rgba(0,0,0,0.5);
cursor: none;
}
.controls {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
margin-top: 8px;
}
.controls-row {
display: flex;
gap: 8px;
}
.btn-ctrl {
width: 52px;
height: 52px;
background: rgba(0,245,255,0.07);
border: 1.5px solid rgba(0,245,255,0.3);
border-radius: 10px;
color: var(--neon);
font-size: 22px;
cursor: pointer;
transition: all 0.15s;
display: flex;
align-items: center;
justify-content: center;
-webkit-tap-highlight-color: transparent;
}
.btn-ctrl:active, .btn-ctrl.pressed {
background: rgba(0,245,255,0.25);
border-color: var(--neon);
box-shadow: 0 0 20px rgba(0,245,255,0.4);
transform: scale(0.92);
}
.actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
justify-content: center;
}
.btn-action {
padding: 10px 24px;
border-radius: 8px;
border: none;
font-family: 'Tajawal', sans-serif;
font-size: 15px;
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
letter-spacing: 1px;
}
.btn-new {
background: linear-gradient(135deg, var(--neon), #0090a8);
color: #000;
}
.btn-new:hover {
box-shadow: 0 0 25px rgba(0,245,255,0.6);
transform: translateY(-2px);
}
.btn-diff {
background: rgba(255,0,110,0.1);
border: 1.5px solid var(--neon2);
color: var(--neon2);
}
.btn-diff:hover {
background: rgba(255,0,110,0.25);
box-shadow: 0 0 20px rgba(255,0,110,0.4);
transform: translateY(-2px);
}
/* Overlay */
.overlay {
position: absolute;
inset: 0;
background: rgba(10,10,18,0.92);
border-radius: 12px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16px;
backdrop-filter: blur(6px);
z-index: 10;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.overlay h2 {
font-size: 32px;
font-weight: 900;
background: linear-gradient(90deg, var(--neon3), var(--neon));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
filter: drop-shadow(0 0 20px rgba(170,255,0,0.5));
animation: bounce 0.5s ease;
}
.overlay .win-icon {
font-size: 64px;
animation: spinBounce 0.6s ease;
}
@keyframes bounce {
0% { transform: scale(0.5); opacity: 0; }
70% { transform: scale(1.15); }
100% { transform: scale(1); opacity: 1; }
}
@keyframes spinBounce {
0% { transform: scale(0) rotate(-180deg); opacity: 0; }
80% { transform: scale(1.2) rotate(10deg); }
100% { transform: scale(1) rotate(0deg); opacity: 1; }
}
.overlay p {
color: rgba(255,255,255,0.7);
font-size: 16px;
text-align: center;
}
.overlay .stat {
color: var(--gold);
font-size: 20px;
font-weight: 700;
}
.hint {
font-size: 12px;
color: rgba(255,255,255,0.3);
text-align: center;
}
.difficulty-badge {
padding: 4px 14px;
border-radius: 20px;
font-size: 13px;
font-weight: 700;
letter-spacing: 2px;
}
.d-easy { background: rgba(170,255,0,0.15); color: var(--neon3); border: 1px solid var(--neon3); }
.d-medium { background: rgba(0,245,255,0.15); color: var(--neon); border: 1px solid var(--neon); }
.d-hard { background: rgba(255,0,110,0.15); color: var(--neon2); border: 1px solid var(--neon2); }
@media (max-width: 500px) {
.btn-ctrl { width: 44px; height: 44px; font-size: 18px; }
}
</style>
</head>
<body>
<div class="container">
<div class="title">🌀 المتاهة</div>
<div class="hud">
<div class="hud-item">
<span>المستوى</span>
<span class="val" id="level-display">1</span>
</div>
<div class="hud-item timer">
<span>⏱️</span>
<span class="val" id="timer-display">00:00</span>
</div>
<div class="hud-item score">
<span>★</span>
<span class="val" id="score-display">0</span>
</div>
<div id="diff-badge" class="difficulty-badge d-medium">متوسط</div>
</div>
<div id="maze-wrapper">
<canvas id="maze-canvas"></canvas>
<!-- Overlay injected by JS -->
</div>
<!-- Mobile D-pad -->
<div class="controls" id="dpad">
<div class="controls-row">
<button class="btn-ctrl" data-dir="up" aria-label="أعلى">▲</button>
</div>
<div class="controls-row">
<button class="btn-ctrl" data-dir="left" aria-label="يسار">◀</button>
<button class="btn-ctrl" data-dir="down" aria-label="أسفل">▼</button>
<button class="btn-ctrl" data-dir="right" aria-label="يمين">▶</button>
</div>
</div>
<div class="actions">
<button class="btn-action btn-new" id="btn-new">🔄 متاهة جديدة</button>
<button class="btn-action btn-diff" id="btn-diff">⚡ تغيير الصعوبة</button>
</div>
<p class="hint">← → ↑ ↓ للحركة | اصل إلى النقطة الخضراء ✦</p>
</div>
<script>
// ─── Config ───────────────────────────────────────────────────
const DIFFICULTIES = [
{ name: 'سهل', label: 'سهل', cls: 'd-easy', cols: 11, rows: 11, speed: 1 },
{ name: 'متوسط', label: 'متوسط', cls: 'd-medium', cols: 17, rows: 17, speed: 1.5 },
{ name: 'صعب', label: 'صعب', cls: 'd-hard', cols: 23, rows: 23, speed: 2 },
];
let diffIdx = 1;
// ─── State ────────────────────────────────────────────────────
let maze = [], cols = 0, rows = 0, cellSize = 0;
let player = { x: 0, y: 0 };
let exit = { x: 0, y: 0 };
let coins = [];
let level = 1, score = 0;
let timerInterval = null, startTime = null, elapsed = 0;
let gameRunning = false;
let trail = [];
let overlayEl = null;
let particles = [];
let animFrameId = null;
const canvas = document.getElementById('maze-canvas');
const ctx = canvas.getContext('2d');
const timerEl = document.getElementById('timer-display');
const scoreEl = document.getElementById('score-display');
const levelEl = document.getElementById('level-display');
const diffBadge = document.getElementById('diff-badge');
// ─── Maze Generation (Recursive Backtracker) ──────────────────
function generateMaze(c, r) {
const grid = Array.from({ length: r }, () =>
Array.from({ length: c }, () => ({ visited: false, walls: { top: true, right: true, bottom: true, left: true } }))
);
function idx(x, y) { return y * c + x; }
const stack = [];
const start = { x: 0, y: 0 };
grid[0][0].visited = true;
stack.push(start);
const dirs = [
{ dx: 0, dy: -1, wall: 'top', opp: 'bottom' },
{ dx: 1, dy: 0, wall: 'right', opp: 'left' },
{ dx: 0, dy: 1, wall: 'bottom', opp: 'top' },
{ dx:-1, dy: 0, wall: 'left', opp: 'right' },
];
while (stack.length) {
const cur = stack[stack.length - 1];
const neighbors = dirs.map(d => ({ x: cur.x + d.dx, y: cur.y + d.dy, ...d }))
.filter(n => n.x >= 0 && n.y >= 0 && n.x < c && n.y < r && !grid[n.y][n.x].visited);
if (!neighbors.length) { stack.pop(); continue; }
const chosen = neighbors[Math.floor(Math.random() * neighbors.length)];
grid[cur.y][cur.x].walls[chosen.wall] = false;
grid[chosen.y][chosen.x].walls[chosen.opp] = false;
grid[chosen.y][chosen.x].visited = true;
stack.push({ x: chosen.x, y: chosen.y });
}
return grid;
}
// ─── Canvas sizing ────────────────────────────────────────────
function calcSize() {
const maxW = Math.min(window.innerWidth - 32, 520);
const maxH = Math.min(window.innerHeight - 280, 520);
const diff = DIFFICULTIES[diffIdx];
const cellW = Math.floor(maxW / diff.cols);
const cellH = Math.floor(maxH / diff.rows);
cellSize = Math.max(12, Math.min(cellW, cellH));
canvas.width = cellSize * diff.cols;
canvas.height = cellSize * diff.rows;
}
// ─── Place coins randomly ─────────────────────────────────────
function placeCoins() {
coins = [];
const count = Math.floor((cols * rows) * 0.06);
const used = new Set([`0,0`, `${exit.x},${exit.y}`]);
let tries = 0;
while (coins.length < count && tries < 1000) {
tries++;
const x = Math.floor(Math.random() * cols);
const y = Math.floor(Math.random() * rows);
const key = `${x},${y}`;
if (!used.has(key)) { used.add(key); coins.push({ x, y, collected: false }); }
}
}
// ─── New Game ─────────────────────────────────────────────────
function newGame(keepLevel = false) {
if (!keepLevel) { level = 1; score = 0; }
stopTimer();
const diff = DIFFICULTIES[diffIdx];
cols = diff.cols; rows = diff.rows;
calcSize();
maze = generateMaze(cols, rows);
player = { x: 0, y: 0 };
exit = { x: cols - 1, y: rows - 1 };
trail = [];
particles = [];
placeCoins();
removeOverlay();
gameRunning = true;
startTime = Date.now();
startTimer();
levelEl.textContent = level;
scoreEl.textContent = score;
updateDiffBadge();
render();
}
function nextLevel() {
level++;
score += 200 + Math.floor((60 - Math.min(elapsed, 60)) * 5);
newGame(true);
}
function updateDiffBadge() {
const diff = DIFFICULTIES[diffIdx];
diffBadge.className = 'difficulty-badge ' + diff.cls;
diffBadge.textContent = diff.label;
}
// ─── Timer ────────────────────────────────────────────────────
function startTimer() {
startTime = Date.now();
timerInterval = setInterval(() => {
elapsed = Math.floor((Date.now() - startTime) / 1000);
const m = String(Math.floor(elapsed / 60)).padStart(2, '0');
const s = String(elapsed % 60).padStart(2, '0');
timerEl.textContent = `${m}:${s}`;
}, 500);
}
function stopTimer() {
clearInterval(timerInterval);
timerInterval = null;
}
// ─── Rendering ────────────────────────────────────────────────
function render() {
if (animFrameId) cancelAnimationFrame(animFrameId);
animFrameId = requestAnimationFrame(() => {
drawMaze();
updateParticles();
animFrameId = null;
});
}
function drawMaze() {
const W = canvas.width, H = canvas.height;
ctx.clearRect(0, 0, W, H);
// Background
ctx.fillStyle = '#080812';
ctx.fillRect(0, 0, W, H);
// Trail
for (let i = 0; i < trail.length; i++) {
const t = trail[i];
const alpha = (i / trail.length) * 0.18;
ctx.fillStyle = `rgba(0,245,255,${alpha})`;
ctx.fillRect(t.x * cellSize + 2, t.y * cellSize + 2, cellSize - 4, cellSize - 4);
}
// Cells & Walls
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
const cell = maze[y][x];
const px = x * cellSize, py = y * cellSize;
// Distance-based subtle tint
const dx = x - exit.x, dy = y - exit.y;
const dist = Math.sqrt(dx * dx + dy * dy);
const maxDist = Math.sqrt(cols * cols + rows * rows);
const t = 1 - dist / maxDist;
ctx.fillStyle = `rgba(170,255,0,${t * 0.04})`;
ctx.fillRect(px, py, cellSize, cellSize);
// Walls
ctx.strokeStyle = '#2a2a6e';
ctx.lineWidth = 2;
ctx.shadowBlur = 0;
ctx.beginPath();
if (cell.walls.top) { ctx.moveTo(px, py); ctx.lineTo(px + cellSize, py); }
if (cell.walls.right) { ctx.moveTo(px + cellSize, py); ctx.lineTo(px + cellSize, py + cellSize); }
if (cell.walls.bottom) { ctx.moveTo(px, py + cellSize); ctx.lineTo(px + cellSize, py + cellSize); }
if (cell.walls.left) { ctx.moveTo(px, py); ctx.lineTo(px, py + cellSize); }
ctx.stroke();
}
}
// Outer border glow
ctx.strokeStyle = 'rgba(0,245,255,0.4)';
ctx.lineWidth = 2;
ctx.strokeRect(1, 1, W - 2, H - 2);
// Exit
{
const ex = exit.x * cellSize + cellSize / 2;
const ey = exit.y * cellSize + cellSize / 2;
const r = cellSize * 0.32;
const grad = ctx.createRadialGradient(ex, ey, 0, ex, ey, r * 2);
grad.addColorStop(0, 'rgba(170,255,0,0.9)');
grad.addColorStop(0.5, 'rgba(170,255,0,0.4)');
grad.addColorStop(1, 'rgba(170,255,0,0)');
ctx.fillStyle = grad;
ctx.beginPath(); ctx.arc(ex, ey, r * 2, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = '#aaff00';
ctx.shadowColor = '#aaff00';
ctx.shadowBlur = 15;
ctx.beginPath(); ctx.arc(ex, ey, r, 0, Math.PI * 2); ctx.fill();
ctx.shadowBlur = 0;
// Pulsing ring
const pulse = (Date.now() % 1200) / 1200;
ctx.strokeStyle = `rgba(170,255,0,${1 - pulse})`;
ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.arc(ex, ey, r + pulse * r * 2.5, 0, Math.PI * 2); ctx.stroke();
}
// Coins
coins.forEach(coin => {
if (coin.collected) return;
const cx = coin.x * cellSize + cellSize / 2;
const cy = coin.y * cellSize + cellSize / 2;
const r = cellSize * 0.18;
ctx.fillStyle = '#ffd700';
ctx.shadowColor = '#ffd700';
ctx.shadowBlur = 8;
ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI * 2); ctx.fill();
ctx.shadowBlur = 0;
});
// Particles
particles.forEach(p => {
ctx.globalAlpha = p.alpha;
ctx.fillStyle = p.color;
ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); ctx.fill();
ctx.globalAlpha = 1;
});
// Player
{
const px = player.x * cellSize + cellSize / 2;
const py = player.y * cellSize + cellSize / 2;
const r = cellSize * 0.3;
const grad = ctx.createRadialGradient(px, py, 0, px, py, r * 2.5);
grad.addColorStop(0, 'rgba(0,245,255,0.4)');
grad.addColorStop(1, 'rgba(0,245,255,0)');
ctx.fillStyle = grad;
ctx.beginPath(); ctx.arc(px, py, r * 2.5, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = '#00f5ff';
ctx.shadowColor = '#00f5ff';
ctx.shadowBlur = 20;
ctx.beginPath(); ctx.arc(px, py, r, 0, Math.PI * 2); ctx.fill();
// Inner bright dot
ctx.fillStyle = '#fff';
ctx.shadowBlur = 5;
ctx.beginPath(); ctx.arc(px, py, r * 0.35, 0, Math.PI * 2); ctx.fill();
ctx.shadowBlur = 0;
}
}
// ─── Particles ────────────────────────────────────────────────
function spawnParticles(x, y, color, count = 8) {
for (let i = 0; i < count; i++) {
const angle = (Math.PI * 2 / count) * i + Math.random() * 0.5;
const speed = 1 + Math.random() * 2;
particles.push({
x: x * cellSize + cellSize / 2,
y: y * cellSize + cellSize / 2,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed,
r: 2 + Math.random() * 2,
alpha: 1,
color,
});
}
}
function updateParticles() {
particles = particles.filter(p => p.alpha > 0.05);
particles.forEach(p => {
p.x += p.vx; p.y += p.vy;
p.alpha -= 0.04;
p.r *= 0.97;
});
}
// ─── Movement ─────────────────────────────────────────────────
function canMove(x, y, dir) {
const cell = maze[y][x];
if (dir === 'up' && !cell.walls.top) return true;
if (dir === 'down' && !cell.walls.bottom) return true;
if (dir === 'left' && !cell.walls.left) return true;
if (dir === 'right' && !cell.walls.right) return true;
return false;
}
function move(dir) {
if (!gameRunning) return;
let nx = player.x, ny = player.y;
if (dir === 'up' && canMove(player.x, player.y, 'up')) { ny--; }
else if (dir === 'down' && canMove(player.x, player.y, 'down')) { ny++; }
else if (dir === 'left' && canMove(player.x, player.y, 'left')) { nx--; }
else if (dir === 'right' && canMove(player.x, player.y, 'right')) { nx++; }
else return;
trail.push({ x: player.x, y: player.y });
if (trail.length > 30) trail.shift();
player.x = nx; player.y = ny;
// Collect coin
const coin = coins.find(c => !c.collected && c.x === nx && c.y === ny);
if (coin) {
coin.collected = true;
score += 10;
scoreEl.textContent = score;
spawnParticles(nx, ny, '#ffd700', 6);
}
render();
// Check win
if (player.x === exit.x && player.y === exit.y) {
gameRunning = false;
stopTimer();
spawnParticles(exit.x, exit.y, '#aaff00', 20);
render();
setTimeout(showWin, 300);
}
}
// ─── Overlay ──────────────────────────────────────────────────
function removeOverlay() {
if (overlayEl) { overlayEl.remove(); overlayEl = null; }
}
function showWin() {
removeOverlay();
const bonus = 200 + Math.floor((60 - Math.min(elapsed, 60)) * 5);
score += bonus;
scoreEl.textContent = score;
overlayEl = document.createElement('div');
overlayEl.className = 'overlay';
const m = String(Math.floor(elapsed / 60)).padStart(2, '0');
const s = String(elapsed % 60).padStart(2, '0');
overlayEl.innerHTML = `
<div class="win-icon">🏆</div>
<h2>أحسنت! وصلت!</h2>
<p class="stat">+${bonus} نقطة مكافأة</p>
<p>الوقت: ${m}:${s} | المستوى: ${level}</p>
<button class="btn-action btn-new" onclick="nextLevel()" style="margin-top:8px;font-size:16px;">➡️ المستوى التالي</button>
`;
document.getElementById('maze-wrapper').appendChild(overlayEl);
}
// ─── Keyboard ─────────────────────────────────────────────────
const keyMap = { ArrowUp:'up', ArrowDown:'down', ArrowLeft:'left', ArrowRight:'right',
w:'up', s:'down', a:'left', d:'right',
'ي':'up', 'س':'down', 'ش':'left', 'د':'right' };
document.addEventListener('keydown', e => {
const dir = keyMap[e.key];
if (dir) { e.preventDefault(); move(dir); }
});
// ─── D-pad buttons ────────────────────────────────────────────
document.querySelectorAll('.btn-ctrl').forEach(btn => {
const dir = btn.dataset.dir;
btn.addEventListener('click', () => move(dir));
btn.addEventListener('touchstart', e => { e.preventDefault(); btn.classList.add('pressed'); move(dir); }, { passive: false });
btn.addEventListener('touchend', () => btn.classList.remove('pressed'));
});
// ─── Touch swipe ──────────────────────────────────────────────
let touchStart = null;
canvas.addEventListener('touchstart', e => {
touchStart = { x: e.touches[0].clientX, y: e.touches[0].clientY };
}, { passive: true });
canvas.addEventListener('touchend', e => {
if (!touchStart) return;
const dx = e.changedTouches[0].clientX - touchStart.x;
const dy = e.changedTouches[0].clientY - touchStart.y;
if (Math.abs(dx) < 10 && Math.abs(dy) < 10) return;
if (Math.abs(dx) > Math.abs(dy)) move(dx > 0 ? 'right' : 'left');
else move(dy > 0 ? 'down' : 'up');
touchStart = null;
}, { passive: true });
// ─── Buttons ──────────────────────────────────────────────────
document.getElementById('btn-new').addEventListener('click', () => newGame(false));
document.getElementById('btn-diff').addEventListener('click', () => {
diffIdx = (diffIdx + 1) % DIFFICULTIES.length;
newGame(false);
});
// ─── Resize ───────────────────────────────────────────────────
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => { if (gameRunning) newGame(true); }, 250);
});
// ─── Start ────────────────────────────────────────────────────
newGame(false);
</script>
</body>
</html>
تعليقات
إرسال تعليق