镰刀少女
by AtomicPenguin4443 lines12.1 KB
复制下面全部代码,粘贴到记事本,保存为 game.html,双击打开就能玩(点击画面也能攻击)。
```html
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>镰刀少女</title><style>*{margin:0;padding:0;box-sizing:border-box;user-select:none}body{background:#1a1a2e;display:flex;justify-content:center;align-items:center;min-height:100vh;font-family:sans-serif}.game-wrapper{background:#16213e;padding:20px;border-radius:32px;border:2px solid #e94560}canvas{display:block;margin:0 auto;border-radius:20px;background:#2d4059;cursor:crosshair;width:800px;height:600px}.panel{display:flex;justify-content:space-between;align-items:center;margin-top:16px;color:#eee;font-weight:bold;padding:0 10px;flex-wrap:wrap;gap:10px}.stats{display:flex;gap:30px;background:#0f3460;padding:8px 20px;border-radius:40px;border:1px solid #e94560}.stats span{color:#f5c842}.controls{background:#0f3460;padding:8px 20px;border-radius:40px;border:1px solid #533483;font-size:14px;color:#bbb}.controls kbd{background:#222;color:#fff;padding:2px 10px;border-radius:6px;margin:0 4px;border:1px solid #555}</style></head><body><div class="game-wrapper"><canvas id="c" width="800" height="600"></canvas><div class="panel"><div class="stats"><div>❤️ 生命: <span id="hp">100000</span></div><div>⚔️ 攻击: <span id="atk">5000</span></div><div>💀 击杀: <span id="kill">0</span></div></div><div class="controls"><kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd> 移动 · <kbd>空格</kbd> 攻击</div></div></div><script>
const canvas=document.getElementById('c'),ctx=canvas.getContext('2d'),hpS=document.getElementById('hp'),atkS=document.getElementById('atk'),killS=document.getElementById('kill');
const R=22,ATK_RANGE=80,COOLDOWN=400,MAX_HP=100000,ATK=5000, MONSTER_HP=15000,BOSS_HP=100000,TREE_HP=50000;
let player={x:400,y:300,radius:R,hp:MAX_HP,maxHp:MAX_HP,attack:ATK,dir:0};
let monsters=[],bosses=[],trees=[],particles=[],floats=[],killCount=0,lastAttack=0,keys={w:0,a:0,s:0,d:0},gameOver=0,frame;
function initTrees(){trees=[];for(let i=0;i<10;i++){let x,y,o,a=0;do{x=60+Math.random()*680;y=60+Math.random()*480;o=Math.hypot(x-400,y-300)<120||trees.some(t=>Math.hypot(x-t.x,y-t.y)<70);a++;}while(o&&a<50);trees.push({x,y,radius:28,hp:TREE_HP,maxHp:TREE_HP});}}
function spawnMonster(){let s=Math.floor(Math.random()*4),x,y;if(s===0){x=40;y=50+Math.random()*500;}else if(s===1){x=760;y=50+Math.random()*500;}else if(s===2){x=50+Math.random()*700;y=40;}else{x=50+Math.random()*700;y=560;}if(Math.hypot(x-player.x,y-player.y)<150){x=Math.min(780,Math.max(20,x+(Math.random()-0.5)*200));y=Math.min(580,Math.max(20,y+(Math.random()-0.5)*200));}monsters.push({x,y,radius:22,hp:MONSTER_HP,maxHp:MONSTER_HP,speed:1.2+Math.random()*0.8});}
function summonBoss(x,y){bosses.push({x,y,radius:38,hp:BOSS_HP,maxHp:BOSS_HP,speed:0.7+Math.random()*0.4});for(let i=0;i<30;i++){let a=Math.random()*6.28,s=2+Math.random()*5;particles.push({x,y,vx:Math.cos(a)*s,vy:Math.sin(a)*s,life:60+Math.random()*30,maxLife:90,radius:4+Math.random()*6,color:`hsl(${340+Math.random()*40},90%,60%)`});}}
function addFloat(x,y,t,c='#fff'){floats.push({x,y,text:t,color:c,life:50,maxLife:50,vy:-2.5});}
function attack(){if(gameOver||Date.now()-lastAttack<COOLDOWN)return;lastAttack=Date.now();let cx=player.x,cy=player.y;
for(let i=monsters.length-1;i>=0;i--){let m=monsters[i];if(Math.hypot(m.x-cx,m.y-cy)<ATK_RANGE+m.radius){m.hp-=ATK;addFloat(m.x,m.y-30,'-'+ATK,'#ffaa00');if(m.hp<=0){let bx=m.x,by=m.y;monsters.splice(i,1);killCount++;summonBoss(bx,by);addFloat(bx,by-50,'⚡ Boss!','#ff3333');}}}
for(let i=bosses.length-1;i>=0;i--){let b=bosses[i];if(Math.hypot(b.x-cx,b.y-cy)<ATK_RANGE+b.radius){b.hp-=ATK;addFloat(b.x,b.y-30,'-'+ATK,'#ff6666');if(b.hp<=0){for(let j=0;j<50;j++){let a=Math.random()*6.28,s=3+Math.random()*8;particles.push({x:b.x,y:b.y,vx:Math.cos(a)*s,vy:Math.sin(a)*s,life:80+Math.random()*40,maxLife:120,radius:6+Math.random()*10,color:`hsl(${40+Math.random()*30},100%,60%)`});}addFloat(b.x,b.y-60,'💥 Boss击败!','#ffcc00');bosses.splice(i,1);killCount+=5;}}}
for(let i=trees.length-1;i>=0;i--){let t=trees[i];if(Math.hypot(t.x-cx,t.y-cy)<ATK_RANGE+t.radius){t.hp-=ATK;addFloat(t.x,t.y-30,'-'+ATK,'#8bc34a');if(t.hp<=0){for(let j=0;j<20;j++){let a=Math.random()*6.28,s=1+Math.random()*4;particles.push({x:t.x,y:t.y,vx:Math.cos(a)*s,vy:Math.sin(a)*s-2,life:40+Math.random()*30,maxLife:70,radius:5+Math.random()*8,color:`hsl(${100+Math.random()*30},70%,40%)`});}addFloat(t.x,t.y-40,'🌳 砍倒!','#8bc34a');trees.splice(i,1);}}}
killS.textContent=killCount;}
function move(){if(gameOver)return;let dx=0,dy=0;if(keys.w)dy=-1;if(keys.s)dy=1;if(keys.a)dx=-1;if(keys.d)dx=1;if(dx||dy){let l=Math.hypot(dx,dy);dx=dx/l*4.5;dy=dy/l*4.5;player.dir=Math.atan2(dy,dx);}let nx=player.x+dx,ny=player.y+dy;player.x=Math.min(780,Math.max(20,nx));player.y=Math.min(580,Math.max(20,ny));}
function updateMonsters(){for(let m of monsters){let dx=player.x-m.x,dy=player.y-m.y,d=Math.hypot(dx,dy);if(d>1){let s=Math.min(m.speed,d);m.x+=dx/d*s;m.y+=dy/d*s;}if(Math.hypot(m.x-player.x,m.y-player.y)<m.radius+player.radius){if(!m.hitCD||Date.now()-m.hitCD>600){player.hp-=800;m.hitCD=Date.now();addFloat(player.x,player.y-40,'-800','#ff4444');if(player.hp<=0){player.hp=0;gameOver=1;addFloat(400,280,'💀 游戏结束','#ff0000');}hpS.textContent=Math.floor(player.hp);}}}}
function updateBosses(){for(let b of bosses){let dx=player.x-b.x,dy=player.y-b.y,d=Math.hypot(dx,dy);if(d>1){let s=Math.min(b.speed,d);b.x+=dx/d*s;b.y+=dy/d*s;}if(Math.hypot(b.x-player.x,b.y-player.y)<b.radius+player.radius){if(!b.hitCD||Date.now()-b.hitCD>500){player.hp-=1500;b.hitCD=Date.now();addFloat(player.x,player.y-50,'-1500','#ff2222');if(player.hp<=0){player.hp=0;gameOver=1;addFloat(400,280,'💀 游戏结束','#ff0000');}hpS.textContent=Math.floor(player.hp);}}}}
function spawnLoop(){if(gameOver)return;if(monsters.length<12&&Math.random()<0.03)spawnMonster();}
function updateParticles(){for(let i=particles.length-1;i>=0;i--){let p=particles[i];p.x+=p.vx;p.y+=p.vy;p.vy+=0.08;p.life--;if(p.life<=0)particles.splice(i,1);}for(let i=floats.length-1;i>=0;i--){let f=floats[i];f.y+=f.vy;f.life--;if(f.life<=0)floats.splice(i,1);}}
function draw(){ctx.clearRect(0,0,800,600);
ctx.strokeStyle='#3a4d66';ctx.lineWidth=1;for(let i=0;i<800;i+=40){ctx.beginPath();ctx.moveTo(i,0);ctx.lineTo(i,600);ctx.stroke();}for(let i=0;i<600;i+=40){ctx.beginPath();ctx.moveTo(0,i);ctx.lineTo(800,i);ctx.stroke();}
for(let t of trees){let r=t.hp/t.maxHp;ctx.shadowColor='#2e4a2e';ctx.shadowBlur=15;ctx.fillStyle='#6b4c3b';ctx.fillRect(t.x-6,t.y+10,12,25);ctx.beginPath();ctx.arc(t.x,t.y-6,t.radius,0,6.28);ctx.fillStyle=`hsl(120,50%,${30+30*r}%)`;ctx.fill();ctx.strokeStyle='#1d3b1d';ctx.lineWidth=2;ctx.stroke();ctx.shadowBlur=0;ctx.fillStyle='#222';ctx.fillRect(t.x-30,t.y-50,60,8);ctx.fillStyle=`hsl(${120*r},80%,50%)`;ctx.fillRect(t.x-30,t.y-50,60*r,8);ctx.fillStyle='#fff';ctx.font='12px sans-serif';ctx.fillText('🌳',t.x-12,t.y-30);}
for(let m of monsters){let r=m.hp/m.maxHp;ctx.shadowColor='#a855f7';ctx.shadowBlur=20;ctx.beginPath();ctx.arc(m.x,m.y,m.radius,0,6.28);ctx.fillStyle=`hsl(280,70%,${40+30*r}%)`;ctx.fill();ctx.strokeStyle='#7c3aed';ctx.lineWidth=3;ctx.stroke();ctx.shadowBlur=0;ctx.fillStyle='#ffdd44';ctx.beginPath();ctx.arc(m.x-8,m.y-5,5,0,6.28);ctx.fill();ctx.beginPath();ctx.arc(m.x+8,m.y-5,5,0,6.28);ctx.fill();ctx.fillStyle='#000';ctx.beginPath();ctx.arc(m.x-10,m.y-7,2,0,6.28);ctx.fill();ctx.beginPath();ctx.arc(m.x+6,m.y-7,2,0,6.28);ctx.fill();ctx.fillStyle='#222';ctx.fillRect(m.x-30,m.y-40,60,6);ctx.fillStyle=`hsl(${120*r},80%,50%)`;ctx.fillRect(m.x-30,m.y-40,60*r,6);ctx.fillStyle='#fff';ctx.font='10px sans-serif';ctx.fillText('👾'+Math.floor(m.hp),m.x-20,m.y-48);}
for(let b of bosses){let r=b.hp/b.maxHp;ctx.shadowColor='#ff0066';ctx.shadowBlur=35;ctx.beginPath();ctx.arc(b.x,b.y,b.radius,0,6.28);let g=ctx.createRadialGradient(b.x-10,b.y-10,5,b.x,b.y,b.radius);g.addColorStop(0,'#ff4d4d');g.addColorStop(1,'#990000');ctx.fillStyle=g;ctx.fill();ctx.strokeStyle='#ffaa00';ctx.lineWidth=4;ctx.stroke();ctx.shadowBlur=0;ctx.fillStyle='#fff';ctx.font='bold 24px sans-serif';ctx.fillText('😡',b.x-18,b.y+10);ctx.fillStyle='#111';ctx.fillRect(b.x-45,b.y-55,90,12);ctx.fillStyle=`hsl(${120*r},90%,50%)`;ctx.fillRect(b.x-45,b.y-55,90*r,12);ctx.fillStyle='#fff';ctx.font='bold 12px sans-serif';ctx.fillText('👑BOSS '+Math.floor(b.hp),b.x-35,b.y-60);}
ctx.shadowColor='#e94560';ctx.shadowBlur=25;ctx.beginPath();ctx.ellipse(player.x,player.y+10,18,22,0,0,6.28);ctx.fillStyle='#ff6b9d';ctx.fill();ctx.strokeStyle='#d6336c';ctx.lineWidth=2;ctx.stroke();ctx.shadowBlur=15;ctx.beginPath();ctx.arc(player.x,player.y-8,18,0,6.28);ctx.fillStyle='#ffe0bd';ctx.fill();ctx.strokeStyle='#d4a373';ctx.lineWidth=2;ctx.stroke();ctx.fillStyle='#4a2c2c';ctx.beginPath();ctx.ellipse(player.x-16,player.y-2,6,16,-0.3,0,6.28);ctx.fill();ctx.beginPath();ctx.ellipse(player.x+16,player.y-2,6,16,0.3,0,6.28);ctx.fill();ctx.fillStyle='#ff1493';ctx.beginPath();ctx.ellipse(player.x-10,player.y-24,8,4,-0.5,0,6.28);ctx.fill();ctx.beginPath();ctx.ellipse(player.x+10,player.y-24,8,4,0.5,0,6.28);ctx.fill();ctx.fillStyle='#fff';ctx.beginPath();ctx.arc(player.x,player.y-24,3,0,6.28);ctx.fill();ctx.fillStyle='#222';ctx.beginPath();ctx.arc(player.x-7,player.y-10,3,0,6.28);ctx.fill();ctx.beginPath();ctx.arc(player.x+7,player.y-10,3,0,6.28);ctx.fill();ctx.fillStyle='#fff';ctx.beginPath();ctx.arc(player.x-9,player.y-13,1.2,0,6.28);ctx.fill();ctx.beginPath();ctx.arc(player.x+5,player.y-13,1.2,0,6.28);ctx.fill();
ctx.shadowBlur=30;ctx.shadowColor='#c0c0c0';let a=player.dir||0,bl=42,hl=30,sx=player.x+Math.cos(a)*20,sy=player.y+Math.sin(a)*20,ex=sx+Math.cos(a)*hl,ey=sy+Math.sin(a)*hl;ctx.beginPath();ctx.moveTo(sx,sy);ctx.lineTo(ex,ey);ctx.strokeStyle='#5d4037';ctx.lineWidth=6;ctx.stroke();ctx.beginPath();let ba=a-0.8,ba2=a+0.8,bex=ex+Math.cos(ba)*bl,bey=ey+Math.sin(ba)*bl,bex2=ex+Math.cos(ba2)*bl*0.7,bey2=ey+Math.sin(ba2)*bl*0.7;ctx.moveTo(ex,ey);ctx.quadraticCurveTo(ex+Math.cos(a)*30,ey+Math.sin(a)*30-10,bex,bey);ctx.quadraticCurveTo(ex+Math.cos(a)*10,ey+Math.sin(a)*10+12,bex2,bey2);ctx.closePath();ctx.fillStyle='#e0e0e0';ctx.fill();ctx.strokeStyle='#999';ctx.lineWidth=2;ctx.stroke();ctx.fillStyle='rgba(255,255,255,0.3)';ctx.beginPath();ctx.arc(ex+10,ey-8,6,0,6.28);ctx.fill();
ctx.shadowBlur=0;ctx.fillStyle='#fff';ctx.font='bold 14px sans-serif';ctx.fillText('🌸 镰刀少女',player.x-40,player.y-60);ctx.fillStyle='#ff6b6b';ctx.fillRect(player.x-35,player.y-70,70,6);ctx.fillStyle='#51cf66';ctx.fillRect(player.x-35,player.y-70,70*(player.hp/player.maxHp),6);
for(let p of particles){ctx.shadowBlur=20;ctx.shadowColor=p.color;ctx.beginPath();ctx.arc(p.x,p.y,p.radius*(p.life/p.maxLife),0,6.28);ctx.fillStyle=p.color;ctx.fill();}
ctx.shadowBlur=10;ctx.shadowColor='#000';for(let f of floats){ctx.font=`bold ${20+(1-f.life/f.maxLife)*10}px sans-serif`;ctx.fillStyle=f.color;ctx.globalAlpha=f.life/f.maxLife;ctx.fillText(f.text,f.x-30,f.y);ctx.globalAlpha=1;}
ctx.shadowBlur=0;ctx.fillStyle='rgba(255,255,255,0.2)';ctx.font='14px sans-serif';ctx.fillText('小怪HP:15000 | BossHP:100000 | 树HP:50000',20,580);if(gameOver){ctx.fillStyle='rgba(0,0,0,0.7)';ctx.fillRect(0,0,800,600);ctx.fillStyle='#ff3333';ctx.font='bold 56px sans-serif';ctx.fillText('💀 败北',300,300);ctx.fillStyle='#fff';ctx.font='24px sans-serif';ctx.fillText('刷新页面 重新开始',280,370);}}
function loop(){if(!gameOver){move();updateMonsters();updateBosses();spawnLoop();updateParticles();if(player.hp<player.maxHp&&!gameOver){player.hp=Math.min(player.maxHp,player.hp+0.5);}hpS.textContent=Math.floor(player.hp);}draw();frame=requestAnimationFrame(loop);}
window.addEventListener('keydown',e=>{let k=e.key.toLowerCase();if(k==='w'||k==='a'||k==='s'||k==='d'){keys[k]=1;e.preventDefault();}if(e.key===' '){e.preventDefault();attack();}});
window.addEventListener('keyup',e=>{let k=e.key.toLowerCase();if(k==='w'||k==='a'||k==='s'||k==='d'){keys[k]=0;e.preventDefault();}if(e.key===' ')e.preventDefault();});
canvas.addEventListener('click',attack);
initTrees();for(let i=0;i<3;i++)spawnMonster();atkS.textContent=ATK;loop();
</script></body></html>
```
保存后双击运行,键盘 WASD 移动,空格 或点击画面攻击。击败小怪会召唤 Boss,砍树也有收益。祝玩得开心!Game Source: 镰刀少女
Creator: AtomicPenguin44
Libraries: none
Complexity: simple (43 lines, 12.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-atomicpenguin44" to link back to the original. Then publish at arcadelab.ai/publish.