๐ŸŽฎArcadeLab

Remix of BeastClash

by FrozenOtter31
1531 lines42.9 KB
โ–ถ Play
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
  <meta charset="UTF-8" />
  <title>BeastClash</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; user-select: none; -webkit-user-select: none; }
    body {
      background: linear-gradient(135deg, #1a1a2e, #16213e);
      color: #fff;
      font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      overflow: hidden;
      height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }
    #game-container {
      position: relative;
      width: 100%;
      max-width: 900px;
      height: 100vh;
      max-height: 600px;
      background: radial-gradient(circle at center, #0f3460, #1a1a2e);
      border-radius: 12px;
      box-shadow: 0 10px 30px rgba(0,0,0,0.5);
      overflow: hidden;
    }
    canvas {
      display: block;
      width: 100%;
      height: 100%;
    }
    .screen {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background: rgba(0,0,0,0.85);
      z-index: 10;
      transition: opacity 0.3s;
    }
    .screen.hidden {
      opacity: 0;
      pointer-events: none;
    }
    h1 {
      font-size: 3rem;
      marginืžืฆื•ื™ืŸ โ€” ื”ื ื” **ืงื•ื“ ืžืœื ื•ืžื•ื›ืŸ ืœื”ืจืฆื”** ืฉืœ ืžืฉื—ืง ื“ืคื“ืคืŸ ื‘ืกื’ื ื•ืŸ BeastClash. ื–ื”ื• ืงื•ื‘ืฅ HTML ื™ื—ื™ื“ ืฉื›ื•ืœืœ ืืช ื›ืœ ื”ืงื•ื“ (HTML, CSS, JavaScript). ืชืขืชื™ืง ืืช ื”ืงื•ื“, ืชืฉืžื•ืจ ื›ืงื•ื‘ืฅ `index.html`, ื•ืชืคืชื— ื‘ื“ืคื“ืคืŸ (Chrome/Edge/Safari) โ€” ื’ื ื‘ืžื—ืฉื‘ ื•ื’ื ื‘ื˜ืœืคื•ืŸ.

```html
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
  <meta charset="UTF-8" />
  <title>BeastClash</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; user-select: none; -webkit-user-select: none; }
    body {
      background: linear-gradient(135deg, #1a1a2e, #16213e);
      color: #fff;
      font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      overflow: hidden;
      height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }
    #game-container {
      position: relative;
      width: 100%;
      max-width: 900px;
      height: 100vh;
      max-height: 600px;
      background: radial-gradient(circle at center, #0f3460, #1a1a2e);
      border-radius: 12px;
      box-shadow: 0 10px 30px rgba(0,0,0,0.5);
      overflow: hidden;
    }
    canvas {
      display: block;
      width: 100%;
      height: 100%;
    }
    .screen {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background: rgba(0,0,0,0.85);
      z-index: 10;
      transition: opacity 0.3s;
    }
    .screen.hidden {
      opacity: 0;
      pointer-events: none;
    }
    h1 {
      font-size: 3rem;
      margin-bottom: 1rem;
      text-shadow: 0 0 20px #e94560, 0 0 40px #e94560;
      letter-spacing: 2px;
    }
    p {
      font-size: 1.2rem;
      margin-bottom: 2rem;
      text-align: center;
      max-width: 80%;
      line-height: 1.6;
    }
    button {
      background: linear-gradient(135deg, #e94560, #c23a51);
      color: #fff;
      border: none;
      padding: 1rem 3rem;
      font-size: 1.3rem;
      border-radius: 50px;
      cursor: pointer;
      box-shadow: 0 5px 20px rgba(233,69,96,0.4);
      transition: transform 0.2s, box-shadow 0.2s;
    }
    button:hover {
      transform: scale(1.05);
      box-shadow: 0 8px 30px rgba(233,69,96,0.6);
    }
    button:active {
      transform: scale(0.98);
    }
    #ui-layer {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      pointer-events: none;
      z-index: 5;
    }
    .mana-bar {
      position: absolute;
      bottom: 20px;
      left: 50%;
      transform: translateX(-50%);
      width: 200px;
      height: 30px;
      background: rgba(0,0,0,0.6);
      border-radius: 15px;
      overflow: hidden;
      border: 2px solid #4ecca3;
    }
    .mana-fill {
      height: 100%;
      background: linear-gradient(90deg, #4ecca3, #45b393);
      width: 0%;
      transition: width 0.3s;
    }
    .mana-text {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 1rem;
      font-weight: bold;
      color: #fff;
      text-shadow: 0 0 5px #000;
    }
    .card-hand {
      position: absolute;
      bottom: 80px;
      left: 50%;
      transform: translateX(-50%);
      display: flex;
      gap: 15px;
      pointer-events: auto;
    }
    .card {
      width: 100px;
      height: 140px;
      background: linear-gradient(135deg, #2d4059, #1a1a2e);
      border: 3px solid #e94560;
      border-radius: 10px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      transition: transform 0.2s, box-shadow 0.2s;
      box-shadow: 0 5px 15px rgba(0,0,0,0.5);
    }
    .card:hover {
      transform: translateY(-10px) scale(1.05);
      box-shadow: 0 10px 25px rgba(233,69,96,0.6);
    }
    .card-name {
      font-size: 0.9rem;
      font-weight: bold;
      margin-bottom: 5px;
    }
    .card-cost {
      font-size: 1.2rem;
      color: #4ecca3;
      font-weight: bold;
    }
    .card-desc {
      font-size: 0.7rem;
      text-align: center;
      padding: 5px;
    }
    #health-display {
      position: absolute;
      top: 20px;
      width: 100%;
      display: flex;
      justify-content: space-between;
      padding: 0 40px;
      font-size: 1.5rem;
      font-weight: bold;
      text-shadow: 0 0 10px #000;
    }
    .health-bar {
      width: 200px;
      height: 20px;
      background: rgba(0,0,0,0.6);
      border-radius: 10px;
      overflow: hidden;
      border: 2px solid #e94560;
    }
    .health-fill {
      height: 100%;
      background: linear-gradient(90deg, #e94560, #c23a51);
      width: 100%;
      transition: width 0.3s;
    }
    #message {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 2rem;
      font-weight: bold;
      color: #fff;
      text-shadow: 0 0 20px #e94560;
      opacity: 0;
      transition: opacity 0.3s;
      pointer-events: none;
    }
  </style>
</head>
<body>
  <div id="game-container">
    <canvas id="game-canvas"></canvas>
    
    <div id="ui-layer">
      <div id="health-display">
        <div>
          <div>ืฉื—ืงืŸ</div>
          <div class="health-bar"><div class="health-fill" id="player-health"></div></div>
        </div>
        <div>
          <div>ื™ืจื™ื‘</div>
          <div class="health-bar"><div class="health-fill" id="enemy-health"></div></div>
        </div>
      </div>
      
      <div class="mana-bar">
        <div class="mana-fill" id="mana-fill"></div>
        <div class="mana-text" id="mana-text">0 / 10</div>
      </div>
      
      <div class="card-hand" id="card-hand"></div>
      
      <div id="message"></div>
    </div>
    
    <div id="start-screen" class="screen">
      <h1>๐Ÿพ BeastClash ๐Ÿ—ก๏ธ</h1>
      <p>ื”ื‘ืก ืืช ื”ื™ืจื™ื‘ ื‘ืงืจื‘ ืืกื˜ืจื˜ื’ื™!<br>ื”ืฆื‘ ื™ื—ื™ื“ื•ืช, ื ื”ืœ ืžืื ื, ื•ื”ืฉืžื“ ืืช ื”ื‘ืกื™ืก ืฉืœื•.</p>
      <button id="start-btn">ื”ืชื—ืœ ืงืจื‘</button>
    </div>
    
    <div id="game-over-screen" class="screen hidden">
      <h1 id="game-over-title">ื ื™ืฆื—ื•ืŸ!</h1>
      <p id="game-over-message">ื”ื‘ืกืช ืืช ื”ื™ืจื™ื‘!</p>
      <button id="restart-btn">ืฉื—ืง ืฉื•ื‘</button>
    </div>
  </div>

  <script>
    // === Game State ===
    const canvas = document.getElementById('game-canvas');
    const ctx = canvas.getContext('2d');
    
    let gameState = 'start'; // start, playing, gameover
    let lastTime = 0;
    
    // === Game Constants ===
    const MAX_MANA = 10;
    const PLAYER_MAX_HEALTH = 100;
    const ENEMY_MAX_HEALTH = 100;
    
    // === Card Definitions ===
    const CARDS = [
      { name: 'ื–ืื‘', cost: 2, attack: 15, health: 20, speed: 2, color: '#4ecca3', desc: 'ืžื”ื™ืจ ื•ื—ื–ืง' },
      { name: 'ื“ื•ื‘', cost: 4, attack: 25, health: 40, speed: 1, color: '#e94560', desc: 'ื˜ื ืง ืื™ื˜ื™' },
      { name: 'ื ืฅ', cost: 3, attack: 20, health: 15, speed: 3, color: '#f9ed69', desc: 'ืžื”ื™ืจ ืžืื•ื“' }
    ];
    
    // === Game Objects ===
    let player = {
      health: PLAYER_MAX_HEALTH,
      mana: 3,
      hand: [],
      units: []
    };
    
    let enemy = {
      health: ENEMY_MAX_HEALTH,
      mana: 3,
      units: []
    };
    
    let projectiles = [];
    let particles = [];
    
    // === Resize Canvas ===
    function resizeCanvas() {
      const container = document.getElementById('game-container');
      canvas.width = container.clientWidth;
      canvas.height = container.clientHeight;
    }
    resizeCanvas();
    window.addEventListener('resize', resizeCanvas);
    
    // === Utility Functions ===
    function random(min, max) {
      return Math.random() * (max - min) + min;
    }
    
    function showMessage(text, durationืžืฆื•ื™ืŸ โ€” ื”ื ื” **ืงื•ื“ ืžืœื ื•ืžื•ื›ืŸ ืœื”ืจืฆื”** ืฉืœ ืžืฉื—ืง ื“ืคื“ืคืŸ ื‘ืกื’ื ื•ืŸ BeastClash. ื–ื”ื• ืงื•ื‘ืฅ HTML ื™ื—ื™ื“ ืฉื›ื•ืœืœ ืืช ื›ืœ ื”ืงื•ื“ (HTML, CSS, JavaScript). ืชืขืชื™ืง ืืช ื”ืงื•ื“, ืชืฉืžื•ืจ ื›ืงื•ื‘ืฅ `index.html`, ื•ืชืคืชื— ื‘ื“ืคื“ืคืŸ (Chrome/Edge/Safari) โ€” ื’ื ื‘ืžื—ืฉื‘ ื•ื’ื ื‘ื˜ืœืคื•ืŸ.

```html
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
  <meta charset="UTF-8" />
  <title>BeastClash</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; user-select: none; -webkit-user-select: none; }
    body {
      background: linear-gradient(135deg, #1a1a2e, #16213e);
      color: #fff;
      font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      overflow: hidden;
      height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }
    #game-container {
      position: relative;
      width: 100%;
      max-width: 900px;
      height: 100vh;
      max-height: 600px;
      background: radial-gradient(circle at center, #0f3460, #1a1a2e);
      border-radius: 12px;
      box-shadow: 0 10px 30px rgba(0,0,0,0.5);
      overflow: hidden;
    }
    canvas {
      display: block;
      width: 100%;
      height: 100%;
    }
    .screen {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background: rgba(0,0,0,0.85);
      z-index: 10;
      transition: opacity 0.3s;
    }
    .screen.hidden {
      opacity: 0;
      pointer-events: none;
    }
    h1 {
      font-size: 3rem;
      margin-bottom: 1rem;
      text-shadow: 0 0 20px #e94560, 0 0 40px #e94560;
      letter-spacing: 2px;
    }
    p {
      font-size: 1.2rem;
      margin-bottom: 2rem;
      text-align: center;
      max-width: 80%;
      line-height: 1.6;
    }
    button {
      background: linear-gradient(135deg, #e94560, #c23a51);
      color: #fff;
      border: none;
      padding: 1rem 3rem;
      font-size: 1.3rem;
      border-radius: 50px;
      cursor: pointer;
      box-shadow: 0 5px 20px rgba(233,69,96,0.4);
      transition: transform 0.2s, box-shadow 0.2s;
    }
    button:hover {
      transform: scale(1.05);
      box-shadow: 0 8px 30px rgba(233,69,96,0.6);
    }
    button:active {
      transform: scale(0.98);
    }
    #ui-layer {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      pointer-events: none;
      z-index: 5;
    }
    .mana-bar {
      position: absolute;
      bottom: 20px;
      left: 50%;
      transform: translateX(-50%);
      width: 200px;
      height: 30px;
      background: rgba(0,0,0,0.6);
      border-radius: 15px;
      overflow: hidden;
      border: 2px solid #4ecca3;
    }
    .mana-fill {
      height: 100%;
      background: linear-gradient(90deg, #4ecca3, #45b393);
      width: 0%;
      transition: width 0.3s;
    }
    .mana-text {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 1rem;
      font-weight: bold;
      color: #fff;
      text-shadow: 0 0 5px #000;
    }
    .card-hand {
      position: absolute;
      bottom: 80px;
      left: 50%;
      transform: translateX(-50%);
      display: flex;
      gap: 15px;
      pointer-events: auto;
    }
    .card {
      width: 100px;
      height: 140px;
      background: linear-gradient(135deg, #2d4059, #1a1a2e);
      border: 3px solid #e94560;
      border-radius: 10px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      transition: transform 0.2s, box-shadow 0.2s;
      box-shadow: 0 5px 15px rgba(0,0,0,0.5);
    }
    .card:hover {
      transform: translateY(-10px) scale(1.05);
      box-shadow: 0 10px 25px rgba(233,69,96,0.6);
    }
    .card-name {
      font-size: 0.9rem;
      font-weight: bold;
      margin-bottom: 5px;
    }
    .card-cost {
      font-size: 1.2rem;
      color: #4ecca3;
      font-weight: bold;
    }
    .card-desc {
      font-size: 0.7rem;
      text-align: center;
      padding: 5px;
    }
    #health-display {
      position: absolute;
      top: 20px;
      width: 100%;
      display: flex;
      justify-content: space-between;
      padding: 0 40px;
      font-size: 1.5rem;
      font-weight: bold;
      text-shadow: 0 0 10px #000;
    }
    .health-bar {
      width: 200px;
      height: 20px;
      background: rgba(0,0,0,0.6);
      border-radius: 10px;
      overflow: hidden;
      border: 2px solid #e94560;
    }
    .health-fill {
      height: 100%;
      background: linear-gradient(90deg, #e94560, #c23a51);
      width: 100%;
      transition: width 0.3s;
    }
    #message {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 2rem;
      font-weight: bold;
      color: #fff;
      text-shadow: 0 0 20px #e94560;
      opacity: 0;
      transition: opacity 0.3s;
      pointer-events: none;
    }
  </style>
</head>
<body>
  <div id="game-container">
    <canvas id="game-canvas"></canvas>
    
    <div id="ui-layer">
      <div id="health-display">
        <div>
          <div>ืฉื—ืงืŸ</div>
          <div class="health-bar"><div class="health-fill" id="player-health"></div></div>
        </div>
        <div>
          <div>ื™ืจื™ื‘</div>
          <div class="health-bar"><div class="health-fill" id="enemy-health"></div></div>
        </div>
      </div>
      
      <div class="mana-bar">
        <div class="mana-fill" id="mana-fill"></div>
        <div class="mana-text" id="mana-text">0 / 10</div>
      </div>
      
      <div class="card-hand" id="card-hand"></div>
      
      <div id="message"></div>
    </div>
    
    <div id="start-screen" class="screen">
      <h1>๐Ÿพ BeastClash ๐Ÿ—ก๏ธ</h1>
      <p>ื”ื‘ืก ืืช ื”ื™ืจื™ื‘ ื‘ืงืจื‘ ืืกื˜ืจื˜ื’ื™!<br>ื”ืฆื‘ ื™ื—ื™ื“ื•ืช, ื ื”ืœ ืžืื ื, ื•ื”ืฉืžื“ ืืช ื”ื‘ืกื™ืก ืฉืœื•.</p>
      <button id="start-btn">ื”ืชื—ืœ ืงืจื‘</button>
    </div>
    
    <div id="game-over-screen" class="screen hidden">
      <h1 id="game-over-title">ื ื™ืฆื—ื•ืŸ!</h1>
      <p id="game-over-message">ื”ื‘ืกืช ืืช ื”ื™ืจื™ื‘!</p>
      <button id="restart-btn">ืฉื—ืง ืฉื•ื‘</button>
    </div>
  </div>

  <script>
    // === Game State ===
    const canvas = document.getElementById('game-canvas');
    const ctx = canvas.getContext('2d');
    
    let gameState = 'start'; // start, playing, gameover
    let lastTime = 0;
    
    // === Game Constants ===
    const MAX_MANA = 10;
    const PLAYER_MAX_HEALTH = 100;
    const ENEMY_MAX_HEALTH = 100;
    
    // === Card Definitions ===
    const CARDS = [
      { name: 'ื–ืื‘', cost: 2, attack: 15, health: 20, speed: 2, color: '#4ecca3', desc: 'ืžื”ื™ืจ ื•ื—ื–ืง' },
      { name: 'ื“ื•ื‘', cost: 4, attack: 25, health: 40, speed: 1, color: '#e94560', desc: 'ื˜ื ืง ืื™ื˜ื™' },
      { name: 'ื ืฅ', cost: 3, attack: 20, health: 15, speed: 3, color: '#f9ed69', desc: 'ืžื”ื™ืจ ืžืื•ื“' }
    ];
    
    // === Game Objects ===
    let player = {
      health: PLAYER_MAX_HEALTH,
      mana: 3,
      hand: [],
      units: []
    };
    
    let enemy = {
      health: ENEMY_MAX_HEALTH,
      mana: 3,
      units: []
    };
    
    let projectiles = [];
    let particles = [];
    
    // === Resize Canvas ===
    function resizeCanvas() {
      const container = document.getElementById('game-container');
      canvas.width = container.clientWidth;
      canvas.height = container.clientHeight;
    }
    resizeCanvas();
    window.addEventListener('resize', resizeCanvas);
    
    // === Utility Functions ===
    function random(min, max) {
      return Math.random() * (max - min) + min;
    }
    
    function showMessage(text, duration = 2000) {
      const msg = document.getElementById('message');
      msg.textContent = text;
      msg.style.opacity = 1;
      setTimeout(() => {
        msg.style.opacity = 0;
      }, duration);
    }
    
    // === Input Handling ===
    let selectedCard = null;
    let isDragging = false;
    let dragStart = { x: 0, y: 0 };
    
    canvas.addEventListener('pointerdown', (e) => {
      if (gameState !== 'playing') return;
      const rect = canvas.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      
      // Check if clicking on arena to spawn unit
      if (y < canvas.height * 0.6) {
        if (selectedCard && player.mana >= selectedCard.cost) {
          spawnUnit(selectedCard, x, y, true);
          player.mana -= selectedCard.cost;
          updateUI();
          selectedCard = null;
          renderHand();
        }
      }
      
      isDragging = true;
      dragStart = { x, y };
    });
    
    canvas.addEventListener('pointermove', (e) => {
      if (!isDragging) return;
      const rect = canvas.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      
      // Simple drag effect (could be expanded)
    });
    
    canvas.addEventListener('pointerup', () => {
      isDragging = false;
    });
    
    // === Game Functions ===
    function spawnUnit(card, x, y, isPlayer) {
      const unit = {
        ...card,
        x,
        y,
        maxHealth: card.health,
        isPlayer,
        target: null,
        attackCooldown: 0
      };
      
      if (isPlayer) {
        player.units.push(unit);
      } else {
        enemy.units.push(unit);
      }
      
      // Spawn particles
      for (let i = 0; i < 10; i++) {
        particles.push({
          x,
          y,
          vx: random(-3, 3),
          vy: random(-3, 3),
          life: 1,
          color: card.color
        });
      }
    }
    
    function drawCard(x, y, card, isSelectable = false) {
      ctx.fillStyle = card.color;
      ctx.fillRect(x - 40, y - 60, 80, 100);
      
      ctx.fillStyle = '#fff';
      ctx.font = 'bold 14px system-ui';
      ctx.textAlign = 'center';
      ctx.fillText(card.name, x, y - 40);
      
      ctx.font = '12px system-ui';
      ctx.fillText(`ืขืœื•ืช: ${card.cost}`, x, y - 20);
      ctx.fillText(`ื”ืชืงืคื”: ${card.attack}`, x, y);
      ctx.fillText(`ื—ื™ื™ื: ${card.health}`, x, y + 20);
      
      if (isSelectable) {
        ctx.strokeStyle = '#fff';
        ctx.lineWidth = 3;
        ctx.strokeRect(x - 42, y - 62, 84, 104);
      }
    }
    
    function updateUnits(delta) {
      // Player units
      player.units.forEach(unit => {
        if (unit.attackCooldown > 0) unit.attackCooldown -= delta;
        
        // Find nearest enemy unit or enemy base
        let nearest = null;
        let nearestDist = Infinity;
        
        enemy.units.forEach(enemyUnit => {
          const dist = Math.hypot(enemyUnit.x - unit.x, enemyUnit.y - unit.y);
          if (dist < nearestDist) {
            nearestDist = dist;
            nearest = enemyUnit;
          }
        });
        
        // If no enemy units, target enemy base
        if (!nearest) {
          const baseDist = Math.hypot(canvas.width / 2 - unit.x, 0 - unit.y);
          if (baseDist < nearestDist) {
            nearestDist = baseDist;
            nearest = { x: canvas.width / 2, y: 0, isBase: true };
          }
        }
        
        // Move towards target
        if (nearest && nearestDist > 30) {
          const angle = Math.atan2(nearest.y - unit.y, nearest.x - unit.x);
          unit.x += Math.cos(angle) * unit.speed;
          unit.y += Math.sin(angle) * unit.speed;
        } else if (nearest) {
          // Attack
          if (unit.attackCooldown <= 0) {
            if (nearest.isBase) {
              enemy.health -= unit.attack;
              showMessage(`-${unit.attack} ืœื‘ืกื™ืก!`);
            } else {
              nearest.health -= unit.attack;
              if (nearest.health <= 0) {
                enemy.units = enemy.units.filter(u => u !== nearest);
              }
            }
            unit.attackCooldown = 1; // 1 second cooldown
            
            // Attack projectile
            projectiles.push({
              x: unit.x,
              y: unit.y,
              targetX: nearest.x,
              targetY: nearest.y,
              life: 0.5,
              color: unit.color
            });
          }
        }
      });
      
      // Enemy units (simple AI)
      enemyืžืฆื•ื™ืŸ โ€” ื”ื ื” **ืงื•ื“ ืžืœื ื•ืžื•ื›ืŸ ืœื”ืจืฆื”** ืฉืœ ืžืฉื—ืง ื“ืคื“ืคืŸ ื‘ืกื’ื ื•ืŸ BeastClash. ื–ื”ื• ืงื•ื‘ืฅ HTML ื™ื—ื™ื“ ืฉื›ื•ืœืœ ืืช ื›ืœ ื”ืงื•ื“ (HTML, CSS, JavaScript). ืชืขืชื™ืง ืืช ื”ืงื•ื“, ืชืฉืžื•ืจ ื›ืงื•ื‘ืฅ `index.html`, ื•ืชืคืชื— ื‘ื“ืคื“ืคืŸ (Chrome/Edge/Safari) โ€” ื’ื ื‘ืžื—ืฉื‘ ื•ื’ื ื‘ื˜ืœืคื•ืŸ.

```html
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
  <meta charset="UTF-8" />
  <title>BeastClash</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; user-select: none; -webkit-user-select: none; }
    body {
      background: linear-gradient(135deg, #1a1a2e, #16213e);
      color: #fff;
      font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      overflow: hidden;
      height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }
    #game-container {
      position: relative;
      width: 100%;
      max-width: 900px;
      height: 100vh;
      max-height: 600px;
      background: radial-gradient(circle at center, #0f3460, #1a1a2e);
      border-radius: 12px;
      box-shadow: 0 10px 30px rgba(0,0,0,0.5);
      overflow: hidden;
    }
    canvas {
      display: block;
      width: 100%;
      height: 100%;
    }
    .screen {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background: rgba(0,0,0,0.85);
      z-index: 10;
      transition: opacity 0.3s;
    }
    .screen.hidden {
      opacity: 0;
      pointer-events: none;
    }
    h1 {
      font-size: 3rem;
      margin-bottom: 1rem;
      text-shadow: 0 0 20px #e94560, 0 0 40px #e94560;
      letter-spacing: 2px;
    }
    p {
      font-size: 1.2rem;
      margin-bottom: 2rem;
      text-align: center;
      max-width: 80%;
      line-height: 1.6;
    }
    button {
      background: linear-gradient(135deg, #e94560, #c23a51);
      color: #fff;
      border: none;
      padding: 1rem 3rem;
      font-size: 1.3rem;
      border-radius: 50px;
      cursor: pointer;
      box-shadow: 0 5px 20px rgba(233,69,96,0.4);
      transition: transform 0.2s, box-shadow 0.2s;
    }
    button:hover {
      transform: scale(1.05);
      box-shadow: 0 8px 30px rgba(233,69,96,0.6);
    }
    button:active {
      transform: scale(0.98);
    }
    #ui-layer {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      pointer-events: none;
      z-index: 5;
    }
    .mana-bar {
      position: absolute;
      bottom: 20px;
      left: 50%;
      transform: translateX(-50%);
      width: 200px;
      height: 30px;
      background: rgba(0,0,0,0.6);
      border-radius: 15px;
      overflow: hidden;
      border: 2px solid #4ecca3;
    }
    .mana-fill {
      height: 100%;
      background: linear-gradient(90deg, #4ecca3, #45b393);
      width: 0%;
      transition: width 0.3s;
    }
    .mana-text {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 1rem;
      font-weight: bold;
      color: #fff;
      text-shadow: 0 0 5px #000;
    }
    .card-hand {
      position: absolute;
      bottom: 80px;
      left: 50%;
      transform: translateX(-50%);
      display: flex;
      gap: 15px;
      pointer-events: auto;
    }
    .card {
      width: 100px;
      height: 140px;
      background: linear-gradient(135deg, #2d4059, #1a1a2e);
      border: 3px solid #e94560;
      border-radius: 10px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      transition: transform 0.2s, box-shadow 0.2s;
      box-shadow: 0 5px 15px rgba(0,0,0,0.5);
    }
    .card:hover {
      transform: translateY(-10px) scale(1.05);
      box-shadow: 0 10px 25px rgba(233,69,96,0.6);
    }
    .card-name {
      font-size: 0.9rem;
      font-weight: bold;
      margin-bottom: 5px;
    }
    .card-cost {
      font-size: 1.2rem;
      color: #4ecca3;
      font-weight: bold;
    }
    .card-desc {
      font-size: 0.7rem;
      text-align: center;
      padding: 5px;
    }
    #health-display {
      position: absolute;
      top: 20px;
      width: 100%;
      display: flex;
      justify-content: space-between;
      padding: 0 40px;
      font-size: 1.5rem;
      font-weight: bold;
      text-shadow: 0 0 10px #000;
    }
    .health-bar {
      width: 200px;
      height: 20px;
      background: rgba(0,0,0,0.6);
      border-radius: 10px;
      overflow: hidden;
      border: 2px solid #e94560;
    }
    .health-fill {
      height: 100%;
      background: linear-gradient(90deg, #e94560, #c23a51);
      width: 100%;
      transition: width 0.3s;
    }
    #message {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 2rem;
      font-weight: bold;
      color: #fff;
      text-shadow: 0 0 20px #e94560;
      opacity: 0;
      transition: opacity 0.3s;
      pointer-events: none;
    }
  </style>
</head>
<body>
  <div id="game-container">
    <canvas id="game-canvas"></canvas>
    
    <div id="ui-layer">
      <div id="health-display">
        <div>
          <div>ืฉื—ืงืŸ</div>
          <div class="health-bar"><div class="health-fill" id="player-health"></div></div>
        </div>
        <div>
          <div>ื™ืจื™ื‘</div>
          <div class="health-bar"><div class="health-fill" id="enemy-health"></div></div>
        </div>
      </div>
      
      <div class="mana-bar">
        <div class="mana-fill" id="mana-fill"></div>
        <div class="mana-text" id="mana-text">0 / 10</div>
      </div>
      
      <div class="card-hand" id="card-hand"></div>
      
      <div id="message"></div>
    </div>
    
    <div id="start-screen" class="screen">
      <h1>๐Ÿพ BeastClash ๐Ÿ—ก๏ธ</h1>
      <p>ื”ื‘ืก ืืช ื”ื™ืจื™ื‘ ื‘ืงืจื‘ ืืกื˜ืจื˜ื’ื™!<br>ื”ืฆื‘ ื™ื—ื™ื“ื•ืช, ื ื”ืœ ืžืื ื, ื•ื”ืฉืžื“ ืืช ื”ื‘ืกื™ืก ืฉืœื•.</p>
      <button id="start-btn">ื”ืชื—ืœ ืงืจื‘</button>
    </div>
    
    <div id="game-over-screen" class="screen hidden">
      <h1 id="game-over-title">ื ื™ืฆื—ื•ืŸ!</h1>
      <p id="game-over-message">ื”ื‘ืกืช ืืช ื”ื™ืจื™ื‘!</p>
      <button id="restart-btn">ืฉื—ืง ืฉื•ื‘</button>
    </div>
  </div>

  <script>
    // === Game State ===
    const canvas = document.getElementById('game-canvas');
    const ctx = canvas.getContext('2d');
    
    let gameState = 'start'; // start, playing, gameover
    let lastTime = 0;
    
    // === Game Constants ===
    const MAX_MANA = 10;
    const PLAYER_MAX_HEALTH = 100;
    const ENEMY_MAX_HEALTH = 100;
    
    // === Card Definitions ===
    const CARDS = [
      { name: 'ื–ืื‘', cost: 2, attack: 15, health: 20, speed: 2, color: '#4ecca3', desc: 'ืžื”ื™ืจ ื•ื—ื–ืง' },
      { name: 'ื“ื•ื‘', cost: 4, attack: 25, health: 40, speed: 1, color: '#e94560', desc: 'ื˜ื ืง ืื™ื˜ื™' },
      { name: 'ื ืฅ', cost: 3, attack: 20, health: 15, speed: 3, color: '#f9ed69', desc: 'ืžื”ื™ืจ ืžืื•ื“' }
    ];
    
    // === Game Objects ===
    let player = {
      health: PLAYER_MAX_HEALTH,
      mana: 3,
      hand: [],
      units: []
    };
    
    let enemy = {
      health: ENEMY_MAX_HEALTH,
      mana: 3,
      units: []
    };
    
    let projectiles = [];
    let particles = [];
    
    // === Resize Canvas ===
    function resizeCanvas() {
      const container = document.getElementById('game-container');
      canvas.width = container.clientWidth;
      canvas.height = container.clientHeight;
    }
    resizeCanvas();
    window.addEventListener('resize', resizeCanvas);
    
    // === Utility Functions ===
    function random(min, max) {
      return Math.random() * (max - min) + min;
    }
    
    function showMessage(text, duration = 2000) {
      const msg = document.getElementById('message');
      msg.textContent = text;
      msg.style.opacity = 1;
      setTimeout(() => {
        msg.style.opacity = 0;
      }, duration);
    }
    
    // === Input Handling ===
    let selectedCard = null;
    let isDragging = false;
    let dragStart = { x: 0, y: 0 };
    
    canvas.addEventListener('pointerdown', (e) => {
      if (gameState !== 'playing') return;
      const rect = canvas.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      
      // Check if clicking on arena to spawn unit
      if (y < canvas.height * 0.6) {
        if (selectedCard && player.mana >= selectedCard.cost) {
          spawnUnit(selectedCard, x, y, true);
          player.mana -= selectedCard.cost;
          updateUI();
          selectedCard = null;
          renderHand();
        }
      }
      
      isDragging = true;
      dragStart = { x, y };
    });
    
    canvas.addEventListener('pointermove', (e) => {
      if (!isDragging) return;
      const rect = canvas.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      
      // Simple drag effect (could be expanded)
    });
    
    canvas.addEventListener('pointerup', () => {
      isDragging = false;
    });
    
    // === Game Functions ===
    function spawnUnit(card, x, y, isPlayer) {
      const unit = {
        ...card,
        x,
        y,
        maxHealth: card.health,
        isPlayer,
        target: null,
        attackCooldown: 0
      };
      
      if (isPlayer) {
        player.units.push(unit);
      } else {
        enemy.units.push(unit);
      }
      
      // Spawn particles
      for (let i = 0; i < 10; i++) {
        particles.push({
          x,
          y,
          vx: random(-3, 3),
          vy: random(-3, 3),
          life: 1,
          color: card.color
        });
      }
    }
    
    function drawCard(x, y, card, isSelectable = false) {
      ctx.fillStyle = card.color;
      ctx.fillRect(x - 40, y - 60, 80, 100);
      
      ctx.fillStyle = '#fff';
      ctx.font = 'bold 14px system-ui';
      ctx.textAlign = 'center';
      ctx.fillText(card.name, x, y - 40);
      
      ctx.font = '12px system-ui';
      ctx.fillText(`ืขืœื•ืช: ${card.cost}`, x, y - 20);
      ctx.fillText(`ื”ืชืงืคื”: ${card.attack}`, x, y);
      ctx.fillText(`ื—ื™ื™ื: ${card.health}`, x, y + 20);
      
      if (isSelectable) {
        ctx.strokeStyle = '#fff';
        ctx.lineWidth = 3;
        ctx.strokeRect(x - 42, y - 62, 84, 104);
      }
    }
    
    function updateUnits(delta) {
      // Player units
      player.units.forEach(unit => {
        if (unit.attackCooldown > 0) unit.attackCooldown -= delta;
        
        // Find nearest enemy unit or enemy base
        let nearest = null;
        let nearestDist = Infinity;
        
        enemy.units.forEach(enemyUnit => {
          const dist = Math.hypot(enemyUnit.x - unit.x, enemyUnit.y - unit.y);
          if (dist < nearestDist) {
            nearestDist = dist;
            nearest = enemyUnit;
          }
        });
        
        // If no enemy units, target enemy base
        if (!nearest) {
          const baseDist = Math.hypot(canvas.width / 2 - unit.x, 0 - unit.y);
          if (baseDist < nearestDist) {
            nearestDist = baseDist;
            nearest = { x: canvas.width / 2, y: 0, isBase: true };
          }
        }
        
        // Move towards target
        if (nearest && nearestDist > 30) {
          const angle = Math.atan2(nearest.y - unit.y, nearest.x - unit.x);
          unit.x += Math.cos(angle) * unit.speed;
          unit.y += Math.sin(angle) * unit.speed;
        } else if (nearest) {
          // Attack
          if (unit.attackCooldown <= 0) {
            if (nearest.isBase) {
              enemy.health -= unit.attack;
              showMessage(`-${unit.attack} ืœื‘ืกื™ืก!`);
            } else {
              nearest.health -= unit.attack;
              if (nearest.health <= 0) {
                enemy.units = enemy.units.filter(u => u !== nearest);
              }
            }
            unit.attackCooldown = 1; // 1 second cooldown
            
            // Attack projectile
            projectiles.push({
              x: unit.x,
              y: unit.y,
              targetX: nearest.x,
              targetY: nearest.y,
              life: 0.5,
              color: unit.color
            });
          }
        }
      });
      
      // Enemy units (simple AI)
      enemy.units.forEach(unit => {
        if (unit.attackCooldown > 0) unit.attackCooldown -= delta;
        
        // Find nearest player unit or player base
        let nearest = null;
        let nearestDist = Infinity;
        
        player.units.forEach(playerUnit => {
          const dist = Math.hypot(playerUnit.x - unit.x, playerUnit.y - unit.y);
          if (dist < nearestDist) {
            nearestDist = dist;
            nearest = playerUnit;
          }
        });
        
        // If no player units, target player base
        if (!nearest) {
          const baseDist = Math.hypot(canvas.width / 2 - unit.x, canvas.height - unit.y);
          if (baseDist < nearestDist) {
            nearestDist = baseDist;
            nearest = { x: canvas.width / 2, y: canvas.height, isBase: true };
          }
        }
        
        // Move towards target
        if (nearest && nearestDist > 30) {
          const angle = Math.atan2(nearest.y - unit.y, nearest.x - unit.x);
          unit.x += Math.cos(angle) * unit.speed;
          unit.y += Math.sin(angle) * unit.speed;
        } else if (nearest) {
          // Attack
          if (unit.attackCooldown <= 0) {
            if (nearest.isBase) {
              player.health -= unit.attack;
              showMessage(`-${unit.attack} ืœื‘ืกื™ืก!`);
            } else {
              nearest.health -= unit.attack;
              if (nearest.health <= 0) {
                player.units = player.units.filter(u => u !== nearest);
              }
            }
            unit.attackCooldown = 1;
            
            // Attack projectile
            projectiles.push({
              x: unit.x,
              y: unit.y,
              targetX: nearest.x,
              targetY: nearest.y,
              life: 0.5,
              color: unit.color
            });
          }
        }
      });
    }
    
    function updateParticles(delta) {
      particles.forEach(p => {
        p.x += p.vx;
        p.y += p.vy;
        p.life -= delta;
      });
      particles = particles.filter(p => p.life > 0);
    }
    
    function updateProjectiles(delta) {
      projectiles.forEach(p => {
        p.life -= delta;
      });
      projectiles = projectiles.filter(p => p.life > 0);
    }
    
    function drawUnits() {
      // Player units
      player.units.forEach(unit => {
        ctx.fillStyle = unit.color;
        ctx.beginPath();
        ctx.arc(unit.x, unit.y, 20, 0, Math.PI * 2);
        ctx.fill();
        
        // Health bar
        const healthPercent = unit.health / unit.maxHealth;
        ctx.fillStyle = '#e94560';
        ctx.fillRect(unit.x - 20, unit.y - 30, 40, 5);
        ctx.fillStyle = '#4ecca3';
        ctx.fillRect(unit.x - 20, unit.y - 30, 40 * healthPercent, 5);
      });
      
      // Enemy units
      enemy.units.forEach(unit => {
        ctx.fillStyle = unit.color;
        ctx.beginPath();
        ctx.arc(unit.x, unit.y, 20, 0, Math.PI * 2);
        ctx.fill();
        
        // Health bar
        const healthPercent = unit.health / unit.maxHealth;
        ctx.fillStyle = '#e94560';
        ctx.fillRect(unit.x - 20, unit.y - 30, 40, 5);
        ctx.fillStyle = '#4ecca3';
        ctx.fillRect(unit.x - 20, unit.y - 30, 40 * healthPercent, 5);
      });
    }
    
    function drawParticles() {
      particles.forEach(p => {
        ctx.fillStyle = p.color;
        ctx.globalAlpha = p.life;
        ctx.beginPath();
        ctx.arc(p.x, p.y, 5, 0, Math.PI * 2);
        ctx.fill();
        ctx.globalAlpha = 1;
      });
    }
    
    function drawProjectiles() {
      projectiles.forEach(p => {
        ctx.strokeStyle = p.color;
        ctx.lineWidth = 3;
        ctx.globalAlpha = p.life * 2;
        ctx.beginPath();
        ctx.moveTo(p.x, p.y);
        ctx.lineTo(p.targetX, p.targetY);
        ctx.stroke();
        ctx.globalAlpha = 1;
      });
    }
    
    function drawArena() {
      // Draw arena background
      ctx.fillStyle = 'rgba(0,0,0,0.3)';
      ctx.fillRect(0, canvas.height * 0.4, canvas.width, canvas.height * 0.6);
      
      // Draw center line
      ctx.strokeStyle = 'rgba(255,255,255,0.2)';
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.moveTo(0, canvas.height * 0.5);
      ctx.lineTo(canvas.width, canvas.height * 0.5);
      ctx.stroke();
    }
    
    function updateUI() {
      // Update mana
      const manaFill = document.getElementById('mana-fill');
      const manaText = document.getElementById('mana-text');
      manaFill.style.width = `${(player.mana / MAX_MANA) * 100}%`;
      manaText.textContent = `${player.mana} / ${MAX_MANA}`;
      
      // Update health
      const playerHealth = document.getElementById('player-health');
      const enemyHealth = document.getElementById('enemy-health');
      playerHealth.style.width = `${(player.health / PLAYER_MAX_HEALTH) * 100}%`;
      enemyHealth.style.width = `${(enemy.health / ENEMY_MAX_HEALTH) * 100}%`;
    }
    
    function renderHand() {
      const handContainer = document.getElementById('card-hand');
      handContainer.innerHTML = '';
      
      player.hand.forEach((card, index) => {
        const cardEl = document.createElement('div');
        cardEl.className = 'card';
        cardEl.innerHTML = `
          <div class="card-name">${card.name}</div>
          <div class="card-cost">${card.cost} ๐Ÿ’Ž</div>
          <div class="card-desc">${card.desc}</div>
        `;
        cardEl.style.borderColor = card.color;
        
        cardEl.addEventListener('click', () => {
          if (player.mana >= card.cost) {
            selectedCard = card;
            showMessage(`ื ื‘ื—ืจ: ${card.name}`);
            document.querySelectorAll('.card').forEach(c => c.style.transform = 'none');
            cardEl.style.transform = 'translateY(-20px) scale(1.1)';
          } else {
            showMessage('ืื™ืŸ ืžืกืคื™ืง ืžืื ื!');
          }
        });
        
        handContainer.appendChild(cardEl);
      });
    }
    
    function spawnEnemyUnit() {
      if (enemy.mana >= 2 && Math.random() < 0.02) {
        const card = CARDS[Math.floor(Math.random() * CARDS.length)];
        if (enemy.mana >= card.cost) {
          const x = random(canvas.width * 0.2, canvas.width * 0.8);
          const y = random(canvas.height * 0.1, canvas.height * 0.3);
          spawnUnit(card, x, y, false);
          enemy.mana -= card.cost;
        }
      }
    }
    
    function checkGameOver() {
      if (enemy.health <= 0) {
        gameState = 'gameover';
        document.getElementById('game-over-title').textContent = '๐ŸŽ‰ ื ื™ืฆื—ื•ืŸ!';
        document.getElementById('game-over-message').textContent = 'ื”ื‘ืกืช ืืช ื”ื™ืจื™ื‘!';
        document.getElementById('game-over-screen').classList.remove('hidden');
      } else if (player.health <= 0) {
        gameState = 'gameover';
        document.getElementById('game-over-title').textContent = '๐Ÿ’€ ื”ืคืกื“';
        document.getElementById('game-over-message').textContent = 'ื”ื™ืจื™ื‘ ื”ื‘ื™ืก ืื•ืชืš...';
        document.getElementById('game-over-screen').classList.remove('hidden');
      }
    }
    
    function gameLoop(timestamp) {
      const delta = (timestamp - lastTime) / 1000;
      lastTime = timestamp;
      
      if (gameState === 'playing') {
        // Clear canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        
        // Draw arena
        drawArena();
        
        // Update game objects
        updateUnits(delta);
        updateParticles(delta);
        updateProjectiles(delta);
        spawnEnemyUnit();
        
        // Regenerate mana
        if (player.mana < MAX_MANA) {
          player.mana += delta * 0.5; // 0.5 mana per second
        }
        if (enemy.mana < MAX_MANA) {
          enemy.mana += delta * 0.5;
        }
        
        // Draw game objects
        drawProjectiles();
        drawParticles();
        drawUnits();
        
        // Update UI
        updateUI();
        
        // Check game over
        checkGameOver();
      }
      
      requestAnimationFrame(gameLoop);
    }
    
    function startGame() {
      gameState = 'playing';
      player.health = PLAYER_MAX_HEALTH;
      player.mana = 3;
      player.hand = [];
      player.units = [];
      
      enemy.health = ENEMY_MAX_HEALTH;
      enemy.mana = 3;
      enemy.units = [];
      
      projectiles = [];
      particles = [];
      
      // Give player starting hand
      for (let i = 0; i < 3; i++) {
        const randomCard = CARDS[Math.floor(Math.random() * CARDS.length)];
        player.hand.push({ ...randomCard });
      }
      
      renderHand();
      updateUI();
      
      document.getElementById('start-screen').classList.add('hidden');
      document.getElementById('game-over-screen').classList.add('hidden');
      
      lastTime = performance.now();
      requestAnimationFrame(gameLoop);
    }
    
    // === Event Listeners ===
    document.getElementById('start-btn').addEventListener('click', startGame);
    document.getElementById('restart-btn').addEventListener('click', startGame);
    
    // Initial render
    resizeCanvas();
  </script>
</body>
</html>

Game Source: Remix of BeastClash

Creator: FrozenOtter31

Libraries: none

Complexity: complex (1531 lines, 42.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: remix-of-beastclash-frozenotter31" to link back to the original. Then publish at arcadelab.ai/publish.