Hill climb Race Car Move Animation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hill Climb Racing</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #87CEEB;
font-family: Arial, sans-serif;
overflow: hidden;
user-select: none;
touch-action: manipulation;
}
#game-container {
position: relative;
width: 800px;
max-width: 100%;
height: 400px;
margin: 20px auto;
border: 4px solid #333;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
background-color: #7CFC00;
overflow: hidden;
}
#game-canvas {
background-color: #87CEEB;
display: block;
width: 100%;
height: 100%;
}
#ui-container {
position: absolute;
top: 10px;
left: 10px;
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
font-size: 18px;
pointer-events: none;
}
#game-over {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
font-size: 36px;
}
#restart-btn {
margin-top: 20px;
padding: 10px 20px;
font-size: 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
#restart-btn:hover {
background-color: #45a049;
}
.controls {
text-align: center;
margin-top: 10px;
font-size: 18px;
color: #333;
}
/* On-screen controls */
#touch-controls {
display: flex;
justify-content: space-between;
position: absolute;
bottom: 20px;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
.arrow-btn {
width: 80px;
height: 80px;
background-color: rgba(0, 0, 0, 0.3);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 40px;
color: white;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
.arrow-btn:active {
background-color: rgba(0, 0, 0, 0.5);
transform: scale(0.95);
}
@media (max-width: 600px) {
.arrow-btn {
width: 60px;
height: 60px;
font-size: 30px;
}
}
</style>
</head>
<body>
<div id="game-container">
<canvas id="game-canvas"></canvas>
<div id="ui-container">
<div>Distance: <span id="distance">0</span>m</div>
<div>Fuel: <span id="fuel">100</span>%</div>
</div>
<div id="game-over">
<div>Game Over!</div>
<div>Your score: <span id="final-score">0</span>m</div>
<button id="restart-btn">Play Again</button>
</div>
<!-- On-screen controls -->
<div id="touch-controls">
<div class="arrow-btn" id="left-btn">←</div>
<div class="arrow-btn" id="right-btn">→</div>
</div>
</div>
<div class="controls">
Use <strong>arrow keys</strong> or <strong>on-screen buttons</strong> to drive
</div>
<script>
// Game variables
const canvas = document.getElementById('game-canvas');
const ctx = canvas.getContext('2d');
// Set canvas size
function resizeCanvas() {
const container = document.getElementById('game-container');
canvas.width = container.clientWidth;
canvas.height = container.clientHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
let playerX = 100;
let playerY = 300;
let velocityX = 0;
let velocityY = 0;
let terrain = [];
let score = 0;
let fuel = 100;
let gameRunning = true;
let leftPressed = false;
let rightPressed = false;
// UI elements
const distanceElement = document.getElementById('distance');
const fuelElement = document.getElementById('fuel');
const gameOverElement = document.getElementById('game-over');
const finalScoreElement = document.getElementById('final-score');
const restartBtn = document.getElementById('restart-btn');
const leftBtn = document.getElementById('left-btn');
const rightBtn = document.getElementById('right-btn');
// Initialize game
function initGame() {
playerX = 100;
playerY = canvas.height * 0.75;
velocityX = 0;
velocityY = 0;
score = 0;
fuel = 100;
gameRunning = true;
generateTerrain();
gameOverElement.style.display = 'none';
// Start game loop
requestAnimationFrame(gameLoop);
}
// Generate terrain
function generateTerrain() {
terrain = [];
let y = canvas.height * 0.75; // Starting height
for(let x = 0; x < canvas.width * 2; x += 10) {
y += Math.random() * 20 - 10; // Random height changes
terrain.push({x, y});
}
}
// Get terrain height at x position
function getTerrainY(x) {
x = Math.max(0, Math.min(x, canvas.width * 2 - 10));
const index = Math.floor(x / 10);
const segment = x % 10 / 10;
if (index >= terrain.length - 1) {
return terrain[terrain.length - 1].y;
}
// Linear interpolation between terrain points
return terrain[index].y + (terrain[index + 1].y - terrain[index].y) * segment;
}
// Draw terrain
function drawTerrain() {
ctx.fillStyle = '#7CFC00';
ctx.beginPath();
ctx.moveTo(0, canvas.height);
for(let i = 0; i < terrain.length; i++) {
ctx.lineTo(terrain[i].x, terrain[i].y);
}
ctx.lineTo(canvas.width * 2, canvas.height);
ctx.closePath();
ctx.fill();
// Add some dirt/ground texture
ctx.strokeStyle = '#8B4513';
ctx.lineWidth = 2;
ctx.beginPath();
for(let i = 0; i < terrain.length; i++) {
if (i === 0) {
ctx.moveTo(terrain[i].x, terrain[i].y);
} else {
ctx.lineTo(terrain[i].x, terrain[i].y);
}
}
ctx.stroke();
}
// Draw player vehicle
function drawPlayer() {
// Car body
ctx.fillStyle = '#FF0000';
ctx.fillRect(playerX - 20, playerY - 15, 40, 10);
ctx.fillRect(playerX - 15, playerY - 25, 30, 10);
// Windows
ctx.fillStyle = '#ADD8E6';
ctx.fillRect(playerX - 10, playerY - 20, 20, 5);
// Wheels
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.arc(playerX - 15, playerY, 5, 0, Math.PI * 2);
ctx.arc(playerX + 15, playerY, 5, 0, Math.PI * 2);
ctx.fill();
}
// Update physics
function updatePhysics() {
// Handle controls
if (leftPressed && fuel > 0) {
velocityX -= 0.5;
}
if (rightPressed && fuel > 0) {
velocityX += 0.5;
}
// Gravity
velocityY += 0.2;
// Apply velocity
playerX += velocityX;
playerY += velocityY;
// Check terrain collision
let terrainY = getTerrainY(playerX);
if(playerY > terrainY - 10) {
playerY = terrainY - 10;
velocityY = 0;
}
// Fuel consumption
if((leftPressed || rightPressed) && Math.abs(velocityX) > 0) {
fuel -= 0.05;
fuel = Math.max(0, fuel);
}
// Friction
velocityX *= 0.98;
// Camera follow (move terrain when player reaches middle of screen)
if(playerX > canvas.width / 2) {
const diff = playerX - canvas.width / 2;
playerX = canvas.width / 2;
// Shift terrain left
for(let i = 0; i < terrain.length; i++) {
terrain[i].x -= diff;
}
// Generate new terrain segments on the right
while(terrain[terrain.length - 1].x < canvas.width * 2) {
const last = terrain[terrain.length - 1];
const newX = last.x + 10;
const newY = last.y + Math.random() * 20 - 10;
terrain.push({x: newX, y: newY});
}
// Remove segments that are off-screen left
while(terrain.length > 0 && terrain[0].x < 0) {
terrain.shift();
}
// Add to score based on distance moved
score += diff;
}
}
// Draw UI
function drawUI() {
distanceElement.textContent = Math.floor(score);
fuelElement.textContent = Math.floor(fuel);
// Fuel warning
if(fuel < 30) {
fuelElement.style.color = fuel < 15 ? '#FF0000' : '#FFA500';
} else {
fuelElement.style.color = 'white';
}
}
// Game over
function gameOver() {
gameRunning = false;
finalScoreElement.textContent = Math.floor(score);
gameOverElement.style.display = 'flex';
}
// Game loop
function gameLoop() {
if(!gameRunning) return;
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Update game state
updatePhysics();
// Draw terrain
drawTerrain();
// Draw player
drawPlayer();
// Draw UI
drawUI();
// Check game over conditions
if(fuel <= 0 || playerY > canvas.height) {
gameOver();
return;
}
requestAnimationFrame(gameLoop);
}
// Keyboard controls
document.addEventListener('keydown', (e) => {
if(!gameRunning) return;
if(e.key === 'ArrowRight') {
rightPressed = true;
}
if(e.key === 'ArrowLeft') {
leftPressed = true;
}
});
document.addEventListener('keyup', (e) => {
if(e.key === 'ArrowRight') {
rightPressed = false;
}
if(e.key === 'ArrowLeft') {
leftPressed = false;
}
});
// Touch controls
leftBtn.addEventListener('touchstart', (e) => {
e.preventDefault();
leftPressed = true;
});
leftBtn.addEventListener('touchend', (e) => {
e.preventDefault();
leftPressed = false;
});
leftBtn.addEventListener('mousedown', () => {
leftPressed = true;
});
leftBtn.addEventListener('mouseup', () => {
leftPressed = false;
});
leftBtn.addEventListener('mouseleave', () => {
leftPressed = false;
});
rightBtn.addEventListener('touchstart', (e) => {
e.preventDefault();
rightPressed = true;
});
rightBtn.addEventListener('touchend', (e) => {
e.preventDefault();
rightPressed = false;
});
rightBtn.addEventListener('mousedown', () => {
rightPressed = true;
});
rightBtn.addEventListener('mouseup', () => {
rightPressed = false;
});
rightBtn.addEventListener('mouseleave', () => {
rightPressed = false;
});
restartBtn.addEventListener('click', initGame);
// Start the game
initGame();
</script>
</body>
</html>
Comments
Post a Comment