🎮ArcadeLab

溶洞像素跳跃

by MysticMaker96
228 lines5.1 KB
▶ Play
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>溶洞像素跳跃</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#181412;color:#fff;font-family:monospace;overflow:hidden}
canvas{display:block;margin:0 auto;background:#2c2420;image-rendering:pixelated;}
.info{position:absolute;top:8px;left:12px;font-size:18px;text-shadow:1px 1px #000}
</style>
</head>
<body>
<div class="info">
💰金币:<span id="coinCount">0</span> &nbsp;&nbsp; ⭐分数:<span id="score">0</span>
</div>
<canvas id="game" width="480" height="320"></canvas>

<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const coinDom = document.getElementById('coinCount');
const scoreDom = document.getElementById('score');

function drawPixel(x,y,w,h,color){
    ctx.fillStyle = color;
    ctx.fillRect(Math.floor(x),Math.floor(y),w,h);
}

// 玩家:紫色像素小人
const player = {
    x: 60,
    y: 200,
    w: 12,
    h: 18,
    vx: 2.6,         // 固定向右跑步速度
    vy: 0,
    jumpPower: -13,
    gravity: 0.48,
    onGround: false,
    pixelSize: 3,
    runPhase: 0,     // 跑步相位
    flip: 1,
    coinNum: 0,
    score: 0
};

const groundY = 260;
let spikes = [];
let coins = [];

// 尖刺:棕色溶洞石柱
function spawnSpike(){
    const h = 28 + Math.random() * 22;
    spikes.push({
        x: canvas.width,
        y: groundY - h,
        w: 14,
        h: h,
        scored: false
    });
}

// 普通金币
function spawnCoin(){
    coins.push({
        x: canvas.width,
        y: groundY - 36 - Math.random()*55,
        r: 5,
        collected: false
    });
}

// 大片金币区域
function spawnCoinWave(){
    const count = 5 + Math.floor(Math.random()*4);
    const startY = groundY - 40 - Math.random()*40;
    for(let i=0;i<count;i++){
        coins.push({
            x: canvas.width + i*22,
            y: startY + Math.sin(i*0.6)*10,
            r: 5,
            collected: false
        });
    }
}

// 点击画布任意位置跳跃
canvas.addEventListener('click', ()=>{
    if(player.onGround){
        player.vy = player.jumpPower;
        player.onGround = false;
    }
});

canvas.addEventListener('touchstart',e=>{
    e.preventDefault();
    if(player.onGround){
        player.vy = player.jumpPower;
        player.onGround = false;
    }
});

let spawnTimer = 0;
const spawnRate = 110;
const moveSpeed = 3;
let coinWaveTimer = 0;
const coinWaveRate = 320;

function resetGame(){
    player.x = 60;
    player.y = 200;
    player.vy = 0;
    player.onGround = false;
    player.coinNum = 0;
    player.score = 0;
    player.runPhase = 0;
    spikes = [];
    coins = [];
    spawnTimer = 0;
    coinWaveTimer = 0;
    updateUI();
}

function updateUI(){
    coinDom.textContent = player.coinNum;
    scoreDom.textContent = Math.floor(player.score);
}

function rectOverlap(a,b){
    return a.x < b.x + b.w && a.x+a.w > b.x && a.y < b.y + b.h && a.y+a.h > b.y;
}

function circleRect(c, r, rect){
    let cx = Math.max(rect.x, Math.min(c.x, rect.x+rect.w));
    let cy = Math.max(rect.y, Math.min(c.y, rect.y+rect.h));
    let dx = c.x - cx;
    let dy = c.y - cy;
    return dx*dx + dy*dy < r*r;
}

function update(){
    spawnTimer++;
    coinWaveTimer++;

    if(spawnTimer >= spawnRate){
        spawnTimer = 0;
        if(Math.random()<0.8) spawnSpike();
        if(Math.random()<0.28) spawnCoin();
    }

    if(coinWaveTimer >= coinWaveRate){
        coinWaveTimer = 0;
        spawnCoinWave();
    }

    // 重力
    player.vy += player.gravity;
    player.y += player.vy;

    // 地面碰撞
    if(player.y + player.h*player.pixelSize >= groundY){
        player.y = groundY - player.h*player.pixelSize;
        player.vy = 0;
        player.onGround = true;
    }else{
        player.onGround = false;
    }

    // 跑步动画:在地上才累积相位
    if(player.onGround){
        player.runPhase += 0.35;
    }

    // 移动尖刺和金币
    for(let i=spikes.length-1;i>=0;i--){
        spikes[i].x -= moveSpeed;
        if(spikes[i].x + spikes[i].w < 0) spikes.splice(i,1);
    }

    for(let i=coins.length-1;i>=0;i--){
        coins[i].x -= moveSpeed;
        if(coins[i].x + coins[i].r < 0) coins.splice(i,1);
    }

    // 碰撞尖刺
    const playerBox = {
        x: player.x+2,
        y: player.y+2,
        w: player.w*player.pixelSize-4,
        h: player.h*player.pixelSize-4
    };

    for(let s of spikes){
        if(rectOverlap(playerBox, s)){
            resetGame();
            return;
        }

        if(!s.scored && s.x + s.w/2 < player.x){
            s.scored = true;
            player.score += 1;
            updateUI();
        }
    }

    // 吃金币
    for(let i=coins.length-1;i>=0;i--){
        const c = coins[i];
        if(!c.collected && circleRect(c, c.r, playerBox)){
            c.collected = true;
            player.coinNum++;
            player.score += 10;
            coins.splice(i,1);
            updateUI();
        }
    }

    player.score += 0.02;
    updateUI();
}

function drawPlayer(){
    const px = player.pixelSize;
    const baseX = player.x;
    const baseY = player.y;

   

Game Source: 溶洞像素跳跃

Creator: MysticMaker96

Libraries: none

Complexity: complex (228 lines, 5.1 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-mysticmaker96-mw4lgq4g" to link back to the original. Then publish at arcadelab.ai/publish.