🎮ArcadeLab

Mario Landscape Game

by PrismCobra26
469 lines11.9 KB
▶ Play
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="screen-orientation" content="landscape">
<meta name="x5-orientation" content="landscape">
<title>Mario Landscape Game</title>
<style>
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
  }
  html, body {
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: #000;
    font-family: Arial, sans-serif;
  }
  #gameContainer {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #87CEEB;
  }
  canvas {
    display: block;
    background: linear-gradient(#87CEEB, #E0F7FF);
    image-rendering: pixelated;
  }
  /* Portrait warning */
  #rotateMsg {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    background: #222;
    color: white;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    z-index: 9999;
    text-align: center;
    padding: 20px;
  }
  #rotateMsg .icon {
    font-size: 80px;
    margin-bottom: 20px;
    animation: rotate 2s infinite;
  }
  @keyframes rotate {
    0%, 100% { transform: rotate(0deg); }
    50% { transform: rotate(90deg); }
  }
  #rotateMsg h2 {
    font-size: 24px;
    margin-bottom: 10px;
  }
  #rotateMsg p {
    font-size: 16px;
    opacity: 0.8;
    direction: rtl;
  }
  @media (orientation: portrait) {
    #rotateMsg { display: flex; }
    #gameContainer { display: none; }
  }

  /* Touch buttons */
  .btn {
    position: fixed;
    bottom: 15px;
    width: 70px;
    height: 70px;
    border-radius: 50%;
    border: 3px solid rgba(255,255,255,0.5);
    font-size: 26px;
    font-weight: bold;
    color: white;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 100;
    background: rgba(0,0,0,0.35);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    box-shadow: 0 4px 10px rgba(0,0,0,0.4);
    transition: transform 0.05s;
  }
  .btn:active, .btn.pressed {
    transform: scale(0.9);
    background: rgba(255,255,255,0.4);
  }
  #leftBtn { left: 15px; }
  #rightBtn { left: 100px; }
  #jumpBtn {
    right: 20px;
    width: 85px;
    height: 85px;
    bottom: 20px;
    font-size: 16px;
    background: rgba(39,174,96,0.6);
  }
</style>
</head>
<body>

<!-- Portrait Warning -->
<div id="rotateMsg">
  <div class="icon">📱</div>
  <h2>فون کو گھمائیں</h2>
  <p>گیم کھیلنے کے لیے فون کو سیدھا (افقی) کریں</p>
</div>

<!-- Game -->
<div id="gameContainer">
  <canvas id="game"></canvas>
</div>

<!-- Touch Controls -->
<button class="btn" id="leftBtn">◀</button>
<button class="btn" id="rightBtn">▶</button>
<button class="btn" id="jumpBtn">JUMP</button>

<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');

// فکسڈ گیم کی چوڑائی/اونچائی
const CW = 800;
const CH = 400;
canvas.width = CW;
canvas.height = CH;

// Canvas کو سکرین پر فٹ کریں (لینڈ اسکیپ میں)
function resizeCanvas() {
  const winW = window.innerWidth;
  const winH = window.innerHeight;
  const scale = Math.min(winW / CW, winH / CH);
  canvas.style.width = (CW * scale) + 'px';
  canvas.style.height = (CH * scale) + 'px';
}
window.addEventListener('resize', resizeCanvas);
window.addEventListener('orientationchange', () => {
  setTimeout(resizeCanvas, 300);
});
resizeCanvas();

// کی پریس حالت
const keys = { left: false, right: false, up: false };

// Touch buttons - بہتر handling
function bindButton(id, key) {
  const el = document.getElementById(id);
  const press = (e) => { e.preventDefault(); keys[key] = true; el.classList.add('pressed'); };
  const release = (e) => { e.preventDefault(); keys[key] = false; el.classList.remove('pressed'); };

  el.addEventListener('touchstart', press, { passive: false });
  el.addEventListener('touchend', release, { passive: false });
  el.addEventListener('touchcancel', release, { passive: false });
  el.addEventListener('mousedown', press);
  el.addEventListener('mouseup', release);
  el.addEventListener('mouseleave', release);
}
bindButton('leftBtn', 'left');
bindButton('rightBtn', 'right');
bindButton('jumpBtn', 'up');

// کیبورڈ سپورٹ (PC پر ٹیسٹ کے لیے)
document.addEventListener('keydown', e => {
  if (e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'A') keys.left = true;
  if (e.key === 'ArrowRight' || e.key === 'd' || e.key === 'D') keys.right = true;
  if (e.key === 'ArrowUp' || e.key === 'w' || e.key === 'W' || e.key === ' ') {
    keys.up = true;
    e.preventDefault();
  }
});
document.addEventListener('keyup', e => {
  if (e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'A') keys.left = false;
  if (e.key === 'ArrowRight' || e.key === 'd' || e.key === 'D') keys.right = false;
  if (e.key === 'ArrowUp' || e.key === 'w' || e.key === 'W' || e.key === ' ') keys.up = false;
});

