🎮ArcadeLab

制裁白子

by WildOwl28
214 lines6.7 KB
▶ Play
<!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 {overflow: hidden; background: #222; touch-action: none;}
        #gameCanvas {display: block; background: #7ccd7c;}
        #gameOver {
            position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
            background: red; color: #fff; font-size: 32px;
            display: none; flex-direction: column;
            align-items: center; justify-content: center;
            gap: 40px; z-index: 99;
        }
        #restartBtn {
            padding: 14px 36px; font-size: 22px; cursor: pointer;
            border: none; border-radius: 8px; background: #fff; color: red;
        }
        .joystick {
            position: fixed; bottom: 30px; left: 30px;
            width: 120px; height: 120px;
            background: rgba(255,255,255,0.2); border-radius: 50%;
            touch-action: none;
        }
        .stick {
            width: 50px; height: 50px; border-radius: 50%;
            background: rgba(255,255,255,0.4);
            position: absolute; left: 50%; top: 50%;
            transform: translate(-50%,-50%);
        }
    </style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="gameOver">
    <div>你已经被吃了游戏结束(你暗恋方向盘)</div>
    <button id="restartBtn">重新开始</button>
</div>
<div class="joystick" id="joy">
    <div class="stick" id="stick"></div>
</div>

<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const gameOverEl = document.getElementById('gameOver');
const restartBtn = document.getElementById('restartBtn');
const joy = document.getElementById('joy');
const stick = document.getElementById('stick');

function resize(){
    canvas.width = innerWidth;
    canvas.height = innerHeight;
}
resize();
window.addEventListener('resize', resize);

//游戏数据
let gameState = 'play';
let player = {x:0,y:0,size:24,speed:4};
let heldItem = null;
let knifeSpawned = false;
let trees = [];
let enemies = [];
let items = [];
let dragonTimer = 0;
let rainEffect = false;
let enemyFreeze = 0;
let camera = {x:0,y:0};
let lastDragonTime = 0;
let worldExtendDist = 800;

//摇杆
let joyActive = false, joyVec={x:0,y:0};
joy.addEventListener('touchstart',e=>{joyActive=true;updateJoy(e.touches[0]);});
document.addEventListener('touchmove',e=>joyActive&&updateJoy(e.touches[0]));
document.addEventListener('touchend',()=>{joyActive=false;joyVec={x:0,y:0};stick.style.transform='translate(-50%,-50%)';});
function updateJoy(touch){
    const rect = joy.getBoundingClientRect();
    const cx = rect.left+rect.width/2, cy=rect.top+rect.height/2;
    let dx = touch.clientX - cx, dy = touch.clientY - cy;
    const maxR = rect.width/2 - 25;
    const dist = Math.hypot(dx,dy);
    if(dist>maxR){dx=dx/dist*maxR; dy=dy/dist*maxR;}
    stick.style.left = (rect.width/2+dx)+'px';
    stick.style.top = (rect.height/2+dy)+'px';
    joyVec = {x:dx/maxR, y:dy/maxR};
}

//生成树木
function spawnTree(px,py){
    const type = Math.random()>0.5 ? 'tree1' : 'tree2';
    trees.push({x:px+(Math.random()-0.5)*worldExtendDist, y:py+(Math.random()-0.5)*worldExtendDist, type, size:28+Math.random()*12});
}
//生成敌人(数量少、移速慢)
function spawnEnemy(px,py){
    const types = ['devil','ghost','alien'];
    const t = types[Math.floor(Math.random()*types.length)];
    const angle = Math.random()*Math.PI*2;
    const dist = 450+Math.random()*600;
    enemies.push({
        x: px+Math.cos(angle)*dist,
        y: py+Math.sin(angle)*dist,
        type:t, speed:1.1, size:26
    });
}
//道具
function spawnItem(px,py){
    const list = ['dragon','lobster','water','boom','bomb','spin','sleep','knife'];
    let t;
    if(!knifeSpawned && Math.random()<0.12){
        t='knife'; knifeSpawned=true;
    }else{
        t = list.filter(v=>v!=='knife')[Math.floor(Math.random()*7)];
    }
    const ang = Math.random()*Math.PI*2;
    const d = 300+Math.random()*500;
    items.push({
        x:px+Math.cos(ang)*d,
        y:py+Math.sin(ang)*d,
        type:t, size:22
    });
}

function initGame(){
    gameState='play';
    gameOverEl.style.display='none';
    player={x:0,y:0,size:24,speed:4};
    heldItem=null;
    knifeSpawned=false;
    trees=[];enemies=[];items=[];
    dragonTimer=0;rainEffect=false;enemyFreeze=0;
    camera={x:0,y:0};
    lastDragonTime=Date.now();
    for(let i=0;i<35;i++) spawnTree(0,0);
    for(let i=0;i<4;i++) spawnEnemy(0,0);
    for(let i=0;i<9;i++) spawnItem(0,0);
}
restartBtn.onclick = initGame;
initGame();

//键盘
const keys={};
document.addEventListener('keydown',e=>keys[e.key.toLowerCase()]=true);
document.addEventListener('keyup',e=>keys[e.key.toLowerCase()]=false);

function getMoveDir(){
    let x=0,y=0;
    if(keys['w']||keys['arrowup'])y-=1;
    if(keys['s']||keys['arrowdown'])y+=1;
    if(keys['a']||keys['arrowleft'])x-=1;
    if(keys['d']||keys['arrowright'])x+=1;
    if(joyActive){x+=joyVec.x; y+=joyVec.y;}
    const len = Math.hypot(x,y);
    if(len>0) return {x:x/len, y:y/len};
    return {x:0,y:0};
}

//碰撞
function circleCollision(a,b){
    const d = Math.hypot(a.x-b.x, a.y-b.y);
    return d < a.size/2 + b.size/2;
}

//合成系统
function combineItems(itemA,itemB){
    if(itemA==='dragon'&&itemB==='lobster' || itemA==='lobster'&&itemB==='dragon'){
        alert('你是龙啊,你是虾子');
        enemyFreeze = 3000;
        setTimeout(()=>{
            enemies.forEach(e=>e.speed=1.1);
        },3000);
        return true;
    }
    if(itemA==='water'&&itemB==='boom' || itemA==='boom'&&itemB==='water'){
        alert('下雨了!');
        rainEffect=true;
        enemies.forEach(e=>{
            const knock = {x:(e.x-player.x)*0.25, y:(e.y-player.y)*0.25};
            e.x+=knock.x*12; e.y+=knock.y*12;
        });
        setTimeout(()=>rainEffect=false,800);
        return true;
    }
    return false;
}

function gameLoop(){
    ctx.fillStyle='#7ccd7c';
    ctx.fillRect(0,0,canvas.width,canvas.height);
    if(gameState!=='play'){
        requestAnimationFrame(gameLoop);
        return;
    }
    const move = getMoveDir();
    player.x += move.x * player.speed;
    player.y += move.y * player.speed;
    camera.x = player.x - canvas.width/2;
    camera.y = player.y - canvas.height/2;

    //每10秒刷龙
    const now = Date.now();
    if(now - lastDragonTime > 10000){
        const ang = Math.random()*Math.PI*2;
        const dis = 350+Math.random()*400;
        items.push({
            x:player.x+Math.cos(ang)*dis,
            y:player.y+Math.sin(ang)*dis,
            type:'dragon', size:22
       

Game Source: 制裁白子

Creator: WildOwl28

Libraries: none

Complexity: complex (214 lines, 6.7 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-wildowl28" to link back to the original. Then publish at arcadelab.ai/publish.