Hill Climb Racing подобная игра
by PrismBolt10301 lines9.2 KB
<!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 / ←] Газ [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.