🎮ArcadeLab

平板三角洲战术枪战

by PrismHero25
208 lines7.1 KB
▶ Play
html
    

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>平板三角洲战术枪战</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;overflow:hidden;background:#000;font-family:system-ui}
canvas{display:block;width:100%;height:100%}

/* 平板触屏UI */
.joystick{position:absolute;left:20px;bottom:20px;width:140px;height:140px;background:rgba(25,25,25,0.4);border-radius:50%;touch-action:none}
.joystick-knob{width:60px;height:60px;background:rgba(255,255,255,0.5);border-radius:50%;position:absolute;left:40px;top:40px}
.fire-btn{position:absolute;right:24px;bottom:30px;width:100px;height:100px;border-radius:50%;background:rgba(200,30,30,0.4);color:#fff;font-size:24px;border:none;touch-action:none}
.hud{position:absolute;top:16px;left:16px;color:#fff;font-size:20px;background:rgba(0,0,0,0.5);padding:8px;border-radius:8px}
.crosshair{position:absolute;top:50%;left:50%;width:20px;height:20px;margin:-10px 0 0 -10px;color:#fff;font-size:24px;text-align:center;pointer-events:none}
</style>
</head>
<body>
<div class="hud">分数:<span id="score">0</span><br>血量:<span id="hp">100</span></div>
<div class="crosshair">+</div>
<div class="joystick" id="joystick">
    <div class="joystick-knob" id="joystickKnob"></div>
</div>
<button class="fire-btn" id="fireBtn">开火</button>

<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
<script>
// ========== 基础初始化 ==========
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x334433);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const light = new THREE.DirectionalLight(0xffffff,0.8);
light.position.set(20,40,20);
scene.add(light);
scene.add(new THREE.AmbientLight(0x404040));

// 玩家
let playerPos = new THREE.Vector3(0,1.6,0);
let yaw=0,pitch=0;
const playerSpeed=4;
let hp=100;
let score=0;

// 摇杆变量
let joy={active:false,dx:0,dy:0};
// 触屏滑动转向
let touchLookId=null;
let lastTouch={x:0,y:0};

// 地图墙体(坚固的墙,阻挡子弹和移动,对应你的作文)
const walls=[];
function createWall(x,z,w,h,d){
    const geo=new THREE.BoxGeometry(w,h,d);
    const mat=new THREE.MeshLambertMaterial({color:0x777777});
    const wall=new THREE.Mesh(geo,mat);
    wall.position.set(x,h/2,z);
    scene.add(wall);
    walls.push({mesh:wall,x,z,w,d})
}
createWall(8,0,1,4,12);
createWall(-8,0,1,4,12);
createWall(0,8,1,16,1);
createWall(0,-8,1,16,1);
createWall(-4,-4,1,5,5);
createWall(4,4,1,5,5);

// AI敌人
let enemies=[];
function spawnEnemy(){
    const geo=new THREE.CylinderGeometry(0.4,0.4,1.6,8);
    const mat=new THREE.MeshLambertMaterial({color:0xcc3333});
    const enemyMesh=new THREE.Mesh(geo,mat);
    enemyMesh.position.set( (Math.random()>0.5?1:-1)* (6+Math.random()*4), 0.8, (Math.random()>0.5?1:-1)*(6+Math.random()*4) );
    scene.add(enemyMesh);
    enemies.push({mesh:enemyMesh,hp:3,lastShot:0})
}
for(let i=0;i<3;i++) spawnEnemy();

// ========== 触屏摇杆 ==========
const joystick = document.getElementById("joystick");
const knob = document.getElementById("joystickKnob");
joystick.addEventListener("touchstart",e=>{
    e.preventDefault();
    joy.active=true;
})
joystick.addEventListener("touchmove",e=>{
    e.preventDefault();
    const t=e.touches[0];
    const rect=joystick.getBoundingClientRect();
    const cx=rect.left+rect.width/2;
    const cy=rect.top+rect.height/2;
    joy.dx = (t.clientX-cx)/60;
    joy.dy = (t.clientY-cy)/60;
    const len=Math.sqrt(joy.dx*joy.dx+joy.dy*joy.dy);
    if(len>1){joy.dx/=len;joy.dy/=len}
    knob.style.transform=`translate(${joy.dx*40}px,${joy.dy*40}px)`;
})
joystick.addEventListener("touchend",()=>{
    joy.active=false;
    joy.dx=0;joy.dy=0;
    knob.style.transform="translate(0,0)";
})

// 触屏滑动旋转视角
renderer.domElement.addEventListener("touchstart",e=>{
    for(let t of e.touches){
        if(t.target!==joystick && t.target!==fireBtn){
            touchLookId=t.identifier;
            lastTouch.x=t.clientX; lastTouch.y=t.clientY;
        }
    }
})
renderer.domElement.addEventListener("touchmove",e=>{
    for(let t of e.touches){
        if(t.identifier === touchLookId){
            const dx = t.clientX - lastTouch.x;
            const dy = t.clientY - lastTouch.y;
            yaw -= dx *0.004;
            pitch = Math.max(-1.2, Math.min(1.2, pitch - dy*0.004));
            lastTouch.x = t.clientX; lastTouch.y = t.clientY;
        }
    }
})

// 开火按钮
const fireBtn = document.getElementById("fireBtn");
fireBtn.addEventListener("touchstart",shoot);
function shoot(){
    const raycaster=new THREE.Raycaster();
    raycaster.setFromCamera(new THREE.Vector2(0,0),camera);
    const allHits=raycaster.intersectObjects(enemies.map(e=>e.mesh).concat(walls.map(w=>w.mesh)));
    if(allHits.length>0){
        const hit=allHits[0];
        for(let e of enemies){
            if(hit.object === e.mesh){
                e.hp--;
                if(e.hp<=0){
                    scene.remove(e.mesh);
                    enemies = enemies.filter(x=>x!==e);
                    score += 50;
                    document.getElementById("score").innerText=score;
                }
            }
        }
    }
}

// 敌人AI逻辑
function updateEnemies(delta){
    const now=Date.now();
    enemies.forEach(e=>{
        const ePos = e.mesh.position;
        const dir = new THREE.Vector3(playerPos.x-ePos.x,0,playerPos.z-ePos.z).normalize();
        const dist = playerPos.distanceTo(ePos);
        if(dist < 12 && dist>2){
            e.mesh.position.add(dir.multiplyScalar(0.025));
        }
        //敌人射击
        if(dist<10 && now-e.lastShot>1200){
            e.lastShot=now;
            hp -=8;
            document.getElementById("hp").innerText=Math.max(0,hp);
            if(hp<=0) alert("游戏结束!分数:"+score);
        }
        e.mesh.lookAt(playerPos.x, e.mesh.position.y, playerPos.z);
    })
}

// 游戏循环
let lastTime=0;
function loop(time){
    requestAnimationFrame(loop);
    const delta = (time-lastTime)/1000;
    lastTime=time;
    //摇杆移动
    if(joy.active){
        const forward=new THREE.Vector3(-Math.sin(yaw),0,-Math.cos(yaw));
        const right=new THREE.Vector3(Math.cos(yaw),0,-Math.sin(yaw));
        playerPos.add(forward.multiplyScalar(-joy.dy * playerSpeed*delta));
        playerPos.add(right.multiplyScalar(joy.dx * playerSpeed*delta));
    }
    camera.position.copy(playerPos);
    camera.rotation.order="YXZ";
    camera.rotation.y=yaw;
    camera.rotation.x=pitch;

    updateEnemies(delta);
    renderer.render(scene,camera);
}
requestAnimationFrame(loop);

// 窗口适配
window.addEventListener("resize",()=>{
    camera.aspect=window.innerWidth/window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth,window.innerHeight);
})
</script>
</body>
</html>

Game Source: 平板三角洲战术枪战

Creator: PrismHero25

Libraries: none

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