Spaces:
Running
Running
<html lang="ru"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Гонки Шерегеш - Лыжные Гонки</title> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
font-family: 'Montserrat', sans-serif; | |
} | |
body { | |
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); | |
color: white; | |
min-height: 100vh; | |
overflow-x: hidden; | |
} | |
.container { | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 20px; | |
position: relative; | |
} | |
header { | |
text-align: center; | |
margin-bottom: 30px; | |
position: relative; | |
z-index: 10; | |
} | |
h1 { | |
font-size: 3rem; | |
margin-bottom: 10px; | |
text-shadow: 0 0 10px rgba(255, 255, 255, 0.3); | |
background: linear-gradient(to right, #fff, #65c7f7); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
} | |
.subtitle { | |
font-size: 1.2rem; | |
opacity: 0.9; | |
} | |
.game-area { | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
gap: 20px; | |
} | |
.menu { | |
background: rgba(0, 0, 0, 0.5); | |
border-radius: 15px; | |
padding: 30px; | |
width: 100%; | |
max-width: 800px; | |
backdrop-filter: blur(10px); | |
border: 1px solid rgba(255, 255, 255, 0.1); | |
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); | |
} | |
.menu-title { | |
font-size: 1.8rem; | |
margin-bottom: 20px; | |
text-align: center; | |
color: #65c7f7; | |
} | |
.difficulty-list { | |
list-style: none; | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
gap: 15px; | |
} | |
.difficulty-item { | |
background: rgba(255, 255, 255, 0.1); | |
border-radius: 10px; | |
padding: 15px; | |
text-align: center; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
border: 1px solid transparent; | |
} | |
.difficulty-item:hover { | |
transform: translateY(-5px); | |
background: rgba(255, 255, 255, 0.15); | |
border-color: rgba(255, 255, 255, 0.3); | |
} | |
.difficulty-item.locked { | |
opacity: 0.6; | |
cursor: not-allowed; | |
position: relative; | |
overflow: hidden; | |
} | |
.difficulty-item.locked::after { | |
content: '🔒'; | |
position: absolute; | |
top: 10px; | |
right: 10px; | |
font-size: 0.8rem; | |
} | |
.difficulty-name { | |
font-size: 1.3rem; | |
margin-bottom: 5px; | |
} | |
.difficulty-desc { | |
font-size: 0.9rem; | |
opacity: 0.8; | |
margin-bottom: 10px; | |
} | |
.difficulty-icon { | |
font-size: 2rem; | |
margin-bottom: 10px; | |
} | |
.race-canvas { | |
background: linear-gradient(to bottom, #87CEEB, #E0F7FA); | |
border-radius: 10px; | |
display: none; | |
overflow: hidden; | |
position: relative; | |
border: 3px solid rgba(255, 255, 255, 0.3); | |
} | |
.game-info { | |
display: flex; | |
justify-content: space-between; | |
width: 100%; | |
padding: 10px 20px; | |
background: rgba(0, 0, 0, 0.5); | |
border-radius: 8px; | |
margin-bottom: 10px; | |
} | |
.score-display { | |
font-size: 1.2rem; | |
} | |
.controls { | |
margin-top: 20px; | |
display: flex; | |
flex-direction: column; | |
gap: 10px; | |
} | |
.btn { | |
background: linear-gradient(45deg, #65c7f7, #0052d9); | |
border: none; | |
color: white; | |
padding: 12px 25px; | |
border-radius: 30px; | |
font-size: 1rem; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
font-weight: bold; | |
text-transform: uppercase; | |
letter-spacing: 1px; | |
} | |
.btn:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 5px 15px rgba(101, 199, 247, 0.4); | |
} | |
.btn:active { | |
transform: translateY(1px); | |
} | |
.btn.secondary { | |
background: rgba(255, 255, 255, 0.1); | |
} | |
.btn.secondary:hover { | |
background: rgba(255, 255, 255, 0.2); | |
} | |
.game-over { | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
background: rgba(0, 0, 0, 0.8); | |
padding: 30px; | |
border-radius: 15px; | |
text-align: center; | |
z-index: 100; | |
display: none; | |
width: 80%; | |
max-width: 500px; | |
backdrop-filter: blur(5px); | |
border: 1px solid rgba(255, 255, 255, 0.1); | |
} | |
.game-over h2 { | |
font-size: 2rem; | |
margin-bottom: 20px; | |
color: #65c7f7; | |
} | |
.game-over p { | |
font-size: 1.2rem; | |
margin-bottom: 20px; | |
} | |
.particles { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
pointer-events: none; | |
z-index: 1; | |
} | |
.snow { | |
position: absolute; | |
width: 3px; | |
height: 3px; | |
background: white; | |
border-radius: 50%; | |
opacity: 0.7; | |
animation: fall linear infinite; | |
} | |
@keyframes fall { | |
to { | |
transform: translateY(100vh) translateX(10vw); | |
} | |
} | |
.mountains { | |
position: absolute; | |
bottom: 0; | |
left: 0; | |
width: 100%; | |
height: 100px; | |
background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.3)); | |
z-index: 2; | |
} | |
.mountain { | |
position: absolute; | |
bottom: 0; | |
width: 0; | |
height: 0; | |
border-left: 100px solid transparent; | |
border-right: 100px solid transparent; | |
border-bottom: 150px solid rgba(255, 255, 255, 0.1); | |
} | |
.mountain:nth-child(1) { | |
left: 10%; | |
border-bottom-width: 180px; | |
} | |
.mountain:nth-child(2) { | |
left: 30%; | |
border-bottom-width: 200px; | |
} | |
.mountain:nth-child(3) { | |
left: 60%; | |
border-bottom-width: 160px; | |
} | |
.mountain:nth-child(4) { | |
left: 80%; | |
border-bottom-width: 190px; | |
} | |
.progress-container { | |
width: 100%; | |
height: 20px; | |
background: rgba(255, 255, 255, 0.1); | |
border-radius: 10px; | |
margin-bottom: 20px; | |
overflow: hidden; | |
} | |
.progress-bar { | |
height: 100%; | |
background: linear-gradient(to right, #65c7f7, #0052d9); | |
border-radius: 10px; | |
width: 0%; | |
transition: width 0.3s ease; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="particles" id="particles"></div> | |
<div class="mountains"> | |
<div class="mountain"></div> | |
<div class="mountain"></div> | |
<div class="mountain"></div> | |
<div class="mountain"></div> | |
</div> | |
<div class="container"> | |
<header> | |
<h1>Гонки Шерегеш</h1> | |
<p class="subtitle">Испытай свою скорость на заснеженных склонах!</p> | |
</header> | |
<div class="game-area"> | |
<div class="menu" id="mainMenu"> | |
<h2 class="menu-title">Выберите испытание</h2> | |
<ul class="difficulty-list"> | |
<li class="difficulty-item" data-difficulty="easy"> | |
<div class="difficulty-icon">⛷️</div> | |
<h3 class="difficulty-name">Легкая трасса</h3> | |
<p class="difficulty-desc">Плавные спуски, идеально для начинающих</p> | |
<button class="btn">Начать</button> | |
</li> | |
<li class="difficulty-item" data-difficulty="medium"> | |
<div class="difficulty-icon">⛷️⛷️</div> | |
<h3 class="difficulty-name">Средняя трасса</h3> | |
<p class="difficulty-desc">Больше поворотов и небольшие препятствия</p> | |
<button class="btn">Начать</button> | |
</li> | |
<li class="difficulty-item" data-difficulty="hard" id="hardLevel"> | |
<div class="difficulty-icon">⛷️⛷️⛷️</div> | |
<h3 class="difficulty-name">Сложная трасса</h3> | |
<p class="difficulty-desc">Крутые склоны и сложные повороты</p> | |
<button class="btn">Начать</button> | |
</li> | |
<li class="difficulty-item locked" data-difficulty="extreme" id="extremeLevel"> | |
<div class="difficulty-icon">💀</div> | |
<h3 class="difficulty-name">Экстрим</h3> | |
<p class="difficulty-desc">Бегите от бурана и выживайте!</p> | |
<button class="btn">Заблокировано</button> | |
</li> | |
<li class="difficulty-item locked" data-difficulty="race" id="raceMode"> | |
<div class="difficulty-icon">🏁</div> | |
<h3 class="difficulty-name">Режим гонки</h3> | |
<p class="difficulty-desc">Случайная трасса с выбором сложности</p> | |
<button class="btn">Заблокировано</button> | |
</li> | |
</ul> | |
</div> | |
<div class="game-info" style="display: none;" id="gameInfo"> | |
<div class="score-display"> | |
Скорость: <span id="speedDisplay">0</span> км/ч | |
</div> | |
<div class="score-display"> | |
Пройдено: <span id="distanceDisplay">0</span> м | |
</div> | |
<div class="score-display"> | |
Время: <span id="timeDisplay">0</span> сек | |
</div> | |
</div> | |
<div class="progress-container" id="progressContainer" style="display: none;"> | |
<div class="progress-bar" id="progressBar"></div> | |
</div> | |
<canvas id="gameCanvas" class="race-canvas" width="800" height="500"></canvas> | |
<div class="controls" style="display: none;" id="gameControls"> | |
<button class="btn" id="pauseBtn">Пауза</button> | |
<button class="btn secondary" id="backToMenuBtn">В меню</button> | |
</div> | |
</div> | |
</div> | |
<div class="game-over" id="gameOver"> | |
<h2 id="resultTitle">Испытание пройдено!</h2> | |
<p>Ваш результат:</p> | |
<div id="resultStats"> | |
<p>Скорость: <span id="finalSpeed">0</span> км/ч</p> | |
<p>Дистанция: <span id="finalDistance">0</span> м</p> | |
<p>Время: <span id="finalTime">0</span> сек</p> | |
</div> | |
<button class="btn" id="continueBtn">Продолжить</button> | |
<button class="btn secondary" id="menuBtn">В меню</button> | |
</div> | |
<script> | |
// Объект состояния игры | |
const gameState = { | |
difficulty: null, | |
isPlaying: false, | |
score: 0, | |
distance: 0, | |
time: 0, | |
speed: 0, | |
maxSpeed: 0, | |
completed: { | |
easy: false, | |
medium: false, | |
hard: false, | |
extreme: false | |
}, | |
playerX: 100, | |
playerY: 250, | |
obstacles: [], | |
lastObstacleTime: 0, | |
obstacleInterval: 2000, | |
gameWidth: 800, | |
gameHeight: 500, | |
keys: {}, | |
progress: 0, | |
blizzardActive: false, | |
blizzardSpeed: 0, | |
blizzardSize: 0, | |
blizzardDirection: 1, | |
blizzardInterval: null, | |
requiredProgress: 1000 | |
}; | |
// DOM элементы | |
const elements = { | |
mainMenu: document.getElementById('mainMenu'), | |
gameCanvas: document.getElementById('gameCanvas'), | |
gameInfo: document.getElementById('gameInfo'), | |
progressContainer: document.getElementById('progressContainer'), | |
progressBar: document.getElementById('progressBar'), | |
gameControls: document.getElementById('gameControls'), | |
gameOver: document.getElementById('gameOver'), | |
pauseBtn: document.getElementById('pauseBtn'), | |
backToMenuBtn: document.getElementById('backToMenuBtn'), | |
continueBtn: document.getElementById('continueBtn'), | |
menuBtn: document.getElementById('menuBtn'), | |
resultTitle: document.getElementById('resultTitle'), | |
resultStats: document.getElementById('resultStats'), | |
finalSpeed: document.getElementById('finalSpeed'), | |
finalDistance: document.getElementById('finalDistance'), | |
finalTime: document.getElementById('finalTime'), | |
speedDisplay: document.getElementById('speedDisplay'), | |
distanceDisplay: document.getElementById('distanceDisplay'), | |
timeDisplay: document.getElementById('timeDisplay'), | |
hardLevel: document.getElementById('hardLevel'), | |
extremeLevel: document.getElementById('extremeLevel'), | |
raceMode: document.getElementById('raceMode'), | |
particles: document.getElementById('particles') | |
}; | |
// Инициализация игры | |
function initGame() { | |
// Создание снежинок | |
createSnowflakes(); | |
// Настройка сложностей | |
document.querySelectorAll('.difficulty-item').forEach(item => { | |
if (!item.classList.contains('locked')) { | |
item.querySelector('button').addEventListener('click', () => { | |
const difficulty = item.getAttribute('data-difficulty'); | |
startGame(difficulty); | |
}); | |
} | |
}); | |
// Кнопки управления | |
elements.pauseBtn.addEventListener('click', togglePause); | |
elements.backToMenuBtn.addEventListener('click', backToMenu); | |
elements.continueBtn.addEventListener('click', continueGame); | |
elements.menuBtn.addEventListener('click', backToMenu); | |
// Обработка клавиш | |
document.addEventListener('keydown', (e) => { | |
if (gameState.isPlaying) { | |
if (e.key === 'Escape') { | |
togglePause(); | |
} else { | |
gameState.keys[e.key] = true; | |
} | |
} | |
}); | |
document.addEventListener('keyup', (e) => { | |
gameState.keys[e.key] = false; | |
}); | |
// Проверяем сохраненные прогрессы | |
const savedProgress = localStorage.getItem('sheregeshProgress'); | |
if (savedProgress) { | |
const progress = JSON.parse(savedProgress); | |
gameState.completed = progress; | |
// Разблокируем уровни по прогрессу | |
if (progress.easy && progress.medium) { | |
elements.hardLevel.classList.remove('locked'); | |
elements.hardLevel.querySelector('button').textContent = 'Начать'; | |
} | |
if (progress.easy && progress.medium && progress.hard) { | |
elements.extremeLevel.classList.remove('locked'); | |
elements.extremeLevel.querySelector('button').textContent = 'Начать'; | |
} | |
if (progress.easy && progress.medium && progress.hard && progress.extreme) { | |
elements.raceMode.classList.remove('locked'); | |
elements.raceMode.querySelector('button').textContent = 'Начать'; | |
} | |
} | |
} | |
// Создание снежинок | |
function createSnowflakes() { | |
for (let i = 0; i < 100; i++) { | |
const snowflake = document.createElement('div'); | |
snowflake.classList.add('snow'); | |
// Рандомные параметры снежинок | |
const size = Math.random() * 5; | |
const opacity = Math.random() * 0.7 + 0.3; | |
const x = Math.random() * 100; | |
const duration = Math.random() * 10 + 5; | |
const delay = Math.random() * 10; | |
snowflake.style.width = `${size}px`; | |
snowflake.style.height = `${size}px`; | |
snowflake.style.opacity = opacity; | |
snowflake.style.left = `${x}vw`; | |
snowflake.style.animationDuration = `${duration}s`; | |
snowflake.style.animationDelay = `-${delay}s`; | |
elements.particles.appendChild(snowflake); | |
} | |
} | |
// Начало игры | |
function startGame(difficulty) { | |
gameState.difficulty = difficulty; | |
gameState.isPlaying = true; | |
gameState.score = 0; | |
gameState.distance = 0; | |
gameState.time = 0; | |
gameState.speed = 0; | |
gameState.maxSpeed = getMaxSpeed(difficulty); | |
gameState.playerX = 100; | |
gameState.playerY = 250; | |
gameState.obstacles = []; | |
gameState.lastObstacleTime = 0; | |
gameState.progress = 0; | |
gameState.blizzardActive = difficulty === 'extreme'; | |
gameState.blizzardSpeed = 0; | |
gameState.blizzardSize = 0; | |
gameState.blizzardDirection = 1; | |
gameState.requiredProgress = getRequiredProgress(difficulty); | |
// Настройка интервала препятствий | |
gameState.obstacleInterval = getObstacleInterval(difficulty); | |
// Скрытие меню, показ игры | |
elements.mainMenu.style.display = 'none'; | |
elements.gameCanvas.style.display = 'block'; | |
elements.gameInfo.style.display = 'flex'; | |
elements.gameControls.style.display = 'flex'; | |
// Для экстрима показываем прогресс | |
if (difficulty === 'extreme') { | |
elements.progressContainer.style.display = 'block'; | |
} else { | |
elements.progressContainer.style.display = 'none'; | |
} | |
// Настройка canvas | |
const ctx = elements.gameCanvas.getContext('2d'); | |
ctx.imageSmoothingEnabled = true; | |
// Запуск игрового цикла | |
gameState.lastTime = Date.now(); | |
gameState.gameLoop = requestAnimationFrame(updateGame); | |
// Для бурана | |
if (gameState.blizzardActive) { | |
startBlizzard(); | |
} | |
} | |
// Получение максимальной скорости в зависимости от сложности | |
function getMaxSpeed(difficulty) { | |
switch(difficulty) { | |
case 'easy': return 60; | |
case 'medium': return 100; | |
case 'hard': return 140; | |
case 'extreme': return 180; | |
case 'race': return 120; | |
default: return 60; | |
} | |
} | |
// Получение интервала между препятствиями | |
function getObstacleInterval(difficulty) { | |
switch(difficulty) { | |
case 'easy': return 3000; | |
case 'medium': return 2000; | |
case 'hard': return 1500; | |
case 'extreme': return 1200; | |
case 'race': return 1800; | |
default: return 2000; | |
} | |
} | |
// Получение необходимого прогресса для завершения уровня | |
function getRequiredProgress(difficulty) { | |
switch(difficulty) { | |
case 'easy': return 500; | |
case 'medium': return 800; | |
case 'hard': return 1200; | |
case 'extreme': return 1500; | |
case 'race': return 1000; | |
default: return 500; | |
} | |
} | |
// Запуск бурана | |
function startBlizzard() { | |
gameState.blizzardInterval = setInterval(() => { | |
if (gameState.blizzardDirection === 1 && gameState.blizzardSize < 100) { | |
gameState.blizzardSpeed += 1; | |
gameState.blizzardSize += 1; | |
} else if (gameState.blizzardDirection === 1 && gameState.blizzardSize >= 100) { | |
gameState.blizzardDirection = -1; | |
} else if (gameState.blizzardDirection === -1 && gameState.blizzardSize > 0) { | |
gameState.blizzardSpeed -= 0.5; | |
gameState.blizzardSize -= 0.5; | |
} else { | |
gameState.blizzardDirection = 1; | |
} | |
}, 100); | |
} | |
// Остановка бурана | |
function stopBlizzard() { | |
if (gameState.blizzardInterval) { | |
clearInterval(gameState.blizzardInterval); | |
gameState.blizzardInterval = null; | |
} | |
} | |
// Игровой цикл | |
function updateGame() { | |
const now = Date.now(); | |
const deltaTime = (now - gameState.lastTime) / 1000; | |
gameState.lastTime = now; | |
if (!gameState.isPaused) { | |
// Обновление состояния игры | |
updateGameState(deltaTime); | |
// Отрисовка игры | |
renderGame(); | |
// Проверка условий завершения | |
if (gameState.difficulty === 'extreme' || gameState.difficulty === 'race') { | |
if (gameState.progress >= gameState.requiredProgress) { | |
completeLevel(); | |
return; | |
} | |
} | |
// Для других уровней просто по времени | |
if (gameState.difficulty !== 'extreme' && gameState.time >= 60) { | |
completeLevel(); | |
return; | |
} | |
} | |
gameState.gameLoop = requestAnimationFrame(updateGame); | |
} | |
// Обновление состояния игры | |
function updateGameState(deltaTime) { | |
// Увеличение времени и дистанции | |
gameState.time += deltaTime; | |
// Управление скоростью | |
if (gameState.keys['ArrowUp'] || gameState.keys['w']) { | |
gameState.speed = Math.min(gameState.speed + 10 * deltaTime, gameState.maxSpeed); | |
} else if (gameState.keys['ArrowDown'] || gameState.keys['s']) { | |
gameState.speed = Math.max(gameState.speed - 15 * deltaTime, 0); | |
} else { | |
// Постепенное замедление | |
gameState.speed = Math.max(gameState.speed - 5 * deltaTime, 0); | |
} | |
// Изменение положения игрока по вертикали | |
if (gameState.keys['ArrowLeft'] || gameState.keys['a']) { | |
gameState.playerX = Math.max(gameState.playerX - 200 * deltaTime, 50); | |
} | |
if (gameState.keys['ArrowRight'] || gameState.keys['d']) { | |
gameState.playerX = Math.min(gameState.playerX + 200 * deltaTime, gameState.gameWidth - 50); | |
} | |
// Увеличение дистанции в зависимости от скорости | |
gameState.distance += gameState.speed * deltaTime; | |
// Обновление препятствий | |
updateObstacles(deltaTime); | |
// Для экстремального режима - обновление прогресса | |
if (gameState.difficulty === 'extreme') { | |
gameState.progress += gameState.speed * deltaTime * 0.1; | |
elements.progressBar.style.width = `${Math.min((gameState.progress / gameState.requiredProgress) * 100, 100)}%`; | |
// Проверка поражения от бурана | |
if (gameState.blizzardActive && gameState.speed < gameState.blizzardSpeed) { | |
endGame(false); | |
return; | |
} | |
} else if (gameState.difficulty === 'race') { | |
gameState.progress += gameState.speed * deltaTime * 0.2; | |
} | |
// Обновление UI | |
elements.speedDisplay.textContent = Math.round(gameState.speed); | |
elements.distanceDisplay.textContent = Math.round(gameState.distance); | |
elements.timeDisplay.textContent = Math.round(gameState.time); | |
} | |
// Обновление препятствий | |
function updateObstacles(deltaTime) { | |
// Создание нового препятствия | |
if (Date.now() - gameState.lastObstacleTime > gameState.obstacleInterval) { | |
createObstacle(); | |
gameState.lastObstacleTime = Date.now(); | |
} | |
// Обновление позиций препятствий | |
for (let i = gameState.obstacles.length - 1; i >= 0; i--) { | |
const obstacle = gameState.obstacles[i]; | |
obstacle.x -= gameState.speed * deltaTime; | |
// Проверка столкновения | |
if (checkCollision(gameState.playerX, gameState.playerY, obstacle.x, obstacle.y, obstacle.width, obstacle.height)) { | |
endGame(false); | |
break; | |
} | |
// Удаление препятствий за пределами экрана | |
if (obstacle.x + obstacle.width < 0) { | |
gameState.obstacles.splice(i, 1); | |
gameState.score += 10; | |
} | |
} | |
} | |
// Создание нового препятствия | |
function createObstacle() { | |
const types = ['tree', 'rock', 'jump']; | |
const type = types[Math.floor(Math.random() * types.length)]; | |
const yPositions = [300, 350, 400]; | |
const y = yPositions[Math.floor(Math.random() * yPositions.length)]; | |
let width, height, x; | |
if (type === 'tree') { | |
width = 40; | |
height = 80; | |
x = gameState.gameWidth + Math.random() * 100; | |
} else if (type === 'rock') { | |
width = 60; | |
height = 40; | |
x = gameState.gameWidth + Math.random() * 100; | |
} else if (type === 'jump') { | |
width = 100; | |
height = 20; | |
x = gameState.gameWidth + Math.random() * 150; | |
} | |
gameState.obstacles.push({ | |
type, | |
x, | |
y, | |
width, | |
height | |
}); | |
} | |
// Проверка столкновения | |
function checkCollision(px, py, ox, oy, ow, oh) { | |
// Простая проверка столкновения AABB | |
return px < ox + ow && | |
px + 40 > ox && | |
py < oy + oh && | |
py + 60 > oy; | |
} | |
// Отрисовка игры | |
function renderGame() { | |
const ctx = elements.gameCanvas.getContext('2d'); | |
ctx.clearRect(0, 0, gameState.gameWidth, gameState.gameHeight); | |
// Рисуем фон | |
drawBackground(ctx); | |
// Рисуем препятствия | |
drawObstacles(ctx); | |
// Рисуем игрока | |
drawPlayer(ctx); | |
// Для экстрима - рисуем буран | |
if (gameState.blizzardActive) { | |
drawBlizzard(ctx); | |
} | |
} | |
// Отрисовка фона | |
function drawBackground(ctx) { | |
// Небо | |
const skyGradient = ctx.createLinearGradient(0, 0, 0, gameState.gameHeight); | |
skyGradient.addColorStop(0, '#87CEEB'); | |
skyGradient.addColorStop(1, '#E0F7FA'); | |
ctx.fillStyle = skyGradient; | |
ctx.fillRect(0, 0, gameState.gameWidth, gameState.gameHeight); | |
// Снег (земля) | |
ctx.fillStyle = 'white'; | |
ctx.fillRect(0, gameState.gameHeight - 100, gameState.gameWidth, 100); | |
// Горы на заднем фоне | |
ctx.fillStyle = 'rgba(255, 255, 255, 0.2)'; | |
for (let i = 0; i < 4; i++) { | |
const x = i * 200 + (gameState.distance % 200); | |
drawMountain(ctx, x, gameState.gameHeight - 100); | |
} | |
} | |
// Отрисовка одной горы | |
function drawMountain(ctx, x, y) { | |
ctx.beginPath(); | |
ctx.moveTo(x, y); | |
ctx.lineTo(x + 100, y - 100); | |
ctx.lineTo(x + 200, y); | |
ctx.fill(); | |
} | |
// Отрисовка препятствий | |
function drawObstacles(ctx) { | |
gameState.obstacles.forEach(obstacle => { | |
if (obstacle.type === 'tree') { | |
ctx.fillStyle = '#8B4513'; | |
ctx.fillRect(obstacle.x, obstacle.y, 10, obstacle.height); | |
ctx.fillStyle = '#228B22'; | |
ctx.beginPath(); | |
ctx.arc(obstacle.x + 5, obstacle.y - 10, 20, 0, Math.PI * 2); | |
ctx.fill(); | |
} else if (obstacle.type === 'rock') { | |
ctx.fillStyle = '#808080'; | |
ctx.beginPath(); | |
ctx.arc(obstacle.x + obstacle.width/2, obstacle.y + obstacle.height/2, obstacle.width/2, 0, Math.PI * 2); | |
ctx.fill(); | |
} else if (obstacle.type === 'jump') { | |
ctx.fillStyle = '#A0522D'; | |
ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height); | |
} | |
}); | |
} | |
// Отрисовка игрока | |
function drawPlayer(ctx) { | |
ctx.fillStyle = '#FF0000'; | |
ctx.beginPath(); | |
// Туловище | |
ctx.moveTo(gameState.playerX, gameState.playerY); | |
ctx.lineTo(gameState.playerX - 20, gameState.playerY + 40); | |
ctx.lineTo(gameState.playerX + 20, gameState.playerY + 40); | |
ctx.closePath(); | |
ctx.fill(); | |
// Голова | |
ctx.fillStyle = '#FFD700'; | |
ctx.beginPath(); | |
ctx.arc(gameState.playerX, gameState.playerY - 10, 10, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
// Отрисовка бурана | |
function drawBlizzard(ctx) { | |
ctx.fillStyle = `rgba(255, 255, 255, ${gameState.blizzardSize/100 * 0.7})`; | |
ctx.fillRect(0, 0, gameState.gameWidth, gameState.gameHeight); | |
// Текст скорости бурана | |
ctx.fillStyle = 'red'; | |
ctx.font = '20px Montserrat'; | |
ctx.fillText(`Буран: ${Math.round(gameState.blizzardSpeed)} км/ч`, 20, 30); | |
ctx.fillText(`Ваша скорость: ${Math.round(gameState.speed)} км/ч`, 20, 60); | |
} | |
// Пауза игры | |
function togglePause() { | |
gameState.isPaused = !gameState.isPaused; | |
elements.pauseBtn.textContent = gameState.isPaused ? 'Продолжить' : 'Пауза'; | |
if (gameState.isPaused) { | |
cancelAnimationFrame(gameState.gameLoop); | |
} else { | |
gameState.lastTime = Date.now(); | |
gameState.gameLoop = requestAnimationFrame(updateGame); | |
} | |
} | |
// Завершение уровня | |
function completeLevel() { | |
endGame(true); | |
} | |
// Конец игры | |
function endGame(isSuccess) { | |
cancelAnimationFrame(gameState.gameLoop); | |
gameState.isPlaying = false; | |
if (gameState.blizzardInterval) { | |
stopBlizzard(); | |
} | |
// Обновление UI | |
elements.finalSpeed.textContent = Math.round(gameState.speed); | |
elements.finalDistance.textContent = Math.round(gameState.distance); | |
elements.finalTime.textContent = Math.round(gameState.time); | |
if (isSuccess) { | |
elements.resultTitle.textContent = 'Испытание пройдено!'; | |
// Обновляем прогресс | |
gameState.completed[gameState.difficulty] = true; | |
localStorage.setItem('sheregeshProgress', JSON.stringify(gameState.completed)); | |
// Разблокируем следующие уровни | |
if (gameState.difficulty === 'easy' && !gameState.completed.medium) { | |
elements.hardLevel.classList.remove('locked'); | |
elements.hardLevel.querySelector('button').textContent = 'Начать'; | |
} | |
if (gameState.difficulty === 'medium' && !gameState.completed.hard) { | |
elements.extremeLevel.classList.remove('locked'); | |
elements.extremeLevel.querySelector('button').textContent = 'Начать'; | |
} | |
if (gameState.difficulty === 'hard' && !gameState.completed.extreme) { | |
elements.raceMode.classList.remove('locked'); | |
elements.raceMode.querySelector('button').textContent = 'Начать'; | |
} | |
} else { | |
elements.resultTitle.textContent = gameState.blizzardActive && gameState.speed < gameState.blizzardSpeed ? | |
'Буран вас настиг!' : 'Вы упали!'; | |
} | |
// Показываем экран завершения | |
elements.gameOver.style.display = 'block'; | |
} | |
// Возврат в меню | |
function backToMenu() { | |
if (gameState.isPlaying) { | |
cancelAnimationFrame(gameState.gameLoop); | |
gameState.isPlaying = false; | |
} | |
if (gameState.blizzardInterval) { | |
stopBlizzard(); | |
} | |
elements.mainMenu.style.display = 'block'; | |
elements.gameCanvas.style.display = 'none'; | |
elements.gameInfo.style.display = 'none'; | |
elements.gameControls.style.display = 'none'; | |
elements.progressContainer.style.display = 'none'; | |
elements.gameOver.style.display = 'none'; | |
} | |
// Продолжение игры (после прохождения уровня) | |
function continueGame() { | |
elements.gameOver.style.display = 'none'; | |
backToMenu(); | |
} | |
// Запуск игры при загрузке страницы | |
window.addEventListener('load', initGame); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: absolute; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">This website has been generated by <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> | |
</html> |