🎮ArcadeLab

گمشده در امواج

by RapidKnight54
795 lines20.9 KB🛠️ matter.js (physics engine)
▶ Play
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>گمشده در امواج ⛵</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    background: #000814;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    font-family: Tahoma, sans-serif;
    overflow: hidden;
  }
  #game-container {
    position: relative;
    width: 900px;
    height: 600px;
    border-radius: 14px;
    overflow: hidden;
    box-shadow: 0 0 80px rgba(0, 150, 255, 0.4);
  }
  canvas { display: block; width: 100%; height: 100%; }

  /* ==== نوار بالا ==== */
  #top-bar {
    position: absolute;
    top: 12px; left: 12px; right: 12px;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    pointer-events: none;
    direction: ltr;
  }
  .panel {
    background: rgba(0, 20, 45, 0.9);
    border: 1px solid rgba(0, 180, 255, 0.5);
    border-radius: 12px;
    padding: 10px 18px;
    backdrop-filter: blur(8px);
    color: #9df;
    font-size: 14px;
    line-height: 1.9;
    box-shadow: 0 0 25px rgba(0, 150, 255, 0.25);
  }
  .panel b { color: #0ff; font-size: 16px; }

  /* ==== نوار هدف (بالای صفحه) ==== */
  #goal-bar {
    position: absolute;
    top: 90px;
    left: 50%;
    transform: translateX(-50%);
    width: 500px;
    pointer-events: none;
    text-align: center;
  }
  #goal-label {
    color: #ffd966;
    font-size: 13px;
    margin-bottom: 6px;
    text-shadow: 0 0 10px rgba(255, 200, 0, 0.6);
  }
  #goal-track {
    position: relative;
    height: 14px;
    background: rgba(0, 20, 40, 0.85);
    border: 1px solid rgba(0, 180, 255, 0.4);
    border-radius: 8px;
    overflow: hidden;
  }
  #goal-fill {
    height: 100%;
    width: 0%;
    background: linear-gradient(90deg, #06f, #0ff, #0f8);
    transition: width 0.15s;
    box-shadow: 0 0 20px #0ff inset;
  }
  #goal-marker {
    position: absolute;
    top: -4px;
    right: 6px;
    font-size: 18px;
  }

  /* ==== راهنمای زنده ==== */
  #live-hint {
    position: absolute;
    top: 145px;
    left: 50%;
    transform: translateX(-50%);
    color: #fff;
    font-size: 15px;
    background: rgba(0, 30, 60, 0.85);
    border: 1px solid rgba(0, 200, 255, 0.5);
    border-radius: 20px;
    padding: 8px 22px;
    pointer-events: none;
    text-align: center;
    box-shadow: 0 0 25px rgba(0, 200, 255, 0.3);
    transition: all 0.25s;
    min-width: 280px;
  }

  /* ==== کنترل‌ها ==== */
  #controls {
    position: absolute;
    bottom: 14px;
    left: 14px; right: 14px;
    display: flex;
    gap: 12px;
    justify-content: center;
    direction: ltr;
  }
  .ctrl {
    background: rgba(0, 20, 45, 0.92);
    border: 1px solid rgba(0, 180, 255, 0.5);
    border-radius: 12px;
    padding: 10px 16px;
    color: #9df;
    font-size: 12px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 170px;
    box-shadow: 0 0 20px rgba(0, 150, 255, 0.2);
  }
  .ctrl label { color: #6cf; font-size: 12px; font-weight: bold; }
  .ctrl .sub { color: #4a7; font-size: 10px; }
  input[type=range] {
    width: 100%;
    accent-color: #0af;
    cursor: pointer;
    height: 22px;
  }
  .val { color: #0ff; font-weight: bold; font-size: 14px; }

  /* ==== دکمه‌های جهتی (بزرگ و واضح) ==== */
  #direction-hint {
    display: flex;
    gap: 6px;
    justify-content: center;
    margin-top: 4px;
  }
  .dir-arrow {
    font-size: 22px;
    color: #2a4a6a;
    transition: all 0.15s;
    padding: 2px 8px;
  }
  .dir-arrow.active {
    color: #0ff;
    text-shadow: 0 0 15px #0ff;
    transform: scale(1.3);
  }

  /* ==== Overlay شروع ==== */
  #overlay {
    position: absolute;
    inset: 0;
    background: rgba(0, 8, 20, 0.96);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 16px;
    color: #fff;
    text-align: center;
    z-index: 10;
    padding: 30px;
  }
  #overlay h1 {
    font-size: 34px;
    color: #0ff;
    text-shadow: 0 0 30px #0af, 0 0 60px #06f;
    letter-spacing: 2px;
  }
  #overlay .story {
    font-size: 15px;
    color: #9df;
    max-width: 540px;
    line-height: 2.2;
  }
  #overlay .story b { color: #ffd966; }
  #overlay .how-to {
    background: rgba(0, 30, 60, 0.7);
    border: 1px solid rgba(0, 180, 255, 0.4);
    border-radius: 12px;
    padding: 16px 24px;
    max-width: 540px;
    text-align: right;
    color: #cfe;
    font-size: 14px;
    line-height: 2.2;
  }
  #overlay .how-to h3 { color: #0ff; margin-bottom: 8px; text-align: center; }
  #overlay button {
    background: linear-gradient(135deg, #06f, #0af);
    border: none;
    color: #fff;
    padding: 16px 50px;
    font-size: 20px;
    border-radius: 12px;
    cursor: pointer;
    font-family: Tahoma;
    font-weight: bold;
    box-shadow: 0 0 35px rgba(0, 170, 255, 0.7);
    transition: transform 0.15s;
  }
  #overlay button:hover { transform: scale(1.06); }

  /* ==== پیام شناور ==== */
  #toast {
    position: absolute;
    top: 220px;
    left: 50%;
    transform: translateX(-50%) translateY(-20px);
    background: rgba(0, 80, 140, 0.95);
    border: 2px solid #0ff;
    border-radius: 14px;
    padding: 14px 32px;
    color: #fff;
    font-size: 18px;
    font-weight: bold;
    box-shadow: 0 0 50px rgba(0, 200, 255, 0.8);
    opacity: 0;
    transition: all 0.4s;
    pointer-events: none;
    z-index: 5;
  }
  #toast.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
