像素跑酷 手机修复完整版
by SparkPilot94396 lines11.2 KB
帮我生成图片:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>像素跑酷 手机修复完整版</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #1a1a2e;
color: #fff;
font-family: "Courier New", monospace;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 10px;
overflow: hidden;
}
#gameContainer {
position: relative;
width: 100%;
max-width: 900px;
aspect-ratio: 16 / 9;
border: 3px solid #fff;
box-shadow: 0 0 20px rgba(255,255,255,0.2);
background: #87ceeb;
overflow: hidden;
}
canvas {
display: block;
width: 100%;
height: 100%;
image-rendering: pixelated;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-between;
font-size: 18px;
font-weight: bold;
text-shadow: 2px 2px 0 #000;
pointer-events: none;
}
#ui span {
background: rgba(0,0,0,0.4);
padding: 4px 12px;
border-radius: 4px;
}
#overlay {
position: absolute;
inset: 0;
background: rgba(0,0,0,0.75);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 20px;
z-index: 10;
}
#overlay h1 {
font-size: 36px;
margin-bottom: 10px;
color: #ffd700;
text-shadow: 3px 3px 0 #000;
}
#overlay p {
font-size: 16px;
margin-bottom: 20px;
line-height: 1.6;
}
#overlay .btn {
background: #ff6b35;
color: #fff;
border: none;
padding: 12px 32px;
font-size: 20px;
font-weight: bold;
font-family: inherit;
cursor: pointer;
border-radius: 6px;
box-shadow: 0 4px 0 #c94f24;
margin: 6px;
}
#overlay .btn.green {
background: #4caf50;
box-shadow: 0 4px 0 #388e3c;
}
.hidden { display: none !important; }
#tipText{margin-top:10px;color:#aaa;font-size:14px}
</style>
</head>
<body>
<div id="gameContainer">
<canvas id="game" width="900" height="506"></canvas>
<div id="ui">
<span id="level">第 1 关:草原</span>
<span id="score">分数:0</span>
<span id="coins">0</span>
</div>
<div id="overlay">
<h1>像素跑酷</h1>
<p>手机点击屏幕跳跃<br>避开障碍收集金币冲到终点</p>
<button class="btn green" id="startBtn">开始游戏</button>
</div>
</div>
<div id="tipText">手机:点击画布任意位置跳跃</div>
<script>
(() => {
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const uiLevel = document.getElementById('level');
const uiScore = document.getElementById('score');
const uiCoins = document.getElementById('coins');
const overlay = document.getElementById('overlay');
const startBtn = document.getElementById('startBtn');
const GRAVITY = 0.7;
const JUMP = -13;
const GROUND_Y = 380;
const PLAYER_SCREEN_X = 120;
const LEVELS = [
{ name: '草原', bg1: '#87ceeb', bg2: '#4a90e2', ground: '#6b8e23', ground2: '#556b2f', obstacles: ['rock', 'stump'], coins: 8, length: 1800 },
{ name: '沙漠', bg1: '#ffd27f', bg2: '#f4a460', ground: '#deb887', ground2: '#d2b48c', obstacles: ['cactus', 'pit'], coins: 10, length: 2000 },
{ name: '森林', bg1: '#7ec8e3', bg2: '#3a6b35', ground: '#5a3a1b', ground2: '#3d2817', obstacles: ['log', 'vine'], coins: 12, length: 2200 },
{ name: '雪地', bg1: '#bde0fe', bg2: '#a2d2ff', ground: '#f0f8ff', ground2: '#d6eaf8', obstacles: ['ice', 'snowball'], coins: 12, length: 2400 },
{ name: '城市', bg1: '#ffb3ba', bg2: '#89cff0', ground: '#555', ground2: '#333', obstacles: ['barrier', 'roof'], coins: 15, length: 2800 }
];
let gameState = 'menu';
let currentLevel = 0;
let score = 0;
let coins = 0;
let worldOffset = 0;
let levelLength = 0;
let obstacles = [];
let coinItems = [];
let spawnTimer = 0;
let coinSpawnTimer = 0;
let gameSpeed = 5;
const player = {
screenX: PLAYER_SCREEN_X,
y: GROUND_Y,
w: 32,
h: 40,
vy: 0,
onGround: true,
runFrame: 0,
runTimer: 0
};
function resetPlayer() {
player.y = GROUND_Y;
player.vy = 0;
player.onGround = true;
}
function startLevel(index) {
currentLevel = index;
const level = LEVELS[index];
levelLength = level.length;
worldOffset = 0;
obstacles = [];
coinItems = [];
spawnTimer = 0;
coinSpawnTimer = 0;
gameSpeed = 5 + index * 0.5;
resetPlayer();
gameState = 'playing';
uiLevel.textContent = `第 ${index + 1} 关:${level.name}`;
overlay.classList.add('hidden');
}
function startGame() {
score = 0;
coins = 0;
updateUI();
startLevel(0);
}
function updateUI() {
uiScore.textContent = `分数:${score}`;
uiCoins.textContent = `${coins}`;
}
function jump() {
if (player.onGround && gameState === 'playing') {
player.vy = JUMP;
player.onGround = false;
}
}
function spawnObstacle() {
const level = LEVELS[currentLevel];
const type = level.obstacles[Math.floor(Math.random() * level.obstacles.length)];
let obstacle = {
worldX: worldOffset + 950,
y: GROUND_Y,
type: type,
passed: false
};
if (type === 'rock') { obstacle.w = 36; obstacle.h = 32; obstacle.y = GROUND_Y - 32; }
else if (type === 'stump') { obstacle.w = 32; obstacle.h = 28; obstacle.y = GROUND_Y - 28; }
else if (type === 'cactus') { obstacle.w = 28; obstacle.h = 44; obstacle.y = GROUND_Y - 44; }
else if (type === 'pit') { obstacle.w = 60; obstacle.h = 20; obstacle.y = GROUND_Y - 10; }
else if (type === 'log') { obstacle.w = 42; obstacle.h = 26; obstacle.y = GROUND_Y - 26; }
else if (type === 'vine') { obstacle.w = 22; obstacle.h = 46; obstacle.y = GROUND_Y - 46; }
else if (type === 'ice') { obstacle.w = 38; obstacle.h = 22; obstacle.y = GROUND_Y - 22; }
else if (type === 'snowball') { obstacle.w = 34; obstacle.h = 34; obstacle.y = GROUND_Y - 34; }
else if (type === 'barrier') { obstacle.w = 26; obstacle.h = 38; obstacle.y = GROUND_Y - 38; }
else if (type === 'roof') { obstacle.w = 48; obstacle.h = 20; obstacle.y = GROUND_Y - 20; }
obstacles.push(obstacle);
}
function spawnCoin() {
const wx = worldOffset + 950 + Math.random() * 200;
const wy = GROUND_Y - 60 - Math.random() * 80;
coinItems.push({ worldX: wx, y: wy, w: 20, h: 20, collected: false, frame: 0 });
}
function worldToScreen(worldX) {
return worldX - worldOffset;
}
function rectIntersectScreen(ax,ay,aw,ah,bx,by,bw,bh) {
return ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by;
}
function update() {
if (gameState !== 'playing') return;
worldOffset += gameSpeed;
player.vy += GRAVITY;
player.y += player.vy;
if (player.y >= GROUND_Y) {
player.y = GROUND_Y;
player.vy = 0;
player.onGround = true;
}
player.runTimer++;
if(player.runTimer>6){
player.runTimer=0;
player.runFrame=(player.runFrame+1)%4;
}
spawnTimer += gameSpeed;
if(spawnTimer>220-currentLevel*15){
spawnObstacle();
spawnTimer=0;
}
coinSpawnTimer += gameSpeed;
if(coinSpawnTimer>150){
spawnCoin();
coinSpawnTimer=0;
}
obstacles = obstacles.filter(o => worldToScreen(o.worldX) > -120);
coinItems = coinItems.filter(c => worldToScreen(c.worldX) > -120 && !c.collected);
for(let o of obstacles){
const sx = worldToScreen(o.worldX);
if(rectIntersectScreen(player.screenX, player.y, player.w, player.h, sx, o.y, o.w, o.h)){
gameOver();
return;
}
if(!o.passed && sx+o.w < player.screenX){
o.passed=true;
score+=10;
updateUI();
}
}
for(let c of coinItems){
const sx = worldToScreen(c.worldX);
c.frame++;
if(!c.collected && rectIntersectScreen(player.screenX, player.y, player.w, player.h, sx, c.y, c.w, c.h)){
c.collected=true;
coins++;
score+=20;
updateUI();
}
}
if(worldOffset >= levelLength){
if(currentLevel < LEVELS.length-1){
showOverlay(`第${currentLevel+1}关完成`,`准备进入第${currentLevel+2}关:${LEVELS[currentLevel+1].name}`,"下一关",()=>startLevel(currentLevel+1));
}else{
showOverlay("全部通关!",`总分${score}|金币${coins}`,"再来一局",startGame);
}
gameState="levelComplete";
}
}
function gameOver(){
gameState="gameOver";
showOverlay("游戏结束",`第${currentLevel+1}关|分数${score}`,"重新开始",startGame);
}
function showOverlay(title,txt,btnText,onClick){
overlay.innerHTML=`<h1>${title}</h1><p>${txt}</p><button class="btn green" id="obtn">${btnText}</button>`;
overlay.classList.remove("hidden");
document.getElementById("obtn").onclick=onClick;
}
function draw(){
if(gameState==="menu") return;
const level = LEVELS[currentLevel];
const grad = ctx.createLinearGradient(0,0,0,GROUND_Y);
grad.addColorStop(0,level.bg1);
grad.addColorStop(1,level.bg2);
ctx.fillStyle=grad;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle="rgba(255,255,255,0.6)";
for(let i=0;i<3;i++){
const cx = ((i*320 - worldOffset*0.2) % 1200 +1200)%1200 -100;
ctx.fillRect(cx,60+i*20,60,16);
ctx.fillRect(cx+10,60+i*20-10,40,14);
}
ctx.fillStyle=level.ground2;
ctx.fillRect(0,GROUND_Y,canvas.width,canvas.height-GROUND_Y);
ctx.fillStyle=level.ground;
ctx.fillRect(0,GROUND_Y,canvas.width,8);
for(let o of obstacles){
const sx = worldToScreen(o.worldX);
ctx.fillStyle="#777";
ctx.fillRect(sx,o.y,o.w,o.h);
}
for(let c of coinItems){
if(c.collected) continue;
const sx = worldToScreen(c.worldX);
const bounce = Math.sin(c.frame*0.15)*2;
ctx.fillStyle="#ffd700";
ctx.fillRect(sx+2,c.y+bounce,16,16);
}
if(worldOffset >= levelLength-100 && worldOffset < levelLength){
const finishScreenX = worldToScreen(levelLength);
ctx.fillStyle="rgba(255,215,0,0.8)";
ctx.fillRect(finishScreenX,GROUND_Y-80,6,80);
}
const px = player.screenX;
const py = player.y;
ctx.fillStyle='#4285f4';
ctx.fillRect(px+8,py+12,16,20);
ctx.fillStyle='#ffd9a8';
ctx.fillRect(px+10,py+2,12,12);
ctx.fillStyle='#ff6b35';
ctx.fillRect(px+8,py,16,6);
ctx.fillRect(px+4,py+4,6,4);
ctx.fillStyle='#000';
ctx.fillRect(px+18,py+6,2,2);
const legOff = player.onGround ? (player.runFrame%2===0?0:4):0;
ctx.fillStyle="#333";
ctx.fillRect(px+10,py+32,5,8-legOff);
ctx.fillRect(px+17,py+32,5,8+legOff);
}
function loop(){
update();
draw();
requestAnimationFrame(loop);
}
startBtn.addEventListener("click",startGame);
canvas.addEventListener("touchstart",e=>{
e.preventDefault();
jump();
});
canvas.addEventListener("mousedown",jump);
window.addEventListener("keydown",e=>{
if(e.code==="Space"||e.code==="ArrowUp"){
e.preventDefault();
jump();
}
});
loop();
})();
</script>
</body>
</html>Game Source: 像素跑酷 手机修复完整版
Creator: SparkPilot94
Libraries: none
Complexity: complex (396 lines, 11.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: game-sparkpilot94" to link back to the original. Then publish at arcadelab.ai/publish.