🎮ArcadeLab

Hill Climb Racing подобная игра

by PrismBolt10
301 lines9.2 KB
▶ Play
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>Hill Climb Racing подобная игра</title>
    <style>
        body {
            background: #1a472a;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            font-family: 'Courier New', monospace;
            overflow: hidden;
        }
        canvas {
            border: 4px solid #6b3e1c;
            border-radius: 12px;
            box-shadow: 0 10px 20px rgba(0,0,0,0.5);
            background: #87CEEB;
            cursor: pointer;
        }
        .controls {
            position: absolute;
            bottom: 20px;
            text-align: center;
            color: white;
            font-weight: bold;
            background: #2c2c2c;
            padding: 8px 16px;
            border-radius: 40px;
        }
        .info {
            position: absolute;
            top: 10px;
            left: 20px;
            background: rgba(0,0,0,0.7);
            color: #ffd966;
            padding: 8px 15px;
            border-radius: 20px;
            font-weight: bold;
            pointer-events: none;
            z-index: 10;
        }
        .reset-btn {
            position: absolute;
            top: 20px;
            right: 20px;
            background: #ff9900;
            border: none;
            font-size: 20px;
            font-weight: bold;
            padding: 6px 15px;
            border-radius: 30px;
            cursor: pointer;
            font-family: inherit;
            box-shadow: 0 2px 5px black;
        }
        .reset-btn:hover {
            background: #ffcc66;
        }
        @media (max-width: 700px) {
            .controls { font-size: 12px; }
        }
    </style>
</head>
<body>

<div class="info">Монеты: <span id="coinsVal">0</span> | Топливо: <span id="fuelVal">100%</span></div>
<button class="reset-btn" onclick="resetGame()">🔄 Сброс</button>

<div>
    <canvas id="gameCanvas" width="900" height="400"></canvas>
    <div class="controls">🎮 [A / ←] Газ &nbsp;&nbsp; [D / →] Тормоз/Назад</div>
</div>