</style>
</head>
<body>
<div id="game-container">
  <canvas id="c"></canvas>

  <div id="top-bar">
    <div class="panel">
      <b>مرحله:</b> <span id="level">1</span><br>
      <b>امتیاز:</b> <span id="score">0</span>
    </div>
    <div class="panel" style="text-align:right;">
      <b>سرعت قایق:</b> <span id="speed-display">0</span>
    </div>
  </div>

  <div id="goal-bar">
    <div id="goal-label">🏝️ فاصله تا ساحل امن</div>
    <div id="goal-track">
      <div id="goal-fill"></div>
      <div id="goal-marker">🏝️</div>
    </div>
  </div>

  <div id="live-hint">اسلایدرها را تکان بده تا قایق حرکت کند</div>

  <div id="controls">
    <div class="ctrl">
      <label>🌊 موج بالا-پایین</label>
      <input type="range" id="f1" min="0" max="100" value="50">
      <div class="sub">حرکت عمودی قایق</div>
    </div>
    <div class="ctrl">
      <label>💨 موج چپ-راست</label>
      <input type="range" id="f2" min="0" max="100" value="50">
      <div class="sub">حرکت افقی قایق</div>
      <div id="direction-hint">
        <span class="dir-arrow" id="arrow-left">◀</span>
        <span class="dir-arrow" id="arrow-right">▶</span>
      </div>
    </div>
    <div class="ctrl">
      <label>🎯 قدرت موج</label>
      <input type="range" id="d" min="0" max="100" value="50">
      <div class="sub">سرعت حرکت</div>
    </div>
  </div>

  <div id="toast"></div>

  <div id="overlay">
    <h1>⛵ گمشده در امواج</h1>
    <p class="story">
      تو <b>خدای دریاها</b> هستی. یک قایق کوچک در طوفان گیر افتاده.<br>
      با کنترل <b>امواج</b>، آب را طوری به حرکت دربیار که قایق به <b>ساحل امن</b> برسه.
    </p>
    <div class="how-to">
      <h3>🎮 چطور بازی کنم؟</h3>
      <b>۱.</b> سه اسلایدر پایین صفحه هست<br>
      <b>۲.</b> اسلایدر اول: قایق را بالا/پایین می‌برد<br>
      <b>۳.</b> اسلایدر دوم: قایق را چپ/راست می‌برد<br>
      <b>۴.</b> اسلایدر سوم: قدرت موج را بیشتر می‌کند<br>
      <b>۵.</b> قایق را به 🏝️ ساحل برسان تا برنده شوی!
    </div>
    <button onclick="startGame()">شروع بازی</button>
  </div>