// پلیئر
const player = {
  x: 50, y: 280, w: 28, h: 36,
  vx: 0, vy: 0,
  speed: 4, jumpPower: -11.5,
  onGround: false,
  facing: 1
};

const gravity = 0.6;

// پلیٹ فارم
const platforms = [
  {x: 0, y: 380, w: 800, h: 20},
  {x: 130, y: 310, w: 90, h: 15},
  {x: 270, y: 260, w: 100, h: 15},
  {x: 430, y: 210, w: 90, h: 15},
  {x: 590, y: 260, w: 100, h: 15},
  {x: 350, y: 330, w: 70, h: 15}
];

// سکے
const coins = [
  {x: 160, y: 275, r: 7, collected: false},
  {x: 310, y: 225, r: 7, collected: false},
  {x: 470, y: 175, r: 7, collected: false},
  {x: 630, y: 225, r: 7, collected: false},
  {x: 380, y: 295, r: 7, collected: false}
];

// دشمن
const enemies = [
  {x: 550, y: 350, w: 28, h: 28, vx: -1.4, minX: 480, maxX: 720, alive: true},
  {x: 200, y: 350, w: 28, h: 28, vx: 1.2, minX: 120, maxX: 320, alive: true}
];

let score = 0;
let gameOver = false;
let win = false;

function rectCollide(a, b) {
  return a.x < b.x + b.w && a.x + a.w > b.x &&
         a.y < b.y + b.h && a.y + a.h > b.y;
}

function resetGame() {
  player.x = 50; player.y = 280;
  player.vx = 0; player.vy = 0;
  player.onGround = false;
  score = 0;
  gameOver = false;
  win = false;
  coins.forEach(c => c.collected = false);
  enemies[0].alive = true; enemies[0].x = 550; enemies[0].vx = -1.4;
  enemies[1].alive = true; enemies[1].x = 200; enemies[1].vx = 1.2;
}

function update() {
  if (gameOver || win) {
    // Tap to restart
    if (keys.up || keys.left || keys.right) {
      if (gameOver || win) {
        setTimeout(() => {
          if (gameOver || win) resetGame();
        }, 100);
      }
    }
    return;
  }

  // Horizontal movement
  if (keys.left) { player.vx = -player.speed; player.facing = -1; }
  else if (keys.right) { player.vx = player.speed; player.facing = 1; }
  else { player.vx *= 0.75; if (Math.abs(player.vx) < 0.1) player.vx = 0; }

  // Jump
  if (keys.up && player.onGround) {
    player.vy = player.jumpPower;
    player.onGround = false;
  }

  player.vy += gravity;
  if (player.vy > 15) player.vy = 15;

  // Horizontal collision
  player.x += player.vx;
  for (let p of platforms) {
    if (rectCollide(player, p)) {
      if (player.vx > 0) player.x = p.x - player.w;
      else if (player.vx < 0) player.x = p.x + p.w;
      player.vx = 0;
    }
  }

  // Vertical collision
  player.y += player.vy;
  player.onGround = false;
  for (let p of platforms) {
    if (rectCollide(player, p)) {
      if (player.vy > 0) {
        player.y = p.y - player.h;
        player.vy = 0;
        player.onGround = true;
      } else if (player.vy < 0) {
        player.y = p.y + p.h;
        player.vy = 0;
      }
    }
  }

  // Boundaries
  if (player.x < 0) player.x = 0;
  if (player.x + player.w > CW) player.x = CW - player.w;
  if (player.y > CH + 100) gameOver = true;

  // Coins
  for (let c of coins) {
    if (!c.collected) {
      const cr = {x: c.x - c.r, y: c.y - c.r, w: c.r * 2, h: c.r * 2};
      if (rectCollide(player, cr)) { c.collected = true; score += 10; }
    }
  }

  // Enemies
  for (let e of enemies) {
    if (!e.alive) continue;
    e.x += e.vx;
    if (e.x < e.minX || e.x + e.w > e.maxX) e.vx *= -1;

    if (rectCollide(player, e)) {
      if (player.vy > 0 && player.y + player.h - player.vy <= e.y + 12) {
        e.alive = false;
        player.vy = -8;
        score += 50;
      } else {
        gameOver = true;
      }
    }
  }

  // Win
  if (player.x + player.w > CW - 40) win = true;
}

