天天酷跑
by ShadowCoder44522 lines17.9 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>天天酷跑</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #2c3e50;
font-family: "Microsoft Yahei", sans-serif;
}
#gameCanvas {
border: 3px solid #fff;
border-radius: 8px;
background: linear-gradient(#74b9ff 0%, #a29bfe 60%, #fdcb6e 100%);
cursor: pointer;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="480" height="700"></canvas>
<!-- 欢快风格背景音乐 -->
<audio id="bgm" loop preload="auto">
<source src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3" type="audio/mpeg">
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const bgm = document.getElementById('bgm');
const W = canvas.width;
const H = canvas.height;
// 游戏状态
let gameState = 'start';
let score = 0;
let coinCount = 0;
let gameSpeed = 1.5;
const maxGameSpeed = 2.8;
let frameCount = 0;
let nextObstacleFrame = 0;
// 地面参数
const groundHeight = 100;
const groundY = H - groundHeight;
let groundOffset = 0;
// 玩家对象
const player = {
x: 80,
y: groundY - 80,
width: 50,
height: 80,
velocityY: 0,
gravity: 0.25,
jumpPower: -8,
jumpCount: 0,
maxJump: 2,
landSmoothRange: 12,
// 飞行属性 - 延长至8秒
isFlying: false,
flyDuration: 480, // 8秒(60帧/秒)
flyTimer: 0,
flyTargetY: groundY - 180,
// 护盾属性 - 延长至10秒
hasShield: false,
shieldDuration: 600, // 10秒
shieldTimer: 0
};
// 实体数组
let obstacles = [];
let coins = [];
let powerups = [];
// 初始化游戏
function initGame() {
score = 0;
coinCount = 0;
gameSpeed = 1.5;
frameCount = 0;
nextObstacleFrame = 180;
obstacles = [];
coins = [];
powerups = [];
player.y = groundY - player.height;
player.velocityY = 0;
player.jumpCount = 0;
player.isFlying = false;
player.flyTimer = 0;
player.hasShield = false;
player.shieldTimer = 0;
}
// 跳跃
function jump() {
if (gameState === 'start') {
gameState = 'playing';
initGame();
bgm.play().catch(() => {});
return;
}
if (gameState === 'over') {
gameState = 'start';
bgm.pause();
bgm.currentTime = 0;
return;
}
if (!player.isFlying && player.jumpCount < player.maxJump) {
player.velocityY = player.jumpPower;
player.jumpCount++;
}
}
// 生成随机障碍物
function spawnObstacle() {
const width = 35 + Math.random() * 15;
const height = 45 + Math.random() * 25;
obstacles.push({
x: W,
y: groundY - height,
width: width,
height: height,
type: 'ground'
});
const minInterval = 230;
const maxInterval = 370;
const randomInterval = minInterval + Math.random() * (maxInterval - minInterval);
nextObstacleFrame = frameCount + Math.floor(randomInterval);
}
// 生成金币
function spawnCoin() {
const y = groundY - 120 - Math.random() * 100;
coins.push({
x: W,
y: y,
radius: 15
});
}
// 生成随机道具
function spawnPowerup() {
const types = ['fly', 'shield'];
const type = types[Math.floor(Math.random() * types.length)];
const y = groundY - 130 - Math.random() * 80;
powerups.push({
x: W,
y: y,
radius: 18,
type: type
});
}
// 碰撞检测
function checkCollision(rect1, rect2) {
return rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y;
}
// 更新游戏逻辑
function update() {
if (gameState !== 'playing') return;
frameCount++;
score += 1;
if (frameCount % 1500 === 0 && gameSpeed < maxGameSpeed) {
gameSpeed += 0.1;
}
groundOffset -= gameSpeed;
if (groundOffset <= -W) {
groundOffset = 0;
}
// 飞行状态处理
if (player.isFlying) {
player.flyTimer--;
if (player.flyTimer <= 0) {
player.isFlying = false;
player.velocityY = 0;
} else {
player.velocityY = 0;
player.y += (player.flyTargetY - player.y) * 0.05;
}
}
// 护盾状态处理
if (player.hasShield) {
player.shieldTimer--;
if (player.shieldTimer <= 0) {
player.hasShield = false;
}
}
// 玩家物理
if (!player.isFlying) {
player.velocityY += player.gravity;
}
player.y += player.velocityY;
// 落地滑行缓冲
if (!player.isFlying) {
const distanceToGround = groundY - (player.y + player.height);
if (distanceToGround < player.landSmoothRange && distanceToGround > 0 && player.velocityY > 0) {
player.velocityY *= 0.65;
}
if (player.y + player.height >= groundY) {
player.y = groundY - player.height;
player.velocityY = 0;
player.jumpCount = 0;
}
}
// 生成障碍物
if (frameCount >= nextObstacleFrame) {
spawnObstacle();
}
// 生成金币
if (frameCount % 160 === 0) {
spawnCoin();
}
// 生成道具
if (frameCount % 350 === 0 && Math.random() > 0.3) {
spawnPowerup();
}
// 更新障碍物
for (let i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].x -= gameSpeed;
if (obstacles[i].x + obstacles[i].width < 0) {
obstacles.splice(i, 1);
continue;
}
const playerRect = {
x: player.x + 10,
y: player.y + 10,
width: player.width - 20,
height: player.height - 20
};
if (checkCollision(playerRect, obstacles[i])) {
if (!player.hasShield && !player.isFlying) {
gameState = 'over';
bgm.pause();
}
}
}
// 更新金币
for (let i = coins.length - 1; i >= 0; i--) {
coins[i].x -= gameSpeed;
if (coins[i].x + coins[i].radius < 0) {
coins.splice(i, 1);
continue;
}
const playerRect = {
x: player.x,
y: player.y,
width: player.width,
height: player.height
};
const coinRect = {
x: coins[i].x - coins[i].radius,
y: coins[i].y - coins[i].radius,
width: coins[i].radius * 2,
height: coins[i].radius * 2
};
if (checkCollision(playerRect, coinRect)) {
coinCount++;
score += 100;
coins.splice(i, 1);
}
}
// 更新道具
for (let i = powerups.length - 1; i >= 0; i--) {
powerups[i].x -= gameSpeed;
if (powerups[i].x + powerups[i].radius < 0) {
powerups.splice(i, 1);
continue;
}
const playerRect = {
x: player.x,
y: player.y,
width: player.width,
height: player.height
};
const powerupRect = {
x: powerups[i].x - powerups[i].radius,
y: powerups[i].y - powerups[i].radius,
width: powerups[i].radius * 2,
height: powerups[i].radius * 2
};
if (checkCollision(playerRect, powerupRect)) {
if (powerups[i].type === 'fly') {
player.isFlying = true;
player.flyTimer = player.flyDuration;
} else if (powerups[i].type === 'shield') {
player.hasShield = true;
player.shieldTimer = player.shieldDuration;
}
powerups.splice(i, 1);
}
}
}
// 绘制画面
function render() {
ctx.clearRect(0, 0, W, H);
// 云朵
ctx.fillStyle = 'rgba(255,255,255,0.8)';
drawCloud(100 - (frameCount * 0.15) % 600, 80);
drawCloud(350 - (frameCount * 0.1) % 600, 150);
// 地面
ctx.fillStyle = '#8B4513';
ctx.fillRect(0, groundY, W, groundHeight);
ctx.fillStyle = '#654321';
for (let i = 0; i < 3; i++) {
ctx.fillRect(groundOffset + i * W, groundY + 20, W, 5);
ctx.fillRect(groundOffset + i * W, groundY + 50, W, 5);
}
ctx.fillStyle = '#27ae60';
ctx.fillRect(0, groundY, W, 15);
// 障碍物
obstacles.forEach(obs => {
ctx.fillStyle = '#2c3e50';
ctx.fillRect(obs.x, obs.y, obs.width, obs.height);
ctx.fillStyle = '#34495e';
const spikeCount = Math.floor(obs.width / 20);
for (let i = 0; i < spikeCount; i++) {
ctx.beginPath();
ctx.moveTo(obs.x + i*20, obs.y);
ctx.lineTo(obs.x + i*20 + 10, obs.y - 12);
ctx.lineTo(obs.x + i*20 + 20, obs.y);
ctx.fill();
}
});
// 金币
coins.forEach(coin => {
ctx.fillStyle = '#f1c40f';
ctx.beginPath();
ctx.arc(coin.x, coin.y, coin.radius, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#f39c12';
ctx.font = 'bold 16px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('$', coin.x, coin.y);
});
// 道具
powerups.forEach(p => {
if (p.type === 'fly') {
ctx.fillStyle = '#0984e3';
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#fff';
ctx.font = 'bold 14px Microsoft Yahei';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('飞行', p.x, p.y);
} else {
ctx.fillStyle = '#00b894';
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#fff';
ctx.font = 'bold 14px Microsoft Yahei';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('护盾', p.x, p.y);
}
});
// 玩家
ctx.fillStyle = '#e74c3c';
ctx.fillRect(player.x, player.y, player.width, player.height);
ctx.fillStyle = '#f39c12';
ctx.beginPath();
ctx.arc(player.x + player.width/2, player.y + 15, 18, 0, Math.PI * 2);
ctx.fill();
// 护盾特效
if (player.hasShield) {
const pulse = Math.sin(frameCount * 0.1) * 3;
ctx.strokeStyle = 'rgba(0, 184, 148, 0.7)';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.ellipse(
player.x + player.width/2,
player.y + player.height/2,
player.width/2 + 8 + pulse,
player.height/2 + 8 + pulse,
0, 0, Math.PI * 2
);
ctx.stroke();
}
// 飞行翅膀特效
if (player.isFlying) {
const flap = Math.sin(frameCount * 0.3) * 5;
ctx.fillStyle = 'rgba(255, 255, 255, 0.85)';
ctx.beginPath();
ctx.moveTo(player.x, player.y + player.height/2);
ctx.lineTo(player.x - 28 - flap, player.y + 8);
ctx.lineTo(player.x - 22 - flap, player.y + player.height - 8);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(player.x + player.width, player.y + player.height/2);
ctx.lineTo(player.x + player.width + 28 + flap, player.y + 8);
ctx.lineTo(player.x + player.width + 22 + flap, player.y + player.height - 8);
ctx.closePath();
ctx.fill();
}
// 分数与状态
ctx.fillStyle = '#fff';
ctx.font = 'bold 24px Microsoft Yahei';
ctx.textAlign = 'left';
ctx.shadowColor = '#000';
ctx.shadowBlur = 4;
ctx.fillText(`分数: ${score}`, 20, 40);
ctx.fillText(`金币: ${coinCount}`, 20, 75);
if (player.isFlying) {
ctx.fillStyle = '#74b9ff';
ctx.fillText(`飞行: ${Math.ceil(player.flyTimer / 60)}s`, 20, 110);
}
if (player.hasShield) {
ctx.fillStyle = '#55efc4';
ctx.fillText(`护盾: ${Math.ceil(player.shieldTimer / 60)}s`, 20, 145);
}
ctx.shadowBlur = 0;
// 开始界面
if (gameState === 'start') {
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(0, 0, W, H);
ctx.fillStyle = '#fff';
ctx.font = 'bold 40px Microsoft Yahei';
ctx.textAlign = 'center';
ctx.fillText('天天酷跑', W/2, H/2 - 80);
ctx.font = '20px Microsoft Yahei';
ctx.fillText('空格/↑键/点击屏幕 跳跃(可二段跳)', W/2, H/2 - 30);
ctx.fillText('收集飞行道具可腾空8秒', W/2, H/2 + 5);
ctx.fillText('收集护盾道具可10秒无敌', W/2, H/2 + 40);
ctx.fillText('点击屏幕开始游戏', W/2, H/2 + 90);
}
// 结束界面
if (gameState === 'over') {
ctx.fillStyle = 'rgba(0,0,0,0.7)';
ctx.fillRect(0, 0, W, H);
ctx.fillStyle = '#e74c3c';
ctx.font = 'bold 44px Microsoft Yahei';
ctx.textAlign = 'center';
ctx.fillText('游戏结束', W/2, H/2 - 80);
ctx.fillStyle = '#fff';
ctx.font = '24px Microsoft Yahei';
ctx.fillText(`最终得分: ${score}`, W/2, H/2 - 20);
ctx.fillText(`收集金币: ${coinCount}`, W/2, H/2 + 20);
ctx.fillStyle = '#2ecc71';
ctx.fillText('点击重新开始', W/2, H/2 + 90);
}
}
// 画云朵
function drawCloud(x, y) {
ctx.beginPath();
ctx.arc(x, y, 25, 0, Math.PI * 2);
ctx.arc(x + 25, y - 10, 30, 0, Math.PI * 2);
ctx.arc(x + 55, y, 25, 0, Math.PI * 2);
ctx.fill();
}
// 游戏主循环
function gameLoop() {
update();
render();
requestAnimationFrame(gameLoop);
}
// 操作事件
canvas.addEventListener('click', jump);
document.addEventListener('keydown', (e) => {
if (e.code === 'Space' || e.code === 'ArrowUp') {
e.preventDefault();
jump();
}
});
gameLoop();
</script>
</body>
</html>Game Source: 天天酷跑
Creator: ShadowCoder44
Libraries: none
Complexity: complex (522 lines, 17.9 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: game-shadowcoder44" to link back to the original. Then publish at arcadelab.ai/publish.