Meta Description" name="description" />
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Mobile Surfer</title>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #333;
font-family: Arial, sans-serif;
touch-action: none; /* Prevents zooming/scrolling on tap */
}
canvas {
display: block;
margin: 0 auto;
background: #444;
}
#ui {
position: absolute;
top: 20px;
left: 0;
width: 100%;
text-align: center;
color: white;
font-size: 24px;
pointer-events: none;
text-shadow: 2px 2px 2px #000;
}
#gameOver {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 10px;
text-align: center;
color: white;
}
button {
background: #00ff88;
border: none;
padding: 15px 30px;
font-size: 20px;
border-radius: 5px;
margin-top: 10px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="ui">Score: <span id="scoreVal">0</span></div>
<canvas id="gameCanvas"></canvas>
<div id="gameOver">
<h1>π₯ CRASH!</h1>
<p>Final Score: <span id="finalScore">0</span></p>
<button onclick="resetGame()">Try Again</button>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('scoreVal');
const finalScoreEl = document.getElementById('finalScore');
const gameOverScreen = document.getElementById('gameOver');
// Game State
let gameRunning = true;
let score = 0;
let speed = 5;
let laneWidth;
// Player
let player = {
lane: 1, // 0: Left, 1: Middle, 2: Right
y: 0,
width: 50,
height: 50,
color: '#00ff88'
};
// Obstacles
let obstacles = [];
let frameCount = 0;
// Resize canvas to full mobile screen
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
laneWidth = canvas.width / 3;
player.y = canvas.height - 150;
player.width = laneWidth * 0.5;
}
window.addEventListener('resize', resize);
resize();
// Controls (Touch)
window.addEventListener('touchstart', (e) => {
if (!gameRunning) return;
const touchX = e.touches[0].clientX;
const screenMiddle = canvas.width / 2;
if (touchX < screenMiddle) {
// Tap Left
if (player.lane > 0) player.lane--;
} else {
// Tap Right
if (player.lane < 2) player.lane++;
}
});
// Game Loop
function update() {
if (!gameRunning) return;
// Spawn Obstacles
frameCount++;
if (frameCount % 60 === 0) { // Approx every 1 second
let obsLane = Math.floor(Math.random() * 3);
obstacles.push({
lane: obsLane,
y: -100,
width: laneWidth * 0.5,
height: 50
});
// Increase speed slightly
if (score % 5 === 0) speed += 0.2;
}
// Move Obstacles
for (let i = obstacles.length - 1; i >= 0; i--) {
let obs = obstacles[i];
obs.y += speed;
// Collision Detection
// Player Y is fixed, Obs Y moves down
// Simple box collision
let playerX = (player.lane * laneWidth) + (laneWidth / 2) - (player.width / 2);
let obsX = (obs.lane * laneWidth) + (laneWidth / 2) - (obs.width / 2);
if (
player.lane === obs.lane &&
obs.y + obs.height > player.y &&
obs.y < player.y + player.height
) {
endGame();
}
// Remove if off screen
if (obs.y > canvas.height) {
obstacles.splice(i, 1);
score++;
scoreEl.innerText = score;
}
}
draw();
requestAnimationFrame(update);
}
function draw() {
// Clear Screen
ctx.fillStyle = '#444';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw Lanes
ctx.strokeStyle = '#666';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(laneWidth, 0);
ctx.lineTo(laneWidth, canvas.height);
ctx.moveTo(laneWidth * 2, 0);
ctx.lineTo(laneWidth * 2, canvas.height);
ctx.stroke();
// Draw Player
let pX = (player.lane * laneWidth) + (laneWidth / 2) - (player.width / 2);
ctx.fillStyle = player.color;
// Draw a simple surfboard shape (ellipse-ish) or rectangle
ctx.fillRect(pX, player.y, player.width, player.height);
// Draw Player Eyes (Cute factor)
ctx.fillStyle = 'black';
ctx.fillRect(pX + 10, player.y + 10, 5, 5);
ctx.fillRect(pX + player.width - 15, player.y + 10, 5, 5);
// Draw Obstacles
ctx.fillStyle = '#ff4444';
obstacles.forEach(obs => {
let oX = (obs.lane * laneWidth) + (laneWidth / 2) - (obs.width / 2);
ctx.fillRect(oX, obs.y, obs.width, obs.height);
// Warning stripes
ctx.fillStyle = 'yellow';
ctx.fillRect(oX + 5, obs.y + 10, obs.width - 10, 10);
ctx.fillStyle = '#ff4444';
});
}
function endGame() {
gameRunning = false;
finalScoreEl.innerText = score;
gameOverScreen.style.display = 'block';
}
function resetGame() {
obstacles = [];
score = 0;
speed = 5;
player.lane = 1;
scoreEl.innerText = '0';
gameOverScreen.style.display = 'none';
gameRunning = true;
frameCount = 0;
update();
}
// Start
update();
</script>
</body>
</html>
1
1
7KB
7KB
150.0ms
192.0ms
150.0ms