function draw() {
  // Sky
  const skyGrad = ctx.createLinearGradient(0, 0, 0, CH);
  skyGrad.addColorStop(0, '#87CEEB');
  skyGrad.addColorStop(1, '#E0F7FF');
  ctx.fillStyle = skyGrad;
  ctx.fillRect(0, 0, CW, CH);

  // Clouds
  ctx.fillStyle = 'white';
  ctx.beginPath();
  ctx.arc(120, 60, 22, 0, Math.PI * 2);
  ctx.arc(150, 50, 30, 0, Math.PI * 2);
  ctx.arc(180, 60, 22, 0, Math.PI * 2);
  ctx.fill();
  ctx.beginPath();
  ctx.arc(600, 90, 18, 0, Math.PI * 2);
  ctx.arc(630, 80, 26, 0, Math.PI * 2);
  ctx.arc(660, 90, 18, 0, Math.PI * 2);
  ctx.fill();

  // Platforms
  for (let p of platforms) {
    ctx.fillStyle = '#8B4513';
    ctx.fillRect(p.x, p.y, p.w, p.h);
    ctx.fillStyle = '#228B22';
    ctx.fillRect(p.x, p.y, p.w, 5);
  }

  // Coins
  for (let c of coins) {
    if (!c.collected) {
      ctx.beginPath();
      ctx.arc(c.x, c.y, c.r, 0, Math.PI * 2);
      ctx.fillStyle = '#FFD700';
      ctx.fill();
      ctx.strokeStyle = '#B8860B';
      ctx.lineWidth = 2;
      ctx.stroke();
    }
  }

  // Enemies
  for (let e of enemies) {
    if (e.alive) {
      ctx.fillStyle = '#8B0000';
      ctx.fillRect(e.x, e.y, e.w, e.h);
      ctx.fillStyle = 'white';
      ctx.fillRect(e.x + 5, e.y + 7, 6, 6);
      ctx.fillRect(e.x + 17, e.y + 7, 6, 6);
      ctx.fillStyle = 'black';
      ctx.fillRect(e.x + 7, e.y + 9, 3, 3);
      ctx.fillRect(e.x + 19, e.y + 9, 3, 3);
    }
  }

  // Flag (win point)
  ctx.fillStyle = '#654321';
  ctx.fillRect(CW - 35, 130, 5, 250);
  ctx.fillStyle = '#00AA00';
  ctx.beginPath();
  ctx.moveTo(CW - 30, 130);
  ctx.lineTo(CW - 5, 145);
  ctx.lineTo(CW - 30, 160);
  ctx.fill();

  // Player
  ctx.fillStyle = '#E52521';
  ctx.fillRect(player.x, player.y, player.w, player.h);
  ctx.fillStyle = '#1E90FF';
  ctx.fillRect(player.x + 3, player.y + 18, player.w - 6, player.h - 18);
  ctx.fillStyle = '#FFDAB9';
  ctx.fillRect(player.x + 4, player.y + 4, 20, 11);
  ctx.fillStyle = 'black';
  ctx.fillRect(player.x + 8, player.y + 7, 3, 4);
  ctx.fillRect(player.x + 16, player.y + 7, 3, 4);

  // Score
  ctx.fillStyle = 'rgba(0,0,0,0.7)';
  ctx.fillRect(8, 8, 130, 32);
  ctx.fillStyle = 'white';
  ctx.font = 'bold 18px Arial';
  ctx.fillText('Score: ' + score, 18, 30);

  // Game Over
  if (gameOver) {
    ctx.fillStyle = 'rgba(0,0,0,0.75)';
    ctx.fillRect(0, 0, CW, CH);
    ctx.fillStyle = 'white';
    ctx.font = 'bold 48px Arial';
    ctx.textAlign = 'center';
    ctx.fillText('Game Over!', CW/2, CH/2 - 20);
    ctx.fillStyle = '#FFD700';
    ctx.font = 'bold 26px Arial';
    ctx.fillText('Score: ' + score, CW/2, CH/2 + 25);
    ctx.fillStyle = 'white';
    ctx.font = '16px Arial';
    ctx.fillText('Tap JUMP to restart', CW/2, CH/2 + 65);
    ctx.textAlign = 'left';
  }

  // Win
  if (win) {
    ctx.fillStyle = 'rgba(0,0,0,0.75)';
    ctx.fillRect(0, 0, CW, CH);
    ctx.fillStyle = '#FFD700';
    ctx.font = 'bold 48px Arial';
    ctx.textAlign = 'center';
    ctx.fillText('🏆 You Win! 🏆', CW/2, CH/2 - 20);
    ctx.fillStyle = 'white';
    ctx.font = 'bold 26px Arial';
    ctx.fillText('Score: ' + score, CW/2, CH/2 + 25);
    ctx.font = '16px Arial';
    ctx.fillText('Tap JUMP to play again', CW/2, CH/2 + 65);
    ctx.textAlign = 'left';
  }
}

function gameLoop() {
  update();
  draw();
  requestAnimationFrame(gameLoop);
}
gameLoop();
</script>
</body>
</html>

Game Source: Mario Landscape Game

Creator: PrismCobra26

Libraries: none

Complexity: complex (469 lines, 11.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: mario-landscape-game-prismcobra26" to link back to the original. Then publish at arcadelab.ai/publish.