《网页游戏》💥💥💥
2026-10-25 16:12:36
发布于:浙江
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>蓄力空战 · 难度递增版</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{
overflow:hidden;
background:#050510;
height:100vh;
cursor:crosshair;
font-family:system-ui;
}
canvas{display:block;}
.ui{
position:fixed;
top:14px;
left:14px;
color:#4cf;
text-shadow:0 0 6px #4cf;
z-index:2;
font-size:17px;
line-height:1.6;
}
.chargeBar{
width:160px;height:10px;background:#223;
margin-top:4px;
border-radius:4px;
overflow:hidden;
}
.chargeFill{
height:100%;width:0%;background:#ffc822;
box-shadow:0 0 8px #ffc822;
transition:none;
}
.tip{
position:fixed;bottom:16px;left:16px;color:#999;font-size:14px;
}
#gameOverUI{
position:fixed;
inset:0;
background:rgba(0,0,0,0.75);
display:none;
z-index:10;
flex-direction:column;
align-items:center;
justify-content:center;
color:#ff4455;
text-shadow:0 0 14px #ff2233;
}
#gameOverUI h1{
font-size:64px;
margin:0;
}
#gameOverUI .finalScore{
font-size:26px;
margin:12px 0 24px;
color:#ffbb66;
}
#gameOverUI .hint{
color:#ccc;
font-size:18px;
}
#skillSelectUI{
position:fixed;
inset:0;
background:rgba(0,0,0,0.85);
display:flex;
z-index:20;
flex-direction:column;
align-items:center;
justify-content:center;
color:#fff;
}
#skillSelectUI h2{
font-size:40px;
color:#ffdd44;
text-shadow:0 0 12px #ffdd44;
margin-bottom:24px;
}
.skillBoxWrap{
display:flex;
gap:16px;
flex-wrap:wrap;
max-width:900px;
justify-content:center;
}
.skillCard{
width:200px;
padding:18px;
background:#111830;
border:2px solid #3366aa;
border-radius:12px;
cursor:pointer;
transition:0.25s;
}
.skillCard:hover{
border-color:#ffdd44;
box-shadow:0 0 16px #ffdd4455;
transform:translateY(-6px);
}
.skillCard h3{
color:#4cf;
margin:0 0 10px;
font-size:18px;
}
.skillCard p{
color:#ccc;
font-size:13px;
line-height:1.45;
}
</style>
</head>
<body>
<div class="ui">
分数:<span id="score">0</span><br>
血量:<span id="hp">100</span>|弹药:<span id="ammo">15</span>
<div class="chargeBar"><div class="chargeFill" id="charge"></div></div>
</div>
<div class="tip">WASD移动|长按鼠标蓄力射击|Shift冲刺|Q二连发|E冰冻光环</div>
<div id="gameOverUI">
<h1>陨落</h1>
<div class="finalScore">最终分数:<span id="finalScore">0</span></div>
<div class="hint">按空格键重新挑战</div>
</div>
<div id="skillSelectUI">
<h2>选择你的出战技能</h2>
<div class="skillBoxWrap">
<div class="skillCard" data-skill="double">
<h3>二连发</h3>
<p>Q释放,消耗1发弹药,双发子弹,自带溅射伤害</p>
</div>
<div class="skillCard" data-skill="chargeBoost">
<h3>蓄力增幅</h3>
<p>蓄力伤害+40%,爆炸范围更大,清怪更强</p>
</div>
<div class="skillCard" data-skill="dashTrail">
<h3>冲刺残影</h3>
<p>Shift冲刺留下残影,持续对接触敌人造成伤害</p>
</div>
<div class="skillCard" data-skill="pierce">
<h3>穿透弹</h3>
<p>子弹可以穿透敌人,不会击中一次就消失</p>
</div>
<div class="skillCard" data-skill="lifesteal">
<h3>吸血打击</h3>
<p>击杀敌人恢复少量生命值,提升生存</p>
</div>
<div class="skillCard" data-skill="freezeAura">
<h3>冰冻光环</h3>
<p>E释放,冻结周围敌人,敌人暂停移动和射击</p>
</div>
</div>
</div>
<canvas id="c"></canvas>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const hpEl = document.getElementById('hp');
const ammoEl = document.getElementById('ammo');
const chargeEl = document.getElementById('charge');
const overUI = document.getElementById('gameOverUI');
const finalScoreEl = document.getElementById('finalScore');
const skillSelectUI = document.getElementById('skillSelectUI');
let w = canvas.width = innerWidth;
let h = canvas.height = innerHeight;
window.onresize = ()=>{
w = canvas.width = innerWidth;
h = canvas.height = innerHeight;
}
let selectedSkill = null;
let gameStart = false;
let enemyHpMultiplier = 1.0; // 敌人血量倍率,每击杀+10%
const player = {
x:w/2,y:h/2,size:18,speed:4.2,
hp:100,ammo:15,
dashCD:0,dashMaxCD:120,
freezeCD:0,freezeMaxCD:180,
isCharging:false,chargeTime:0,maxCharge:70
};
let score = 0;
let gameOn = true;
const keys = {};
let mouseX = w/2, mouseY = h/2;
let shake = 0;
let dashTrails = [];
let freezeAuraActive = false;
let freezeAuraTimer = 0;
const freezeRange = 180;
document.querySelectorAll('.skillCard').forEach(card=>{
card.onclick = ()=>{
selectedSkill = card.dataset.skill;
skillSelectUI.style.display = 'none';
gameStart = true;
resetGame();
}
})
window.addEventListener('keydown',e=>{
keys[e.key.toLowerCase()] = true;
if(e.code === 'Space' && !gameOn && gameStart){
resetGame();
}
if(e.key.toLowerCase()==='q' && gameOn && selectedSkill==='double' && player.ammo>0){
doubleFire();
}
if(e.key.toLowerCase()==='e' && gameOn && selectedSkill==='freezeAura' && player.freezeCD<=0){
freezeAuraActive = true;
freezeAuraTimer = 70;
player.freezeCD = player.freezeMaxCD;
shake = 4;
}
})
window.addEventListener('keyup',e=>keys[e.key.toLowerCase()]=false);
window.addEventListener('mousemove',e=>{mouseX=e.clientX;mouseY=e.clientY;})
window.addEventListener('mousedown',e=>{
if(e.button===0 && gameOn && player.ammo>0) player.isCharging=true;
})
window.addEventListener('mouseup',e=>{
if(e.button===0 && player.isCharging){
fire();
player.isCharging=false;
player.chargeTime=0;
}
})
class WaveRing{
constructor(x,y,maxR=80){
this.x = x;
this.y = y;
this.r = 0;
this.maxR = maxR;
this.alpha = 1;
this.centerDotSize = 12;
}
update(){
this.r += 3.8;
this.alpha = 1 - this.r / this.maxR;
this.centerDotSize *= 0.92;
}
draw(){
if(this.alpha <= 0) return;
ctx.save();
ctx.globalAlpha = this.alpha;
ctx.fillStyle="#fff844";
ctx.shadowBlur=18;
ctx.shadowColor="#fff844";
ctx.beginPath();
ctx.arc(this.x,this.y,this.centerDotSize,0,Math.PI*2);
ctx.fill();
let grad = ctx.createRadialGradient(this.x,this.y,0,this.x,this.y,this.r);
grad.addColorStop(0,"#fff833");
grad.addColorStop(0.6,"#ffcc22");
grad.addColorStop(1,"rgba(255,180,0,0)");
ctx.strokeStyle = grad;
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2);
ctx.stroke();
ctx.restore();
}
done(){
return this.r >= this.maxR;
}
}
class Bullet{
constructor(x,y,angle,power){
this.x=x;this.y=y;
this.speed=11;
this.vx=Math.cos(angle)*this.speed;
this.vy=Math.sin(angle)*this.speed;
this.size=3+power*0.08;
this.damage=10+power*0.4;
if(selectedSkill==="chargeBoost") this.damage *= 1.4;
this.power=power;
this.isExplosive = power>50;
this.life=120;
this.splashRange = 55;
this.pierce = selectedSkill === "pierce";
}
update(){
this.x+=this.vx;this.y+=this.vy;this.life--;
}
draw(){
ctx.fillStyle=this.isExplosive?"#ffd040":"#4ff";
ctx.shadowBlur=10;ctx.shadowColor=ctx.fillStyle;
ctx.beginPath();ctx.arc(this.x,this.y,this.size,0,Math.PI*2);ctx.fill();
ctx.shadowBlur=0;
}
out(){return this.x<-30||this.x>w+30||this.y<-30||this.y>h+30||this.life<=0;}
}
class EnemyBullet{
constructor(x,y,tx,ty){
this.x=x;this.y=y;
const a=Math.atan2(ty-y,tx-x);
this.vx=Math.cos(a)*3.2;this.vy=Math.sin(a)*3.2;
this.size=5;this.life=200;
}
update(){this.x+=this.vx;this.y+=this.vy;this.life--;}
draw(){
ctx.fillStyle="#f66";
ctx.shadowBlur=6;ctx.beginPath();ctx.arc(this.x,this.y,this.size,0,Math.PI*2);ctx.fill();
ctx.shadowBlur=0;
}
out(){return this.life<=0;}
}
class Enemy{
constructor(type){
this.type=type;
this.size=type==0?14:17;
const baseHp = type==0?25:45;
this.hp = baseHp * enemyHpMultiplier;
this.baseHp = this.hp;
const side=Math.floor(Math.random()*4);
if(side===0){this.x=Math.random()*w;this.y=-20;}
else if(side===1){this.x=Math.random()*w;this.y=h+20;}
else if(side===2){this.x=-20;this.y=Math.random()*h;}
else {this.x=w+20;this.y=Math.random()*h;}
this.shootTimer=0;
this.frozen = false;
}
update(){
if(this.frozen) return;
const ang=Math.atan2(player.y-this.y,player.x-this.x);
if(this.type===0){
const spd=1.6+score/600;
this.x+=Math.cos(ang)*spd;
this.y+=Math.sin(ang)*spd;
}else{
const dist=Math.hypot(player.x-this.x,player.y-this.y);
const idealDist=220;
if(dist>idealDist+40){
this.x+=Math.cos(ang)*1.3;
this.y+=Math.sin(ang)*1.3;
}else if(dist<idealDist-40){
this.x-=Math.cos(ang)*1.1;
this.y-=Math.sin(ang)*1.1;
}else{
const perp=ang+Math.PI/2;
this.x+=Math.cos(perp)*0.8;
this.y+=Math.sin(perp)*0.8;
}
this.shootTimer++;
if(this.shootTimer>90){
enemyBullets.push(new EnemyBullet(this.x,this.y,player.x,player.y));
this.shootTimer=0;
}
}
}
draw(){
ctx.fillStyle = this.frozen ? "#6cf" : (this.type===0?"#f44":"#f92");
ctx.shadowBlur=8;ctx.beginPath();ctx.arc(this.x,this.y,this.size,0,Math.PI*2);ctx.fill();
ctx.shadowBlur=0;
}
}
class Drop{
constructor(x,y){
this.x=x;this.y=y;this.size=9;this.life=500;
}
update(){this.life--;}
draw(){
ctx.fillStyle="#4f8";ctx.shadowBlur=8;
ctx.beginPath();ctx.arc(this.x,this.y,this.size,0,Math.PI*2);ctx.fill();
ctx.shadowBlur=0;
}
}
class DashTrail{
constructor(x,y){
this.x=x;this.y=y;
this.r=16;
this.life=25;
}
update(){this.life--;}
draw(){
ctx.save();
ctx.globalAlpha=this.life/25*0.6;
ctx.fillStyle="#4cf";
ctx.shadowBlur=10;
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2);
ctx.fill();
ctx.restore();
}
done(){return this.life<=0;}
}
let bullets=[];
let enemyBullets=[];
let enemies=[];
let drops=[];
let waveRings = [];
let lastSpawnTime = 0;
function fire(){
if(player.ammo<=0) return;
player.ammo--;
const ang=Math.atan2(mouseY-player.y,mouseX-player.x);
const power=player.chargeTime;
bullets.push(new Bullet(player.x, player.y, ang, power));
player.x -= Math.cos(ang)*power*0.06;
player.y -= Math.sin(ang)*power*0.06;
updateUI();
}
function doubleFire(){
player.ammo--;
const ang=Math.atan2(mouseY-player.y,mouseX-player.x);
const offset = 0.18;
bullets.push(new Bullet(player.x, player.y, ang-offset, 30));
bullets.push(new Bullet(player.x, player.y, ang+offset, 30));
updateUI();
}
function spawnWave(x,y,maxRadius=80){
if(selectedSkill==="chargeBoost") maxRadius *= 1.35;
waveRings.push(new WaveRing(x,y,maxRadius));
}
function collision(a,b){
return Math.hypot(a.x-b.x,a.y-b.y)<a.size+b.size;
}
function updateUI(){
scoreEl.innerText=score;
hpEl.innerText=Math.max(0,Math.floor(player.hp));
ammoEl.innerText=player.ammo;
chargeEl.style.width = (player.chargeTime/player.maxCharge*100)+"%";
}
function resetGame(){
player.x=w/2;player.y=h/2;player.hp=100;player.ammo=15;
player.dashCD=0;player.freezeCD=0;
player.chargeTime=0;player.isCharging=false;
score=0;bullets=[];enemyBullets=[];enemies=[];drops=[];
waveRings=[];dashTrails=[];
enemyHpMultiplier = 1.0;
freezeAuraActive = false;
freezeAuraTimer = 0;
gameOn=true;
overUI.style.display="none";
lastSpawnTime = Date.now();
updateUI();
}
function gameOver(){
gameOn = false;
finalScoreEl.innerText = score;
overUI.style.display = "flex";
spawnWave(player.x,player.y,120);
}
function loop(){
ctx.save();
if(shake>0){
ctx.translate((Math.random()-0.5)*shake, (Math.random()-0.5)*shake);
shake *= 0.85;
}
ctx.fillStyle='rgba(5,5,16,0.14)';
ctx.fillRect(0,0,w,h);
if(gameStart && gameOn){
if(freezeAuraActive){
freezeAuraTimer--;
ctx.save();
ctx.globalAlpha = 0.35;
ctx.strokeStyle="#6cf";
ctx.lineWidth=3;
ctx.shadowBlur=15;
ctx.shadowColor="#6cf";
ctx.beginPath();
ctx.arc(player.x,player.y,freezeRange,0,Math.PI*2);
ctx.stroke();
ctx.restore();
enemies.forEach(e=>{
if(Math.hypot(e.x-player.x,e.y-player.y) < freezeRange){
e.frozen = true;
}
})
if(freezeAuraTimer <=0){
freezeAuraActive = false;
enemies.forEach(e=>e.frozen=false);
}
}
player.freezeCD--;
let mx=0,my=0;
if(keys['w'])my-=1;if(keys['s'])my+=1;
if(keys['a'])mx-=1;if(keys['d'])mx+=1;
if(mx||my){
const l=Math.hypot(mx,my);
mx/=l;my/=l;
player.x+=mx*player.speed;
player.y+=my*player.speed;
}
if(keys['shift'] && player.dashCD<=0 && (mx||my)){
player.x+=mx*110;
player.y+=my*110;
player.dashCD=player.dashMaxCD;
shake=6;
if(selectedSkill==="dashTrail"){
dashTrails.push(new DashTrail(player.x,player.y));
}
}
player.dashCD--;
player.x=Math.max(player.size,Math.min(w-player.size,player.x));
player.y=Math.max(player.size,Math.min(h-player.size,player.y));
if(player.isCharging && player.chargeTime<player.maxCharge){
player.chargeTime++;
}
const now = Date.now();
const spawnGap = Math.max(1200, 2200 - score*3);
if(now - lastSpawnTime > spawnGap && enemies.length < 6){
const t=Math.random()>0.45?1:0;
enemies.push(new Enemy(t));
lastSpawnTime = now;
}
for(let i=bullets.length-1;i>=0;i--){
const b=bullets[i];
b.update();b.draw();
if(b.out()){bullets.splice(i,1);continue;}
for(let j=enemies.length-1;j>=0;j--){
const e=enemies[j];
if(collision(b,e)){
e.hp -= b.damage;
if(b.isExplosive){
spawnWave(b.x,b.y,90);
enemies.forEach(ee=>{
if(Math.hypot(ee.x-b.x,ee.y-b.y)<b.splashRange) ee.hp -= b.damage*0.5;
})
}else{
enemies.forEach(ee=>{
if(ee!==e && Math.hypot(ee.x-b.x,ee.y-b.y)<b.splashRange) ee.hp -= b.damage*0.35;
})
}
if(!b.pierce){
bullets.splice(i,1);
}
if(e.hp<=0){
spawnWave(e.x,e.y,70);
score += e.type===0?15:25;
enemyHpMultiplier += 0.1; // 击杀敌人,全体敌人血量+10%
if(selectedSkill === "lifesteal"){
player.hp = Math.min(100, player.hp + 6);
}
if(Math.random()>0.4) drops.push(new Drop(e.x,e.y));
enemies.splice(j,1);
}
break;
}
}
}
for(let i=enemyBullets.length-1;i>=0;i--){
const eb=enemyBullets[i];
eb.update();eb.draw();
if(eb.out()){enemyBullets.splice(i,1);continue;}
if(collision(eb,player)){
player.hp -=12;
shake=8;
spawnWave(player.x,player.y,45);
enemyBullets.splice(i,1);
if(player.hp<=0){
gameOver();
}
updateUI();
}
}
for(let i=enemies.length-1;i>=0;i--){
const e=enemies[i];
e.update();e.draw();
if(collision(e,player)){
player.hp -=18;
shake=10;
spawnWave(player.x,player.y,45);
enemies.splice(i,1);
if(player.hp<=0){
gameOver();
}
updateUI();
}
}
for(let i=dashTrails.length-1;i>=0;i--){
const tr = dashTrails[i];
tr.update();
tr.draw();
for(let j=enemies.length-1;j>=0;j--){
const e = enemies[j];
if(Math.hypot(e.x-tr.x,e.y-tr.y) < tr.r+e.size){
e.hp -= 0.8;
if(e.hp <=0){
spawnWave(e.x,e.y,70);
score += e.type===0?15:25;
enemyHpMultiplier +=0.1;
if(selectedSkill === "lifesteal") player.hp = Math.min(100,player.hp+6);
if(Math.random()>0.4) drops.push(new Drop(e.x,e.y));
enemies.splice(j,1);
}
}
}
if(tr.done()) dashTrails.splice(i,1);
}
for(let i=drops.length-1;i>=0;i--){
const d=drops[i];
d.update();d.draw();
if(d.life<=0){drops.splice(i,1);continue;}
if(collision(d,player)){
player.ammo +=5;
drops.splice(i,1);
updateUI();
}
}
ctx.save();
ctx.translate(player.x,player.y);
const ang=Math.atan2(mouseY-player.y,mouseX-player.x);
ctx.rotate(ang);
ctx.fillStyle="#4cf";
ctx.shadowBlur=12;ctx.shadowColor="#4cf";
ctx.beginPath();
ctx.moveTo(player.size,0);
ctx.lineTo(-player.size*0.7,-player.size*0.6);
ctx.lineTo(-player.size*0.7,player.size*0.6);
ctx.closePath();
ctx.fill();
ctx.restore();
updateUI();
}
for(let i=waveRings.length-1;i>=0;i--){
const r = waveRings[i];
r.update();
r.draw();
if(r.done()) waveRings.splice(i,1);
}
ctx.restore();
requestAnimationFrame(loop);
}
updateUI();
loop();
</script>
</body>
</html>
全部评论 2
1
1周前 来自 浙江
0在哪运行
1周前 来自 山东
0新建txt,复制进去,再改回html后缀
1周前 来自 浙江
0





























有帮助,赞一个