</div>

<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const W = 900, H = 600;
canvas.width = W; canvas.height = H;

// ============ وضعیت ============
let gameState = 'menu';
let level = 1;
let score = 0;
let time = 0;
let lastTime = 0;
let animationId = null;

// کنترل‌ها (0..1)
let ctrlVertical = 0.5;
let ctrlHorizontal = 0.5;
let ctrlPower = 0.5;

// قایق
let boatX = 150;
let boatY = 300;
let boatVX = 0;
let boatVY = 0;

// ساحل
const SHORE_X = 800;

// افکت‌ها
let particles = [];
let shakeAmount = 0;
let flashAmount = 0;
let trailPoints = [];

// ============ DOM ============
const f1S = document.getElementById('f1');
const f2S = document.getElementById('f2');
const dS = document.getElementById('d');
const levelEl = document.getElementById('level');
const scoreEl = document.getElementById('score');
const speedEl = document.getElementById('speed-display');
const goalFill = document.getElementById('goal-fill');
const hintEl = document.getElementById('live-hint');
const overlay = document.getElementById('overlay');
const toast = document.getElementById('toast');
const arrowL = document.getElementById('arrow-left');
const arrowR = document.getElementById('arrow-right');

f1S.addEventListener('input', () => { ctrlVertical = f1S.value / 100; });
f2S.addEventListener('input', () => { ctrlHorizontal = f2S.value / 100; });
dS.addEventListener('input', () => { ctrlPower = dS.value / 100; });

// ============ توابع کمکی ============
function showToast(msg, color = '#0ff') {
  toast.textContent = msg;
  toast.style.borderColor = color;
  toast.style.boxShadow = `0 0 50px ${color}cc`;
  toast.classList.add('show');
  clearTimeout(toast._t);
  toast._t = setTimeout(() => toast.classList.remove('show'), 1800);
}

// ============ فیزیک ساده و واضح ============
function updateBoat(dt) {
  // نیروی عمودی: از ctrlVertical
  const forceY = (ctrlVertical - 0.5) * 2; // -1..1
  // نیروی افقی: از ctrlHorizontal
  const forceX = (ctrlHorizontal - 0.5) * 2; // -1..1
  // قدرت موج: سرعت واکنش
  const power = 0.3 + ctrlPower * 1.5;

  // شتاب
  boatVY += forceY * power * dt * 8;
  boatVX += forceX * power * dt * 8;

  // اصطکاک آب
  boatVY *= 0.94;
  boatVX *= 0.94;

  // محدودیت سرعت
  const maxSpeed = 4 + ctrlPower * 4;
  boatVX = Math.max(-maxSpeed, Math.min(maxSpeed, boatVX));
  boatVY = Math.max(-maxSpeed, Math.min(maxSpeed, boatVY));

  // حرکت
  boatX += boatVX;
  boatY += boatVY;

  // برخورد با لبه‌ها
  if (boatY < 80) { boatY = 80; boatVY *= -0.3; }
  if (boatY > H - 80) { boatY = H - 80; boatVY *= -0.3; }
  if (boatX < 60) { boatX = 60; boatVX *= -0.3; }
  if (boatX > W - 60) { boatX = W - 60; boatVX *= -0.3; }

  // دنباله
  if (Math.abs(boatVX) + Math.abs(boatVY) > 0.5) {
    trailPoints.push({ x: boatX, y: boatY, life: 1 });
    if (trailPoints.length > 40) trailPoints.shift();
  }
  trailPoints.forEach(p => p.life -= dt * 0.8);
  trailPoints = trailPoints.filter(p => p.life > 0);

  // ذرات پاشش آب
  if (Math.abs(boatVX) + Math.abs(boatVY) > 2 && Math.random() < 0.4) {
    particles.push({
      x: boatX, y: boatY + 10,
      vx: -boatVX * 0.3 + (Math.random() - 0.5) * 2,
      vy: -Math.random() * 2 - 1,
      size: 2 + Math.random() * 2,
      life: 1
    });
  }

  // به‌روزرسانی نمایش سرعت
  const speed = Math.hypot(boatVX, boatVY);
  speedEl.textContent = speed.toFixed(1);

  // جهت افقی (فلش‌ها)
  if (boatVX > 0.3) { arrowR.classList.add('active'); arrowL.classList.remove('active'); }
  else if (boatVX < -0.3) { arrowL.classList.add('active'); arrowR.classList.remove('active'); }
  else { arrowL.classList.remove('active'); arrowR.classList.remove('active'); }

  // راهنمای زنده
  updateLiveHint();

  // پیشرفت به ساحل
  const progress = Math.max(0, Math.min(1, (boatX - 60) / (SHORE_X - 60)));
  goalFill.style.width = (progress * 100) + '%';

  // برنده شدن
  if (boatX >= SHORE_X - 30) {
    winLevel();
  }

  // باخت: بیرون رفتن از محدوده
  if (boatY > H + 50 || boatY < -50 || boatX < -50) {
    loseLevel();
  }
}

