摸鱼反应堆 加强版
by CrystalPenguin76754 lines24.1 KB
<!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;-webkit-tap-highlight-color:transparent;}
body{background:#000;overflow:hidden;height:100vh;width:100vw;font-family:system-ui,sans-serif;}
canvas{display:block;width:100vw;height:100vh;}
.popup{
position:fixed;inset:0;background:rgba(0,0,0,0.88);
display:flex;align-items:center;justify-content:center;
z-index:99;
}
.box{
background:#1e1e28;color:#fff;padding:32px 24px;border-radius:18px;
width:min(88vw,380px);text-align:center;
border:1px solid #334;
}
.box h2{margin-bottom:16px;color:#0cf;font-size:24px;}
.box p{line-height:1.7;margin:10px 0;color:#ccc;font-size:15px;}
.btn{
margin-top:20px;padding:13px 24px;border:none;border-radius:10px;
background:#00e0ee;color:#000;font-size:17px;font-weight:bold;
width:100%;transition:0.15s;
}
.btn:active{opacity:0.7;scale:0.97}
.btn-sec{
margin-top:12px;background:#333;color:#fff;
}
.hidden{display:none !important;}
</style>
</head>
<body>
<canvas id="game"></canvas>
<!-- 开局引导弹窗 -->
<div id="guidePopup" class="popup">
<div class="box">
<h2>👔摸鱼反应堆 进阶版</h2>
<p>【判断老板视线】黑色虚线指向中间=盯你,千万别点!</p>
<p>虚线指向左右墙壁=安全,连续点击触发连击加分</p>
<p>【道具】随机掉落隐身/双倍分/暂停老板,触碰拾取</p>
<p>【随机事件】黑屏、极速巡查、双倍扣分,注意规避</p>
<p>⚠️紧急会议全屏变红,连点刷高额分数!</p>
<button class="btn" id="startBtn">开始60秒挑战</button>
</div>
</div>
<!-- 结算弹窗 -->
<div id="endPopup" class="popup hidden">
<div class="box">
<h2>本局结算</h2>
<p>最终能量:<span id="finalEnergy" style="color:#0cf;font-size:22px">0</span></p>
<p>被抓包次数:<span id="catchCount" style="color:#f55">0</span></p>
<p>紧急会议触发:<span id="meetingCount" style="color:#ff0">0</span></p>
<p>最高连击:<span id="maxCombo" style="color:#3f3">0</span></p>
<p>历史最高纪录:<span id="highScore" style="color:#0cf">0</span></p>
<p id="rankText" style="font-size:20px;margin:12px 0;font-weight:bold">评级:F</p>
<button class="btn" id="restartBtn">再来一局</button>
<button class="btn btn-sec" id="shareBtn">复制分享文案</button>
</div>
</div>
<script>
// 画布初始化
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
function resizeCanvas(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize',resizeCanvas);
// 音频工具
let audioCtx = null;
function initAudio(){if(!audioCtx)audioCtx = new (window.AudioContext || window.webkitAudioContext)();}
function playTone(freq,dur,type='sine',vol=0.2){
if(!audioCtx)return;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);gain.connect(audioCtx.destination);
osc.type = type;osc.frequency.value = freq;
gain.gain.setValueAtTime(vol,audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001,audioCtx.currentTime+dur);
osc.start();osc.stop(audioCtx.currentTime+dur);
}
const audio = {
success:()=>{playTone(880,0.12,'sine',0.25);playTone(1200,0.08,'sine',0.15)},
catch:()=>playTone(90,0.35,'triangle',0.35),
meeting:()=>playTone(1300,0.05,'square',0.18),
item:()=>playTone(1000,0.18,'sine',0.22),
warn:()=>playTone(220,0.2,'sawtooth',0.2)
}
// 粒子类(星光/爆炸/火花特效)
class Particle{
constructor(x,y,color,spdX,spdY,life,size){
this.x=x;this.y=y;this.color=color;
this.spdX=spdX;this.spdY=spdY;
this.life=life;this.maxLife=life;this.size=size;
}
update(){
this.x+=this.spdX;
this.y+=this.spdY;
this.life--;
this.spdY+=0.02;
}
draw(){
const a=this.life/this.maxLife;
ctx.globalAlpha=a;
ctx.fillStyle=this.color;
ctx.beginPath();
ctx.arc(this.x,this.y,this.size*a,0,Math.PI*2);
ctx.fill();
ctx.globalAlpha=1;
}
}
let particles=[];
function spawnParticles(x,y,color,count){
for(let i=0;i<count;i++){
const spdX=(Math.random()-0.5)*4;
const spdY=(Math.random()-0.5)*4-2;
const life=30+Math.random()*40;
const size=2+Math.random()*4;
particles.push(new Particle(x,y,color,spdX,spdY,life,size));
}
}
// 道具类
class Item{
constructor(){
this.types=['hide','shield','double','pause'];
this.type=this.types[Math.floor(Math.random()*4)];
this.x=80+Math.random()*(canvas.width-160);
this.y=canvas.height*0.35+Math.random()*canvas.height*0.3;
this.r=22;
this.life=600;
const map={
hide:{name:'隐身',col:'#8cf'},
shield:{name:'护盾',col:'#4f4'},
double:{name:'双倍分',col:'#ff0'},
pause:{name:'暂停老板',col:'#f8f'}
}
this.name=map[this.type].name;
this.col=map[this.type].col;
}
draw(){
ctx.fillStyle=this.col;
ctx.shadowColor=this.col;
ctx.shadowBlur=12;
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2);
ctx.fill();
ctx.shadowBlur=0;
ctx.fillStyle='#000';
ctx.font='bold 13px system-ui';
ctx.textAlign='center';
ctx.fillText(this.name,this.x,this.y+5);
}
}
let dropItems=[];
// 游戏全局状态
const game = {
running:false,timeLeft:60,energy:0,maxEnergy:100,
catchTimes:0,meetingTimes:0,highScore:parseInt(localStorage.getItem('fishHigh'))||0,
combo:0,maxCombo:0,stage:1,//阶段1/2/3 提升难度
reactor:{x:0,y:0,baseR:70,pulse:0,pulseSpeed:0.06,meetingShake:0,level:1},
boss:{x:0,y:60,w:80,speed:0.6,baseSpeed:0.6,dir:1,
lookDir:'front',lookTransition:0.3,lookTimer:0,expression:'normal'
},
emergency:{active:false,duration:4000,timer:0,nextTimer:0,nextDelay:0},
floatTexts:[],flashRed:0,
//道具buff
buff:{hide:0,shield:0,double:0,pauseBoss:0},
//随机全局事件
event:{type:null,timer:0},
deskItems:[]//办公桌装饰
};
// 弹窗DOM
const guidePopup = document.getElementById('guidePopup');
const endPopup = document.getElementById('endPopup');
const startBtn = document.getElementById('startBtn');
const restartBtn = document.getElementById('restartBtn');
const shareBtn = document.getElementById('shareBtn');
const finalEnergyEl = document.getElementById('finalEnergy');
const catchCountEl = document.getElementById('catchCount');
const meetingCountEl = document.getElementById('meetingCount');
const maxComboEl = document.getElementById('maxCombo');
const highScoreEl = document.getElementById('highScore');
const rankText = document.getElementById('rankText');
// 生成办公桌静态装饰
function createDeskItems(){
game.deskItems=[
{type:'paper',x:60,y:canvas.height-120,w:50,h:65},
{type:'cup',x:canvas.width-90,y:canvas.height-100,r:18},
{type:'mouse',x:canvas.width/2+120,y:canvas.height-80,w:30,h:20},
{type:'clock',x:canvas.width-70,y:110,r:24}
]
}
// 重置游戏数据
function resetGame(){
game.running = true;
game.timeLeft = 60;
game.energy = 0;
game.catchTimes = 0;
game.meetingTimes = 0;
game.combo = 0;
game.maxCombo = 0;
game.stage = 1;
game.floatTexts = [];
game.flashRed = 0;
particles=[];
dropItems=[];
game.emergency.active = false;
game.reactor.x = canvas.width/2;
game.reactor.y = canvas.height/2;
game.reactor.pulse = 0;
game.reactor.level = 1;
game.boss.x = game.boss.w;
game.boss.dir = 1;
game.boss.lookDir = 'front';
game.boss.lookTimer = 0;
game.boss.speed=game.boss.baseSpeed;
game.buff={hide:0,shield:0,double:0,pauseBoss:0};
game.event={type:null,timer:0};
createDeskItems();
// 随机8-12秒触发第一次紧急会议
game.emergency.nextDelay = 8000 + Math.random()*4000;
game.emergency.nextTimer = 0;
}
// 开始游戏
startBtn.addEventListener('click',()=>{
initAudio();
guidePopup.classList.add('hidden');
resetGame();
requestAnimationFrame(gameLoop);
});
restartBtn.addEventListener('click',()=>{
endPopup.classList.add('hidden');
resetGame();
requestAnimationFrame(gameLoop);
});
shareBtn.addEventListener('click',async ()=>{
const text = `我在摸鱼反应堆里攒了${game.energy}点能量,最高连击${game.maxCombo},你敢挑战吗?`;
await navigator.clipboard.writeText(text);
alert('分享文案已复制!');
});
// 绘制办公桌装饰
function drawDesk(){
game.deskItems.forEach(d=>{
ctx.save();
if(d.type==='paper'){
ctx.fillStyle='#333444';
ctx.fillRect(d.x,d.y,d.w,d.h);
ctx.strokeStyle='#555';
ctx.lineWidth=1;
ctx.strokeRect(d.x,d.y,d.w,d.h);
}else if(d.type==='cup'){
ctx.fillStyle='#224';
ctx.beginPath();
ctx.arc(d.x,d.y,d.r,0,Math.PI*2);
ctx.fill();
}else if(d.type==='mouse'){
ctx.fillStyle='#222';
ctx.fillRect(d.x,d.y,d.w,d.h);
}else if(d.type==='clock'){
ctx.fillStyle='#222';
ctx.beginPath();
ctx.arc(d.x,d.y,d.r,0,Math.PI*2);
ctx.fill();
ctx.fillStyle='#fff';
ctx.font='bold 14px sans-serif';
ctx.textAlign='center';
ctx.fillText('60',d.x,d.y+5);
}
ctx.restore();
})
}
// 优化版老板绘制:表情+旋转头部+视线射线+红光警告
function drawBoss(){
const b = game.boss;
if(game.buff.pauseBoss>0) ctx.globalAlpha=0.4;
ctx.save();
ctx.translate(b.x,b.y);
const size = b.w;
let rotateAngle = 0;
let rayEndX = 0, rayEndY = -size * 4;
// 表情匹配视线
if(b.lookDir==='front') b.expression='angry';
else b.expression='relax';
if(b.lookDir === "left"){
rotateAngle = -Math.PI / 6;
rayEndX = -canvas.width * 0.6;
}else if(b.lookDir === "right"){
rotateAngle = Math.PI / 6;
rayEndX = canvas.width * 0.6;
}else{
rayEndX = canvas.width/2 - b.x;
rayEndY = canvas.height/2 - b.y;
}
// 正视愤怒红光高亮
if(b.lookDir === "front"){
ctx.shadowColor = "#ff2222";
ctx.shadowBlur = 22;
}
// 西装身体
ctx.fillStyle='#223';
ctx.fillRect(-size/2,-size/2,size,size*0.8);
// 头部旋转容器
ctx.save();
ctx.rotate(rotateAngle);
// 脸部底色
ctx.fillStyle='#ffe0cc';
ctx.beginPath();ctx.arc(0,-size*0.35,size*0.22,0,Math.PI*2);ctx.fill();
// 领带
ctx.fillStyle='#d22';
ctx.beginPath();
ctx.moveTo(0,-size*0.1);
ctx.lineTo(-size*0.08,size*0.3);
ctx.lineTo(size*0.08,size*0.3);
ctx.closePath();ctx.fill();
// 眼睛&表情
ctx.fillStyle='#000';
const eyeY = -size*0.38;
const eyeBaseOffset = size*0.08;
if(b.lookDir === 'left'){
ctx.beginPath();
ctx.arc(-eyeBaseOffset - 8, eyeY, 4, 0, Math.PI*2);
ctx.arc(eyeBaseOffset - 12, eyeY, 4, 0, Math.PI*2);
ctx.fill();
}else if(b.lookDir === 'right'){
ctx.beginPath();
ctx.arc(-eyeBaseOffset + 12, eyeY, 4, 0, Math.PI*2);
ctx.arc(eyeBaseOffset + 8, eyeY, 4, 0, Math.PI*2);
ctx.fill();
}else{
ctx.beginPath();
ctx.arc(-eyeBaseOffset, eyeY, 4, 0, Math.PI*2);
ctx.arc(eyeBaseOffset, eyeY, 4, 0, Math.PI*2);
ctx.fill();
// 愤怒眉毛
ctx.strokeStyle='#000';
ctx.lineWidth=2;
ctx.beginPath();
ctx.moveTo(-eyeBaseOffset-6,eyeY-8);
ctx.lineTo(-eyeBaseOffset+6,eyeY-5);
ctx.moveTo(eyeBaseOffset+6,eyeY-8);
ctx.lineTo(eyeBaseOffset-6,eyeY-5);
ctx.stroke();
}
// 嘴巴区分表情
ctx.strokeStyle='#111';
ctx.lineWidth=2;
ctx.beginPath();
if(b.expression==='angry') ctx.arc(0,-size*0.22,6,0,Math.PI);
else ctx.arc(0,-size*0.22,5,Math.PI,Math.PI*2);
ctx.stroke();
ctx.restore();
// 视线虚线
ctx.strokeStyle = "rgba(0,0,0,0.75)";
ctx.lineWidth = 3;
ctx.setLineDash([8,6]);
ctx.beginPath();
ctx.moveTo(0, -size*0.35);
ctx.lineTo(rayEndX, rayEndY);
ctx.stroke();
ctx.setLineDash([]);
ctx.shadowBlur = 0;
ctx.restore();
ctx.globalAlpha=1;
}
// 反应堆分层绘制,随等级升级外观
function drawReactor(){
const r = game.reactor;
let pulseScale = 1 + Math.sin(r.pulse)*0.12;
if(game.emergency.active) pulseScale = 1 + Math.sin(r.pulse*3)*0.25;
const radius = r.baseR * pulseScale;
const shakeX = game.emergency.active ? (Math.random()-0.5)*r.meetingShake : 0;
const shakeY = game.emergency.active ? (Math.random()-0.5)*r.meetingShake : 0;
const cx = r.x + shakeX;
const cy = r.y + shakeY;
// 渐变分层升级
let grad;
if(game.emergency.active){
grad = ctx.createRadialGradient(cx,cy,0,cx,cy,radius);
grad.addColorStop(0,'#ffdd00');
grad.addColorStop(1,'#ff4400');
}else if(r.level>=3){
grad = ctx.createRadialGradient(cx,cy,0,cx,cy,radius);
grad.addColorStop(0,'#0ff');
grad.addColorStop(0.6,'#08f');
grad.addColorStop(1,'#003');
}else if(r.level>=2){
grad = ctx.createRadialGradient(cx,cy,0,cx,cy,radius);
grad.addColorStop(0,'#0cf');
grad.addColorStop(1,'#004');
}else{
grad = ctx.createRadialGradient(cx,cy,0,cx,cy,radius);
grad.addColorStop(0,'#00f0ff');
grad.addColorStop(1,'#002266');
}
ctx.beginPath();
ctx.arc(cx,cy,radius,0,Math.PI*2);
ctx.fillStyle = grad;
ctx.fill();
// 多层发光
const glowSize=15+r.level*8;
ctx.shadowColor = game.emergency.active ? '#ff7700' : '#0cf';
ctx.shadowBlur = glowSize;
ctx.strokeStyle = '#fff';
ctx.lineWidth = 2;
ctx.stroke();
ctx.shadowBlur = 0;
// 能量文字+连击
let energyColor;
if(game.energy < 30) energyColor = '#f33';
else if(game.energy < 70) energyColor = '#fc0';
else energyColor = '#3f3';
ctx.fillStyle = energyColor;
ctx.font = 'bold 32px system-ui';
ctx.textAlign = 'center';
ctx.fillText(game.energy + '/' + game.maxEnergy, cx, cy - radius - 16);
if(game.combo>1){
ctx.fillStyle='#ff0';
ctx.font='bold 18px sans-serif';
ctx.fillText(`连击×${game.combo}`,cx,cy-radius-42);
}
}
// 浮动分数文字
function drawFloatText(){
game.floatTexts.forEach((t,i)=>{
ctx.fillStyle = t.color;
ctx.font = 'bold 28px system-ui';
ctx.textAlign = 'center';
ctx.globalAlpha = t.alpha;
ctx.fillText(t.text,t.x,t.y);
ctx.globalAlpha = 1;
t.y -= 1.4;
t.alpha -= 0.02;
if(t.alpha <= 0) game.floatTexts.splice(i,1);
})
}
// 绘制掉落道具
function drawItems(){
dropItems.forEach((item,idx)=>{
item.life--;
if(item.life<=0){dropItems.splice(idx,1);return;}
item.draw();
// 检测反应堆拾取碰撞
const d=Math.hypot(item.x-game.reactor.x,item.y-game.reactor.y);
if(d<game.reactor.baseR+item.r){
// 触发buff
audio.item();
switch(item.type){
case 'hide':game.buff.hide=300;break;
case 'shield':game.buff.shield=1;break;
case 'double':game.buff.double=240;break;
case 'pause':game.buff.pauseBoss=200;break;
}
spawnParticles(item.x,item.y,item.col,18);
dropItems.splice(idx,1);
}
})
}
// UI面板
function drawUI(){
// 剩余时间 左上
ctx.fillStyle='#fff';
ctx.font='bold 22px system-ui';
ctx.textAlign='left';
ctx.fillText(`剩余:${Math.ceil(game.timeLeft)}s`,20,36);
// 当前能量 右上
ctx.textAlign='right';
ctx.fillText(`能量:${game.energy}/${game.maxEnergy}`,canvas.width-20,36);
// Buff提示
let buffY=68;
ctx.font='16px sans-serif';
ctx.textAlign='left';
if(game.buff.hide>0){ctx.fillStyle='#8cf';ctx.fillText(`隐身 ${Math.ceil(game.buff.hide/60)}s`,20,buffY);buffY+=24;}
if(game.buff.double>0){ctx.fillStyle='#ff0';ctx.fillText(`双倍得分 ${Math.ceil(game.buff.double/60)}s`,20,buffY);buffY+=24;}
if(game.buff.pauseBoss>0){ctx.fillStyle='#f8f';ctx.fillText(`老板暂停 ${Math.ceil(game.buff.pauseBoss/60)}s`,20,buffY);buffY+=24;}
if(game.buff.shield>0){ctx.fillStyle='#4f4';ctx.fillText(`护盾生效`,20,buffY);buffY+=24;}
}
// 背景绘制+随机事件遮罩
function drawBg(){
// 主桌面底色
const gradBg=ctx.createLinearGradient(0,0,0,canvas.height);
gradBg.addColorStop(0,'#14141a');
gradBg.addColorStop(1,'#1a1a24');
ctx.fillStyle=gradBg;
ctx.fillRect(0,0,canvas.width,canvas.height);
// 磨砂噪点
ctx.fillStyle='rgba(255,255,255,0.02)';
for(let i=0;i<150;i++){
const x = Math.random()*canvas.width;
const y = Math.random()*canvas.height;
ctx.fillRect(x,y,2,2);
}
// 随机事件遮罩
if(game.event.type==='blackout'){
ctx.fillStyle=`rgba(0,0,0,${game.event.timer/120*0.85})`;
ctx.fillRect(0,0,canvas.width,canvas.height);
}
// 被抓红闪
if(game.flashRed>0){
ctx.fillStyle=`rgba(255,40,40,${game.flashRed*0.35})`;
ctx.fillRect(0,0,canvas.width,canvas.height);
game.flashRed -= 0.04;
}
// 紧急会议红边框
if(game.emergency.active){
ctx.strokeStyle='#f22';
ctx.lineWidth=10;
ctx.strokeRect(4,4,canvas.width-8,canvas.height-8);
}
}
// 点击交互
function handleTap(touchX,touchY){
if(!game.running)return;
const r = game.reactor;
const dist = Math.hypot(touchX - r.x, touchY - r.y);
const hitRadius = r.baseR + 50;
if(dist > hitRadius) return;
// 黑屏事件屏蔽点击
if(game.event.type==='blackout') return;
if(game.emergency.active){
let add=5;
if(game.buff.double>0) add*=2;
game.energy = Math.min(game.energy+add,game.maxEnergy);
game.floatTexts.push({
text:`+${add}`,x:r.x,y:r.y-40,color:'#ff0',alpha:1
});
spawnParticles(r.x,r.y,'#ff0',12);
audio.meeting();
return;
}
const bossLook = game.boss.lookDir;
if(bossLook === 'front' && game.buff.hide<=0){
// 被抓包,护盾抵消一次
if(game.buff.shield>0){
game.buff.shield=0;
game.floatTexts.push({text:'护盾抵挡!',x:r.x,y:r.y-40,color:'#4f4',alpha:1});
spawnParticles(r.x,r.y,'#4f4',15);
return;
}
game.energy = Math.max(game.energy-2,0);
game.catchTimes++;
game.combo=0;
game.flashRed = 1;
game.floatTexts.push({
text:'-2',x:r.x,y:r.y-40,color:'#f33',alpha:1
});
spawnParticles(r.x,r.y,'#f33',22);
audio.catch();
// 双倍扣分事件
if(game.event.type==='doublePenalty'){
game.energy=Math.max(game.energy-2,0);
game.floatTexts.push({text:'双倍扣分!',x:r.x,y:r.y-70,color:'#f00',alpha:1});
}
}else{
// 摸鱼成功连击
game.combo++;
if(game.combo>game.maxCombo) game.maxCombo=game.combo;
let add=2;
if(game.combo>=5) add+=1;
if(game.buff.double>0) add*=2;
game.energy = Math.min(game.energy+add,game.maxEnergy);
game.floatTexts.push({
text:`+${add}`,x:r.x,y:r.y-40,color:'#3f3',alpha:1
});
spawnParticles(r.x,r.y,'#0ff',10);
audio.success();
// 反应堆升级
if(game.energy>=30&&game.reactor.level<2) game.reactor.level=2;
if(game.energy>=70&&game.reactor.level<3) game.reactor.level=3;
}
}
// 触摸绑定
canvas.addEventListener('touchstart',e=>{
e.preventDefault();
const t = e.touches[0];
handleTap(t.clientX,t.clientY);
})
canvas.addEventListener('mousedown',e=>handleTap(e.clientX,e.clientY));
// 随机全局事件生成
function spawnRandomEvent(){
const evts=['blackout','fastBoss','doublePenalty'];
const sel=evts[Math.floor(Math.random()*3)];
game.event.type=sel;
game.event.timer=180;
audio.warn();
}
// 主游戏循环
let lastTime = 0;
let itemSpawnTimer=0;
let eventSpawnTimer=0;
function gameLoop(ts){
const dt = (ts - lastTime)/1000;
lastTime = ts;
if(!game.running)return;
// 倒计时
game.timeLeft -= dt;
if(game.timeLeft <= 0){
game.running = false;
if(game.energy > game.highScore){
game.highScore = game.energy;
localStorage.setItem('fishHigh',game.highScore);
}
// 结算评级
let rank='F';
if(game.energy>=90)rank='SS';
else if(game.energy>=70)rank='S';
else if(game.energy>=50)rank='A';
else if(game.energy>=30)rank='B';
else if(game.energy>=10)rank='C';
// 赋值弹窗
finalEnergyEl.textContent = game.energy;
catchCountEl.textContent = game.catchTimes;
meetingCountEl.textContent = game.meetingTimes;
maxComboEl.textContent = game.maxCombo;
highScoreEl.textContent = game.highScore;
rankText.textContent=`评级:${rank}`;
endPopup.classList.remove('hidden');
return;
}
// 阶段难度升级
if(game.timeLeft<40&&game.stage===1){game.stage=2;game.boss.speed=game.boss.baseSpeed*1.4;}
if(game.timeLeft<20&&game.stage===2){game.stage=3;game.boss.speed=game.boss.baseSpeed*1.8;}
// Buff倒计时
if(game.buff.hide>0)game.buff.hide--;
if(game.buff.double>0)game.buff.double--;
if(game.buff.pauseBoss>0)game.buff.pauseBoss--;
// 随机事件计时
if(game.event.timer>0){
game.event.timer--;
if(game.event.timer<=0) game.event.type=null;
}
eventSpawnTimer+=dt;
if(eventSpawnTimer>12&&!game.event.type&&!game.emergency.active){
spawnRandomEvent();
eventSpawnTimer=0;
}
// 道具生成
itemSpawnTimer+=dt;
if(itemSpawnTimer>7&&dropItems.length<3){
dropItems.push(new Item());
itemSpawnTimer=0;
}
// 反应堆脉动
game.reactor.pulse += game.reactor.pulseSpeed;
// 老板移动逻辑(暂停buff阻断)
const b = game.boss;
if(game.buff.pauseBoss<=0){
b.x += b.speed * b.dir;
const boundRight = canvas.width - b.w/2;
const boundLeft = b.w/2;
if(b.x >= boundRight){
b.dir = -1;
b.lookDir = 'right';
}else if(b.x <= boundLeft){
b.dir = 1;
b.lookDir = 'left';
}else{
b.lookTimer += dt;
let switchGap;
if(game.stage===1) switchGap=2.2+Math.random()*1.8;
else if(game.stage===2) switchGap=1.4+Math.random()*1.2;
else switchGap=0.8+Math.random()*0.8;
if(b.lookTimer > switchGap){
b.lookDir = 'front';
setTimeout(()=>{
if(b.dir>0)b.lookDir='left';
else b.lookDir='right';
},b.lookTransition*1000);
b.lookTimer = 0;
}
}
}
// 紧急会议计时器
game.emergency.nextTimer += dt*1000;
if(!game.emergency.active && game.emergency.nextTimer >= game.emergency.nextDelay){
game.emergency.active = true;
game.emergency.timer = game.emergency.duration;
game.meetingTimes++;
}
if(game.emergency.active){
game.emergency.timer -= dt*1000;
if(game.emergency.timer <= 0){
game.emergency.active = false;
game.emergency.nextTimer = 0;
game.emergency.nextDelay = 8000 + Math.random()*4000;
}
}
// 更新粒子
particles.forEach((p,i)=>{
p.update();
if(p.life<=0) particles.splice(i,1);
})
// 渲染顺序
drawBg();
drawDesk();
drawReactor();
if(!game.emergency.active) drawBoss();
drawItems();
particles.forEach(p=>p.draw());
drawFloatText();
drawUI();
requestAnimationFrame(gameLoop);
}
</script>
</body>
</html>Game Source: 摸鱼反应堆 加强版
Creator: CrystalPenguin76
Libraries: none
Complexity: complex (754 lines, 24.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-crystalpenguin76-mr1i0krp" to link back to the original. Then publish at arcadelab.ai/publish.