基地静音开关:新增 b-mute 像素图标按钮、AU.applyMute 音乐闸门、mute/music 音频状态云端同步(server DEFAULT_STATE/vState 扩展,含 mute-btn.png 参考图)
This commit is contained in:
parent
d328c02366
commit
adc4fb36d3
BIN
mute-btn.png
Normal file
BIN
mute-btn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 107 KiB |
@ -102,6 +102,12 @@ h1.logo{font-size:clamp(20px,5.4vw,44px);color:#fff;letter-spacing:4px;line-heig
|
||||
#tb-pause{position:absolute;top:6px;right:6px;z-index:46;font:inherit;font-size:11px;width:40px;height:40px;
|
||||
background:rgba(16,26,51,.7);border:3px solid var(--line);color:var(--ink);letter-spacing:1px}
|
||||
#tb-pause:active{background:var(--cyan);color:#000}
|
||||
#b-mute{position:absolute;top:10px;right:10px;z-index:5;width:42px;height:42px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
background:rgba(16,26,51,.85);border:3px solid var(--line);color:var(--ink);cursor:pointer;padding:0;line-height:1}
|
||||
#b-mute canvas{image-rendering:pixelated;pointer-events:none}
|
||||
#b-mute:hover{border-color:var(--cyan);color:var(--cyan)}
|
||||
#b-mute:active{background:var(--cyan);color:#000}
|
||||
.blink{animation:blk 1s steps(2) infinite}
|
||||
@keyframes blk{50%{opacity:.25}}
|
||||
.help-list{font-size:clamp(7px,1.5vw,10px);color:var(--ink);line-height:2.2;letter-spacing:2px;text-align:left}
|
||||
|
||||
@ -63,6 +63,7 @@
|
||||
|
||||
<!-- 标题 -->
|
||||
<div class="ovl hide" id="o-title">
|
||||
<button id="b-mute" title="静音开关(跟随账号云端保存)"><canvas id="b-mute-icon" width="36" height="26"></canvas></button>
|
||||
<div class="tag">PIXEL ROGUELIKE SHMUP</div>
|
||||
<h1 class="logo">STAR<br>RAID</h1>
|
||||
<div class="logo-cn">星尘突击队</div>
|
||||
|
||||
@ -4,9 +4,11 @@ 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);
|
||||
this.mgain=this.ctx.createGain(); this.mgain.gain.value=SAVE.music?0.16:0; this.mgain.connect(this.master);
|
||||
this.mgain=this.ctx.createGain(); this.mgain.gain.value=(SAVE.mute||!SAVE.music)?0:0.16; this.mgain.connect(this.master);
|
||||
}catch(e){}
|
||||
},
|
||||
/* 音乐音量统一闸门:静音 或 音乐关 都归零(SAVE.mute 管 SFX 由 tone/noise 自查) */
|
||||
applyMute(){ if(this.mgain) this.mgain.gain.value=(SAVE.mute||!SAVE.music)?0:0.16; },
|
||||
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||this.simMute)return;
|
||||
|
||||
@ -53,7 +53,7 @@ addEventListener("keydown",e=>{
|
||||
if(GAMEKEYS.includes(e.code))e.preventDefault();
|
||||
KEYS[e.code]=true;
|
||||
AU.init(); if(AU.ctx&&AU.ctx.state==="suspended")AU.ctx.resume();
|
||||
if(e.code==="KeyM"){SAVE.music=!SAVE.music;if(AU.mgain)AU.mgain.gain.value=SAVE.music?0.16:0;persist();}
|
||||
if(e.code==="KeyM"){SAVE.music=!SAVE.music;AU.applyMute();persist();}
|
||||
if(e.code==="Escape"&&UI==="demoSim"){exitDemoSim();return;}
|
||||
if(e.code==="KeyP"||e.code==="Escape")togglePause();
|
||||
if(UI==="cards"&&["Digit1","Digit2","Digit3"].includes(e.code))pickCard(+e.code.slice(-1)-1);
|
||||
|
||||
@ -51,8 +51,11 @@ const NET = {
|
||||
SAVE.codex = {};
|
||||
SAVE.coins = 0; SAVE.ships = ["falcon"]; SAVE.m = {};
|
||||
SAVE.best = { s0: 0, s1: 0, e0: 0, e1: 0, stage: 0 }; SAVE.rush = {};
|
||||
SAVE.mute = false; SAVE.music = true; // 音频开关也防串号,恢复默认
|
||||
if (typeof SETUP !== "undefined") SETUP.ship = "falcon";
|
||||
persist();
|
||||
if (typeof updateMuteBtn === "function") updateMuteBtn();
|
||||
if (typeof AU !== "undefined") AU.applyMute();
|
||||
},
|
||||
|
||||
/* 应用服务端返回的用户数据:图鉴以服务端为准【替换】本地
|
||||
@ -72,10 +75,14 @@ const NET = {
|
||||
SAVE.m = Object.assign({}, d.state.m);
|
||||
SAVE.best = Object.assign({ s0: 0, s1: 0, e0: 0, e1: 0, stage: 0 }, d.state.best);
|
||||
SAVE.rush = Object.assign({}, d.state.rush);
|
||||
SAVE.mute = d.state.mute === true; // 音频开关跟随账号(缺省不静音)
|
||||
SAVE.music = d.state.music !== false; // 缺省音乐开
|
||||
if (d.state.ship && SAVE.ships.includes(d.state.ship) && typeof SETUP !== "undefined") SETUP.ship = d.state.ship;
|
||||
}
|
||||
persist();
|
||||
this._mutePush = false;
|
||||
if (typeof updateMuteBtn === "function") updateMuteBtn(); // 刷新基地静音按钮图标
|
||||
if (typeof AU !== "undefined") AU.applyMute();
|
||||
if (!d.state) this.pushState(); // 服务端无存档(老账号首登):把本地存档上传初始化
|
||||
},
|
||||
|
||||
@ -90,6 +97,7 @@ const NET = {
|
||||
coins: SAVE.coins, ships: SAVE.ships,
|
||||
ship: typeof SETUP !== "undefined" ? SETUP.ship : "falcon",
|
||||
m: SAVE.m, best: SAVE.best, rush: SAVE.rush || {},
|
||||
mute: !!SAVE.mute, music: SAVE.music !== false,
|
||||
} }).catch(() => { /* 网络失败静默:本地存档仍在 */ });
|
||||
}, 600);
|
||||
},
|
||||
|
||||
@ -14,6 +14,49 @@ $("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=()=>{UI="title";show("o-title");};
|
||||
/* 基地右上角:静音开关(SFX tone/noise 自查 SAVE.mute;音乐走 AU.applyMute 闸门;persist 触发云同步)
|
||||
图标为手绘像素画:开声=青喇叭+绿音波 / 静音=灰喇叭+红叉 */
|
||||
const SPK_ON=[ // 音波三根竖线:从左到右由短到长
|
||||
".....SS.........",
|
||||
"....SSS.........",
|
||||
"..SSSSS........W",
|
||||
"SSSSSSS......W.W",
|
||||
"SSSSSSSS...W.W.W",
|
||||
"SSSSSSSSS..W.W.W",
|
||||
"SSSSSSSS...W.W.W",
|
||||
"SSSSSSS......W.W",
|
||||
"..SSSSS........W",
|
||||
"....SSS.........",
|
||||
".....SS........."];
|
||||
const SPK_OFF=[
|
||||
".....SS.........",
|
||||
"....SSS.........",
|
||||
"..SSSSS.........",
|
||||
"SSSSSSS...X...X.",
|
||||
"SSSSSSSS...X.X..",
|
||||
"SSSSSSSSS...X...",
|
||||
"SSSSSSSS...X.X..",
|
||||
"SSSSSSS...X...X.",
|
||||
"..SSSSS.........",
|
||||
"....SSS.........",
|
||||
".....SS........."];
|
||||
function updateMuteBtn(){
|
||||
const c=$("b-mute-icon");if(!c)return;
|
||||
const g=c.getContext("2d");g.clearRect(0,0,c.width,c.height);
|
||||
const art=SAVE.mute?SPK_OFF:SPK_ON;
|
||||
for(let y=0;y<art.length;y++)for(let x=0;x<art[y].length;x++){
|
||||
const ch=art[y][x];if(ch===".")continue;
|
||||
g.fillStyle=SAVE.mute?(ch==="X"?"#ff5566":"#7f8cb8"):(ch==="W"?"#5cff9d":"#41e6ff");
|
||||
g.fillRect(x*2+2,y*2+2,2,2);
|
||||
}
|
||||
}
|
||||
$("b-mute").onclick=()=>{
|
||||
SAVE.mute=!SAVE.mute;persist();
|
||||
AU.init();if(AU.ctx&&AU.ctx.state==="suspended")AU.ctx.resume();
|
||||
AU.applyMute();updateMuteBtn();
|
||||
if(!SAVE.mute)SFX.pick(); // 解除静音给个反馈音(静音时 tone 自查抑制)
|
||||
};
|
||||
updateMuteBtn();
|
||||
$("b-back4").onclick=()=>{UI="title";bestLine();show("o-title");};
|
||||
$("b-back5").onclick=exitDemoSim;
|
||||
/* 图鉴测试模式(隐藏入口):连点图鉴标题“军”字10次开关。
|
||||
|
||||
@ -22,7 +22,7 @@ const RUN_MODES = new Set(["stage", "endless", "rush"]);
|
||||
const SHIP_KEYS = new Set(["falcon", "ghost", "bastion", "valkyrie", "asura"]);
|
||||
const PASSIVE_KEYS = new Set(["fire", "crit", "shield", "nano", "mag", "bounty", "odcore", "ghost"]);
|
||||
const META_MAX = { weapon: 2, armor: 2, hpup: 2, luck: 2, wallet: 3, mag2: 2, odstart: 1 };
|
||||
const DEFAULT_STATE = { coins: 0, ships: ["falcon"], ship: "falcon", m: {}, best: { s0: 0, s1: 0, e0: 0, e1: 0, stage: 0 }, rush: {} };
|
||||
const DEFAULT_STATE = { coins: 0, ships: ["falcon"], ship: "falcon", m: {}, best: { s0: 0, s1: 0, e0: 0, e1: 0, stage: 0 }, rush: {}, mute: false, music: true };
|
||||
|
||||
const qInsUser = db.prepare("INSERT INTO users(username,email,pass_hash,created_at) VALUES(?,?,?,?)");
|
||||
const qInsStats = db.prepare("INSERT OR IGNORE INTO user_stats(user_id) VALUES(?)");
|
||||
@ -76,7 +76,10 @@ function vState(s) {
|
||||
const rush = {};
|
||||
if (s.rush && typeof s.rush === "object") for (const k of Object.keys(s.rush).slice(0, 32))
|
||||
if (/^\d{1,2}$/.test(k) && vInt(s.rush[k], 0, 8640000)) rush[k] = s.rush[k];
|
||||
return { coins: s.coins, ships, ship, m, best, rush };
|
||||
/* 音频开关:缺省=不静音/音乐开(老存档无此字段) */
|
||||
const mute = s.mute === true;
|
||||
const music = s.music !== false;
|
||||
return { coins: s.coins, ships, ship, m, best, rush, mute, music };
|
||||
}
|
||||
|
||||
/* 无尽模式断点存档校验(波次检查点快照;装备 key 复用图鉴白名单) */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user