function updateLiveHint() {
  if (boatX >= SHORE_X - 100) {
    hintEl.textContent = '🏝️ نزدیک ساحل! ادامه بده!';
    hintEl.style.borderColor = '#0f8';
    hintEl.style.boxShadow = '0 0 30px rgba(0,255,150,0.6)';
    return;
  }

  const sp = Math.hypot(boatVX, boatVY);
  if (sp < 0.3) {
    hintEl.textContent = '👆 اسلایدرها را تکان بده تا قایق حرکت کند';
    hintEl.style.borderColor = 'rgba(0,200,255,0.5)';
    hintEl.style.boxShadow = '0 0 25px rgba(0,200,255,0.3)';
  } else if (boatVX > 1.5) {
    hintEl.textContent = '✅ آفرین! قایق به سمت ساحل می‌رود';
    hintEl.style.borderColor = '#0f8';
    hintEl.style.boxShadow = '0 0 30px rgba(0,255,150,0.5)';
  } else if (boatVX < -0.5) {
    hintEl.textContent = '⚠️ قایق دارد عقب می‌رود!';
    hintEl.style.borderColor = '#f80';
    hintEl.style.boxShadow = '0 0 30px rgba(255,150,0,0.5)';
  } else {
    hintEl.textContent = '🌊 قایق در حال حرکت است...';
    hintEl.style.borderColor = 'rgba(0,200,255,0.5)';
    hintEl.style.boxShadow = '0 0 25px rgba(0,200,255,0.3)';
  }
}

// ============ رندر ============
function draw(t) {
  // پس‌زمینه دریا
  const bg = ctx.createLinearGradient(0, 0, W, H);
  bg.addColorStop(0, '#001428');
  bg.addColorStop(0.5, '#002a4a');
  bg.addColorStop(1, '#00406a');
  ctx.fillStyle = bg;
  ctx.fillRect(0, 0, W, H);

  ctx.save();
  if (shakeAmount > 0.1) {
    ctx.translate((Math.random() - 0.5) * shakeAmount, (Math.random() - 0.5) * shakeAmount);
    shakeAmount *= 0.9;
  }

  // ==== خطوط موج دریا (پس‌زمینه) ====
  drawSeaWaves(t);

  // ==== ساحل ====
  drawShore(t);

  // ==== دنباله قایق ====
  trailPoints.forEach((p, i) => {
    const alpha = p.life * 0.5;
    ctx.fillStyle = `rgba(100, 200, 255, ${alpha})`;
    ctx.beginPath();
    ctx.arc(p.x, p.y, 3 + (1 - p.life) * 3, 0, Math.PI * 2);
    ctx.fill();
  });

  // ==== ذرات ====
  particles = particles.filter(p => p.life > 0);
  particles.forEach(p => {
    p.x += p.vx;
    p.y += p.vy;
    p.vy += 0.08;
    p.life -= 0.02;
    ctx.fillStyle = `rgba(150, 220, 255, ${p.life})`;
    ctx.beginPath();
    ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
    ctx.fill();
  });

  // ==== قایق ====
  drawBoat(t);

  // ==== فلش راهنما بالای قایق ====
  drawBoatArrow();

  // ==== فلاش ====
  if (flashAmount > 0) {
    ctx.fillStyle = `rgba(0, 255, 200, ${flashAmount * 0.4})`;
    ctx.fillRect(0, 0, W, H);
    flashAmount *= 0.9;
  }

  ctx.restore();
}