<script>
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    
    // Элементы интерфейса
    const coinsEl = document.getElementById('coinsVal');
    const fuelEl = document.getElementById('fuelVal');

    // Игровые переменные
    let coins = 0;
    let fuel = 100;
    let gameOver = false;
    let distance = 0;

    // Параметры физики
    const gravity = 0.3;
    const friction = 0.98;

    // Автомобиль
    const car = {
        x: 100,
        y: 250,
        vx: 0,
        vy: 0,
        angle: 0,
        width: 80,
        height: 30,
        wheel1: { x: 60, y: 270, r: 15, vx: 0, vy: 0 },
        wheel2: { x: 140, y: 270, r: 15, vx: 0, vy: 0 },
        power: 0.1,
        brake: 0.05
    };

    // Генерация трассы
    const terrain = [];
    const length = 5000;
    let currentHeight = 250;
    for (let i = 0; i < length; i++) {
        if (i < 50) {
            terrain.push(currentHeight); // Ровный старт
        } else {
            let change = Math.sin(i * 0.03) * 20 + Math.cos(i * 0.01) * 30;
            currentHeight += change;
            if (currentHeight > 350) currentHeight = 350;
            if (currentHeight < 150) currentHeight = 150;
            terrain.push(currentHeight);
        }
    }

    // Монеты и топливо
    const items = [];
    for (let i = 200; i < length; i += 150) {
        if (Math.random() > 0.3) {
            items.push({ x: i * 2, y: terrain[i * 2] - 30, type: 'coin', collected: false });
        } else {
            items.push({ x: i * 2, y: terrain[i * 2] - 40, type: 'fuel', collected: false });
        }
    }

    // Управление
    const keys = { A: false, D: false, ArrowLeft: false, ArrowRight: false };
    window.addEventListener('keydown', (e) => {
        if (keys.hasOwnProperty(e.key.toUpperCase())) keys[e.key.toUpperCase()] = true;
        if (e.key === 'ArrowLeft') keys.ArrowLeft = true;
        if (e.key === 'ArrowRight') keys.ArrowRight = true;
    });
    window.addEventListener('keyup', (e) => {
        if (keys.hasOwnProperty(e.key.toUpperCase())) keys[e.key.toUpperCase()] = false;
        if (e.key === 'ArrowLeft') keys.ArrowLeft = false;
        if (e.key === 'ArrowRight') keys.ArrowRight = false;
    });

    function resetGame() {
        car.x = 100; car.y = 250; car.vx = 0; car.vy = 0; car.angle = 0;
        fuel = 100; coins = 0; gameOver = false; distance = 0;
        items.forEach(item => item.collected = false);
        loop();
    }

    // Получение высоты ландшафта
    function getTerrainHeight(x) {
        const index = Math.floor(x);
        if (index < 0 || index >= terrain.length) return 300;
        return terrain[index];
    }

    function update() {
        if (gameOver) return;

        // Физика автомобиля
        car.vy += gravity;
        car.x += car.vx;
        car.y += car.vy;
        car.vx *= friction;

        // Управление
        if (fuel > 0) {
            if (keys.A || keys.ArrowLeft) car.vx += car.power;
            if (keys.D || keys.ArrowRight) car.vx -= car.brake;

            // Расход топлива при нажатии Газа
            if (keys.A || keys.ArrowLeft) fuel -= 0.05;
            if (fuel < 0) fuel = 0;
        }

        distance = Math.floor(car.x / 10);

        // Столкновение машины с землей
        const groundY = getTerrainHeight(car.x);
        if (car.y + 15 > groundY) {
            car.y = groundY - 15;
            car.vy = -car.vy * 0.2; // Отскок
            car.vx *= 0.9; // Замедление
        }

        // Взаимодействие с монетами и канистрами
        items.forEach(item => {
            if (!item.collected) {
                const dist = Math.hypot(car.x - item.x, car.y - item.y);
                if (dist < 30) {
                    item.collected = true;
                    if (item.type === 'coin') {
                        coins += 100;
                        coinsEl.innerText = coins;
                    } else if (item.type === 'fuel') {
                        fuel = Math.min(100, fuel + 30);
                    }
                }
            }
        });

        if (fuel <= 0 && Math.abs(car.vx) < 0.2) gameOver = true;
    }

    function draw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Движение камеры за машиной
        ctx.save();
        const offsetX = canvas.width / 2 - car.x;
        ctx.translate(offsetX, 0);

        // Рисуем небо (статично)
        ctx.fillStyle = '#87CEEB';
        ctx.fillRect(-offsetX, 0, canvas.width, canvas.height);

        // Рисуем землю
        ctx.beginPath();
        ctx.moveTo(0, canvas.height);
        for (let i = 0; i < terrain.length; i++) {
            ctx.lineTo(i, terrain[i]);
        }
        ctx.lineTo(terrain.length, canvas.height);
        ctx.fillStyle = '#654321';
        ctx.fill();

        // Рисуем предметы
        items.forEach(item => {
            if (!item.collected) {
                ctx.beginPath();
                ctx.arc(item.x, item.y, 10, 0, Math.PI * 2);
                ctx.fillStyle = item.type === 'coin' ? '#FFD700' : '#FF4500';
                ctx.fill();
                ctx.lineWidth = 2;
                ctx.strokeStyle = 'black';
                ctx.stroke();
            }
        });

        // Рисуем машину
        ctx.save();
        ctx.translate(car.x, car.y);
        ctx.rotate(car.angle);
        ctx.fillStyle = '#FF0000';
        ctx.fillRect(-car.width / 2, -car.height, car.width, car.height);
        ctx.restore();

        // Колеса
        const wheel1Y = getTerrainHeight(car.x - car.width / 3) || 270;
        const wheel2Y = getTerrainHeight(car.x + car.width / 3) || 270;

        ctx.beginPath();
        ctx.arc(car.x - car.width / 3, wheel1Y - 15, 12, 0, Math.PI * 2);
        ctx.fillStyle = 'black';
        ctx.fill();

        ctx.beginPath();
        ctx.arc(car.x + car.width / 3, wheel2Y - 15, 12, 0, Math.PI * 2);
        ctx.fillStyle = 'black';
        ctx.fill();

        ctx.restore(); // Сброс камеры

        // Отображение топлива
        fuelEl.innerText = Math.floor(fuel) + '%';
    }

    function loop() {
        update();
        draw();

        // Проигрыш
        if (gameOver) {
            ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = 'white';
            ctx.font = '30px Courier New';
            ctx.textAlign = 'center';
            ctx.fillText('КОНЕЦ ИГРЫ', canvas.width / 2, canvas.height / 2);
            ctx.font = '20px Courier New';
            ctx.fillText('Пройдено: ' + distance + ' м', canvas.width / 2, canvas.height / 2 + 30);
            return;
        }

        requestAnimationFrame(loop);
    }

    loop();
</script>

</body>
</html>

Game Source: Hill Climb Racing подобная игра

Creator: PrismBolt10

Libraries: none

Complexity: complex (301 lines, 9.2 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: hill-climb-racing-prismbolt10" to link back to the original. Then publish at arcadelab.ai/publish.