diff --git a/AGENTS.md b/AGENTS.md index 7b1f7da..1a7a0bc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -96,6 +96,6 @@ star-raid/ - 客户端流程:boot → `/api/me` → 未登录 o-auth(登陆/注册)→ 已登录 o-home(大厅:用户面板+排行榜)→ o-title(基地菜单) - 结算上报:`submitRun()`(ui.js)在 endRun 与 rush 胜利(enemies.js killBoss)两处调用;`G.submitted` 防重 - 图鉴:服务端 `codex_unlocks` 为准,登陆时与本地 SAVE.codex 并集合并;未收集=剪影+???不可演示 -- 背景规则:render() 只在 battleUI()(play/demoSim/pause/cards/over/slot)绘制游戏对象;大厅 UI="home" 时 drawHomeShowcase()(30s 重抽);其余=星空 +- 背景规则:render() 用 battleUI() 门控;**主页/基地背景=实战模拟**(home.js startHomeSim:随机3主Lv3+3副Lv3+2僚Lv2,G.homeSim 标记,复用 demoSim 自动驾驶刷怪,AU.simMute 静音,不伤/不计分/不上报,主循环看门狗自动重建);其余空闲=星空。离场必须 G=null(b-home/b-quit/buildRush 已处理) - 新增装备时必须同步 `server/api.js` 的 CODEX_KEYS 白名单(现 24+17+13+8=62) - 星币/机库/机体仍存 localStorage 不同步(v1 边界,见 DEPLOY.md) diff --git a/star-raid/css/style.css b/star-raid/css/style.css index 33ae25b..7b87768 100644 --- a/star-raid/css/style.css +++ b/star-raid/css/style.css @@ -26,6 +26,7 @@ canvas#game{width:100%;height:100%;display:block;image-rendering:pixelated;image .ovl{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;align-items:center;justify-content:center; background:rgba(4,7,16,.88); text-align:center; padding:4%; gap:10px; overflow-y:auto} .ovl.hide{display:none} +#o-title{background:rgba(4,7,16,.5)} /* 半透明:露出背后实战模拟 */ h1.logo{font-size:clamp(20px,5.4vw,44px);color:#fff;letter-spacing:4px;line-height:1.35; text-shadow:3px 3px 0 var(--mag), -3px -3px 0 var(--cyan), 0 0 24px rgba(65,230,255,.6)} .logo-cn{font-size:clamp(12px,2.6vw,20px);color:var(--gold);letter-spacing:12px;text-shadow:2px 2px 0 #7a4b00} @@ -127,7 +128,7 @@ h1.logo{font-size:clamp(20px,5.4vw,44px);color:#fff;letter-spacing:4px;line-heig .auth-f .btn{width:100%;min-width:0;margin-top:2px} /* ---------- 飞行员大厅 ---------- */ #o-home{background:rgba(4,7,16,.42);justify-content:flex-start;gap:8px;overflow-y:auto} -#o-home .lb{width:min(94%,430px);background:var(--panel);border:3px solid var(--line);padding:10px 10px 8px;margin-top:auto;margin-bottom:2%} +#o-home .lb{width:min(94%,430px);flex:1;min-height:0;display:flex;flex-direction:column;background:var(--panel);border:3px solid var(--line);padding:10px 10px 8px;margin-bottom:2%} .lb-tabs{display:flex;gap:6px;justify-content:center;margin:6px 0 8px} .lb-tabs button{font:inherit;font-size:clamp(7px,1.3vw,9px);background:var(--panel2);color:var(--dim); border:2px solid var(--line);padding:6px 10px;cursor:pointer;letter-spacing:1px} @@ -138,5 +139,5 @@ h1.logo{font-size:clamp(20px,5.4vw,44px);color:#fff;letter-spacing:4px;line-heig .lb-row span:first-child{color:var(--dim)} .lb-row.lb-head{color:var(--dim);border-bottom:2px solid var(--line)} .lb-row.me{background:rgba(65,230,255,.12);outline:1px solid rgba(65,230,255,.35)} -.lb-list{max-height:34%;min-height:60px;overflow-y:auto} +.lb-list{flex:1;min-height:100px;overflow-y:auto} .lb-empty{color:var(--dim);font-size:clamp(7px,1.3vw,9px);padding:14px 0;letter-spacing:2px} diff --git a/star-raid/js/audio.js b/star-raid/js/audio.js index 809cc64..8136c58 100644 --- a/star-raid/js/audio.js +++ b/star-raid/js/audio.js @@ -1,6 +1,6 @@ "use strict"; /* ---------------- 音频:程序化合成 ---------------- */ -const AU={ctx:null,master:null,mgain:null, +const AU={ctx:null,master:null,mgain:null,simMute:false, init(){ if(this.ctx) return; try{ this.ctx=new (window.AudioContext||window.webkitAudioContext)(); this.master=this.ctx.createGain(); this.master.gain.value=0.5; this.master.connect(this.ctx.destination); @@ -9,12 +9,12 @@ const AU={ctx:null,master:null,mgain:null, }, now(){return this.ctx?this.ctx.currentTime:0;}, env(g,t,a,d,v){g.gain.setValueAtTime(0,t);g.gain.linearRampToValueAtTime(v,t+a);g.gain.exponentialRampToValueAtTime(0.001,t+a+d);}, - tone(f,type,dur,vol=0.2,slide=0){ if(!this.ctx||SAVE.mute)return; + tone(f,type,dur,vol=0.2,slide=0){ if(!this.ctx||SAVE.mute||this.simMute)return; const t=this.now(),o=this.ctx.createOscillator(),g=this.ctx.createGain(); o.type=type;o.frequency.setValueAtTime(f,t); if(slide) o.frequency.exponentialRampToValueAtTime(Math.max(20,f+slide),t+dur); this.env(g,t,0.005,dur,vol); o.connect(g);g.connect(this.master); o.start(t);o.stop(t+dur+0.05); }, - noise(dur,vol=0.25,hp=400){ if(!this.ctx||SAVE.mute)return; + noise(dur,vol=0.25,hp=400){ if(!this.ctx||SAVE.mute||this.simMute)return; const t=this.now(),len=Math.floor(this.ctx.sampleRate*dur),buf=this.ctx.createBuffer(1,len,this.ctx.sampleRate),d=buf.getChannelData(0); for(let i=0;i 1800) rollHomeShow(); // 30 秒重抽一轮 - const hs = HOME_SHOW; - hs.t += dt; - /* 展柜:3主武+3副武+2僚机,两排漂浮 */ - const items = [ - ...hs.m.map((k) => ({ d: WEAPONS[k] })), - ...hs.s.map((k) => ({ d: SUBS[k] })), - ...hs.d.map((k) => ({ d: DRONES[k] })), - ]; - ctx.textAlign = "center"; - items.forEach((it, i) => { - const col = i % 4, row = (i / 4) | 0; - const x = W / 2 + (col - 1.5) * 56; - const y = 118 + row * 52 + Math.sin(hs.t * 0.03 + i * 1.7) * 2.5; - const img = it.d.icon ? ICONS[it.d.icon] : SPR[it.d.spr]; - if (img) { - ctx.globalAlpha = 0.85; - ctx.drawImage(img, x - img.width * 1.5, y - img.height * 1.5, img.width * 3, img.height * 3); - ctx.globalAlpha = 1; - } - ctx.font = "6px 'Press Start 2P',monospace"; - ctx.fillStyle = "#7f8cb8"; - ctx.fillText(it.d.name, x, y + 22); - }); - /* 随机刷怪:从顶部飘入,正弦摆动 */ - hs.spawnT -= dt; - if (hs.spawnT <= 0 && hs.mobs.length < 8) { - hs.spawnT = rndi(50, 110); - const ty = pick(HOME_MOB_TYPES), elite = Math.random() < 0.2; - const spr = SPR[(elite ? "e_" : "") + ty] || SPR[ty] || SPR.scout; - hs.mobs.push({ x: rnd(20, W - 20), y: -16, vy: rnd(0.25, 0.6), ph: rnd(0, TAU), amp: rnd(6, 26), spr, sc: elite ? 1.8 : 1.3, t: 0 }); - } - for (const m of hs.mobs) { - m.t += dt; - m.y += m.vy * dt; - const mx = m.x + Math.sin(m.t * 0.02 + m.ph) * m.amp; - ctx.globalAlpha = 0.8; - ctx.drawImage(m.spr, mx - (m.spr.width * m.sc) / 2, m.y - (m.spr.height * m.sc) / 2, m.spr.width * m.sc, m.spr.height * m.sc); - ctx.globalAlpha = 1; - } - hs.mobs = hs.mobs.filter((m) => m.y < H + 24); +/* ---------- 大厅/基地背景:实战模拟 ---------- + 复用真实战斗引擎:随机 3主武Lv3 + 3副武Lv3 + 2僚机Lv2,自动驾驶,随机刷怪。 + 与图鉴演示同源(G.demoSim 真值→自动走位/无HUD/demoSpawn),G.homeSim 标记用于静音与渲染门控 */ +function startHomeSim() { + newRun("stage", "falcon", 0); + const build = rollRushBuild(); // 与BOSS挑战同款随机武装 + G.weapons = {}; build.m.forEach((k) => (G.weapons[k] = 3)); G.loadout = build.m.slice(); + G.subs = {}; build.s.forEach((k) => (G.subs[k] = 3)); G.subLoadout = build.s.slice(); + G.drones = {}; build.d.forEach((k) => (G.drones[k] = 2)); G.droneLoadout = build.d.slice(); + G.xpNeed = 1e9; // 不升级打断 + G.p.inv = 999999; // 背景模拟:玩家无伤 + G.demoSim = { home: true }; + G.homeSim = true; } diff --git a/star-raid/js/render.js b/star-raid/js/render.js index d99e788..1685816 100644 --- a/star-raid/js/render.js +++ b/star-raid/js/render.js @@ -232,13 +232,12 @@ function drawSeg(x1,y1,x2,y2,w,col,alpha){ ctx.fillRect(Math.round(lerp(x1,x2,t2)-w/2),Math.round(lerp(y1,y2,t2)-w/2),w,w);} ctx.globalAlpha=1; } -/* 战斗相关界面才绘制游戏对象;大厅/标题/登陆页只画星空(修复:回基地后背景卡在上场残影) */ -function battleUI(){return UI==="play"||UI==="demoSim"||UI==="pause"||UI==="cards"||UI==="over"||UI==="slot";} +/* 战斗相关界面才绘制游戏对象;大厅/标题跑实战模拟背景(修复:回基地后背景卡在上场残影) */ +function battleUI(){return UI==="play"||UI==="demoSim"||UI==="pause"||UI==="cards"||UI==="over"||UI==="slot"||!!(G&&G.homeSim&&(UI==="home"||UI==="title"));} function render(){ ctx.save(); if(G&&G.shake>0){ctx.translate(rnd(-G.shake,G.shake)*0.5,rnd(-G.shake,G.shake)*0.5);} drawBG(1); - if(UI==="home"&&typeof drawHomeShowcase==="function")drawHomeShowcase(1); if(G&&battleUI()){ // 拾取物 for(const k of G.picks){const bob=Math.sin(k.t*0.1)*1.5;drawSprite(SPR[k.spr],k.x,k.y+bob);} @@ -469,7 +468,10 @@ function loop(ts){ requestAnimationFrame(loop); const dt=Math.min(100,ts-last);last=ts; MUS.tick(); - if(UI==="play"||UI==="demoSim"){ + // 主页/基地背景=实战模拟(自动驾驶随机武装打怪);离开即销毁,永不计分 + if((UI==="home"||UI==="title")&&(!G||!G.homeSim)&&typeof startHomeSim==="function")startHomeSim(); + AU.simMute=!!(G&&G.homeSim); // 背景模拟战静音 + if(UI==="play"||UI==="demoSim"||(G&&G.homeSim&&(UI==="home"||UI==="title"))){ acc+=dt; let steps=0; while(acc>=1000/60&&steps<4){update();acc-=1000/60;steps++;} diff --git a/star-raid/js/ui.js b/star-raid/js/ui.js index 6fc7ffa..bd58576 100644 --- a/star-raid/js/ui.js +++ b/star-raid/js/ui.js @@ -13,8 +13,8 @@ $("b-back2").onclick=()=>show("o-title"); $("b-hangar").onclick=()=>{AU.init();buildShop();show("o-hangar");}; $("b-codex").onclick=()=>{AU.init();buildCodex();show("o-codex");}; $("b-rush").onclick=()=>{AU.init();buildRush();show("o-rush");}; -$("b-back6").onclick=()=>show("o-title"); -$("b-back4").onclick=()=>{bestLine();show("o-title");}; +$("b-back6").onclick=()=>{UI="title";show("o-title");}; +$("b-back4").onclick=()=>{UI="title";bestLine();show("o-title");}; $("b-back5").onclick=exitDemoSim; $("b-start").onclick=()=>startGame(); if("ontouchstart" in window){const pb=$("tb-pause");pb.style.display="block";pb.onclick=()=>togglePause();}