function drawSeaWaves(t) {
  // موج‌های افقی متحرک برای حس دریا
  ctx.strokeStyle = 'rgba(100, 200, 255, 0.08)';
  ctx.lineWidth = 1;
  for (let i = 0; i < 15; i++) {
    const y = 60 + i * 40;
    ctx.beginPath();
    for (let x = 0; x < W; x += 8) {
      const wave = Math.sin(x * 0.02 + t * 1.5 + i * 0.5) * 6;
      if (x === 0) ctx.moveTo(x, y + wave);
      else ctx.lineTo(x, y + wave);
    }
    ctx.stroke();
  }

  // موج‌های عمودی از چشمه‌ها
  const srcs = getSources();
  srcs.forEach((s, idx) => {
    const color = idx === 0 ? '80,200,255' : '120,180,255';
    for (let r = 20; r < 400; r += 40) {
      const radius = (r + t * 60) % 400;
      const alpha = Math.max(0, 0.15 - radius / 2000);
      if (alpha <= 0) continue;
      ctx.strokeStyle = `rgba(${color}, ${alpha})`;
      ctx.lineWidth = 1.5;
      ctx.beginPath();
      ctx.arc(s.x, s.y, radius, 0, Math.PI * 2);
      ctx.stroke();
    }
  });
}

function getSources() {
  // دو چشمه موج در سمت چپ صفحه
  return [
    { x: 40, y: 150 },
    { x: 40, y: 450 }
  ];
}

function drawShore(t) {
  // ساحل در سمت راست
  const grad = ctx.createLinearGradient(SHORE_X - 40, 0, W, 0);
  grad.addColorStop(0, 'rgba(255, 220, 120, 0)');
  grad.addColorStop(0.3, 'rgba(255, 220, 120, 0.15)');
  grad.addColorStop(1, 'rgba(255, 220, 120, 0.4)');
  ctx.fillStyle = grad;
  ctx.fillRect(SHORE_X - 40, 0, W - SHORE_X + 40, H);

  // نخل‌های کوچک
  ctx.fillStyle = 'rgba(80, 180, 80, 0.6)';
  for (let i = 0; i < 5; i++) {
    const px = SHORE_X + 20 + i * 18;
    const py = 100 + (i % 3) * 180;
    ctx.beginPath();
    ctx.arc(px, py, 8, 0, Math.PI * 2);
    ctx.fill();
  }

  // برچسب ساحل
  ctx.fillStyle = 'rgba(255, 220, 120, 0.9)';
  ctx.font = 'bold 22px Tahoma';
  ctx.textAlign = 'center';
  ctx.fillText('🏝️', SHORE_X + 40, H / 2);
  ctx.font = 'bold 16px Tahoma';
  ctx.fillText('ساحل امن', SHORE_X + 40, H / 2 + 30);
}

function drawBoat(t) {
  ctx.save();
  ctx.translate(boatX, boatY);

  // چرخش قایق بر اساس سرعت عمودی
  const tilt = Math.max(-0.4, Math.min(0.4, boatVY * 0.08));
  ctx.rotate(tilt);

  // سایه زیر قایق
  ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
  ctx.beginPath();
  ctx.ellipse(0, 18, 32, 8, 0, 0, Math.PI * 2);
  ctx.fill();

  // بدنه قایق
  ctx.fillStyle = '#c84a1a';
  ctx.beginPath();
  ctx.moveTo(-30, -8);
  ctx.lineTo(30, -8);
  ctx.lineTo(22, 14);
  ctx.lineTo(-22, 14);
  ctx.closePath();
  ctx.fill();
  ctx.strokeStyle = '#fff';
  ctx.lineWidth = 2;
  ctx.stroke();

  // خط بدنه
  ctx.fillStyle = '#fff';
  ctx.fillRect(-28, -2, 56, 3);

  // بادبان
  ctx.fillStyle = '#fff';
  ctx.beginPath();
  ctx.moveTo(0, -35);
  ctx.lineTo(0, -8);
  ctx.lineTo(22, -8);
  ctx.closePath();
  ctx.fill();
  ctx.strokeStyle = '#0af';
  ctx.lineWidth = 1.5;
  ctx.stroke();

  // دکل
  ctx.strokeStyle = '#333';
  ctx.lineWidth = 3;
  ctx.beginPath();
  ctx.moveTo(0, -38);
  ctx.lineTo(0, -8);
  ctx.stroke();

  // پرچم کوچک
  const flagWave = Math.sin(t * 5) * 2;
  ctx.fillStyle = '#0ff';
  ctx.beginPath();
  ctx.moveTo(0, -38);
  ctx.lineTo(10 + flagWave, -35);
  ctx.lineTo(0, -32);
  ctx.closePath();
  ctx.fill();

  ctx.restore();
}

function drawBoatArrow() {
  // فلش بزرگ بالای قایق که جهت حرکت را نشان می‌دهد
  const speed = Math.hypot(boatVX, boatVY);
  if (speed < 0.2) return;

  const arrowLen = 15 + speed * 6;
  const angle = Math.atan2(boatVY, boatVX);

  ctx.save();
  ctx.translate(boatX + Math.cos(angle) * 50, boatY + Math.sin(angle) * 50);
  ctx.rotate(angle);

  ctx.fillStyle = `rgba(0, 255, 200, ${0.4 + speed * 0.1})`;
  ctx.beginPath();
  ctx.moveTo(arrowLen, 0);
  ctx.lineTo(-arrowLen * 0.5, -arrowLen * 0.5);
  ctx.lineTo(-arrowLen * 0.5, arrowLen * 0.5);
  ctx.closePath();
  ctx.fill();

  ctx.restore();
}

// ============ حلقه بازی ============
function gameLoop(ts) {
  if (gameState !== 'playing') return;
  const dt = Math.min((ts - lastTime) / 1000, 0.05);
  lastTime = ts;
  time += dt;

  updateBoat(dt);

  flashAmount *= 0.9;
  shakeAmount *= 0.9;

  draw(time);

  animationId = requestAnimationFrame(gameLoop);
}

// ============ برد و باخت ============
function winLevel() {
  gameState = 'won';
  cancelAnimationFrame(animationId);
  score += 100 * level;
  scoreEl.textContent = score;
  flashAmount = 1;
  shakeAmount = 15;

  if (level < 3) {
    showToast(`🎉 مرحله ${level} کامل شد!`, '#0f8');
    level++;
    levelEl.textContent = level;
    setTimeout(() => {
      resetLevel();
      gameState = 'playing';
      lastTime = performance.now();
      animationId = requestAnimationFrame(gameLoop);
    }, 1500);
  } else {
    showToast('🏆 برنده شدی!', '#ffd966');
    setTimeout(showWinScreen, 1200);
  }
}

function loseLevel() {
  gameState = 'lost';
  cancelAnimationFrame(animationId);
  shakeAmount = 25;
  showToast('💥 قایق غرق شد!', '#f44');
  setTimeout(() => {
    resetLevel();
    gameState = 'playing';
    lastTime = performance.now();
    animationId = requestAnimationFrame(gameLoop);
  }, 1500);
}

function resetLevel() {
  boatX = 150;
  boatY = 300;
  boatVX = 0;
  boatVY = 0;
  trailPoints = [];
  particles = [];
  goalFill.style.width = '0%';
}

function showWinScreen() {
  overlay.innerHTML = `
    <h1>🏆 برنده شدی!</h1>
    <p class="story">
      تو موفق شدی قایق را از میان طوفان به <b>ساحل امن</b> برسانی.<br>
      امتیاز نهایی: <b>${score}</b><br>
      خدای دریاها ازت راضی است. 🌊
    </p>
    <button onclick="location.reload()">بازی دوباره</button>
  `;
  overlay.style.display = 'flex';
}

function startGame() {
  overlay.style.display = 'none';
  gameState = 'playing';
  level = 1;
  score = 0;
  time = 0;
  levelEl.textContent = '1';
  scoreEl.textContent = '0';
  resetLevel();

  // شروع اسلایدرها در وسط
  f1S.value = 50;
  f2S.value = 50;
  dS.value = 50;
  ctrlVertical = 0.5;
  ctrlHorizontal = 0.5;
  ctrlPower = 0.5;

  showToast('⛵ قایق را به ساحل برسان!', '#0ff');

  lastTime = performance.now();
  animationId = requestAnimationFrame(gameLoop);
}

// ============ رندر اولیه ============
draw(0);
</script>
</body>
</html>

Game Source: گمشده در امواج

Creator: RapidKnight54

Libraries: matter

Complexity: complex (795 lines, 20.9 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-rapidknight54-mv6ygoh2" to link back to the original. Then publish at arcadelab.ai/publish.