diff --git a/_server/config.json b/_server/config.json index 84aac55..e97cbbe 100644 --- a/_server/config.json +++ b/_server/config.json @@ -1 +1 @@ -{"viewportLoc":[0,0],"editorLastFloorId":"street02"} \ No newline at end of file +{"viewportLoc":[0,0],"editorLastFloorId":"KTV"} \ No newline at end of file diff --git a/_server/table/data.comment.js b/_server/table/data.comment.js index b6c921a..3a76bd7 100644 --- a/_server/table/data.comment.js +++ b/_server/table/data.comment.js @@ -102,7 +102,7 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { "_range": "editor.mode.checkUnique(thiseval)", "_directory": "./project/sounds/", "_transform": (function (one) { - if (one.endsWith('.mp3') || one.endsWith('.ogg') || one.endsWith('.wav') || one.endsWith('.m4a') || one.endsWith('.flac')) + if (one.endsWith('.mp3') || one.endsWith('.ogg') || one.endsWith('.wav') || one.endsWith('.m4a') || one.endsWith('.flac') || one.endsWith('.opus')) return one; return null; }).toString(), diff --git a/project/bgms/Asphodelus_Ceui.mp3 b/project/bgms/Asphodelus_Ceui.mp3 deleted file mode 100644 index 718744a..0000000 Binary files a/project/bgms/Asphodelus_Ceui.mp3 and /dev/null differ diff --git a/project/bgms/Asphodelus_Ceui.opus b/project/bgms/Asphodelus_Ceui.opus new file mode 100644 index 0000000..55580e9 Binary files /dev/null and b/project/bgms/Asphodelus_Ceui.opus differ diff --git a/project/bgms/Blind_Alley.mp3 b/project/bgms/Blind_Alley.mp3 deleted file mode 100644 index ad5510c..0000000 Binary files a/project/bgms/Blind_Alley.mp3 and /dev/null differ diff --git a/project/bgms/Blind_Alley.opus b/project/bgms/Blind_Alley.opus new file mode 100644 index 0000000..92df164 Binary files /dev/null and b/project/bgms/Blind_Alley.opus differ diff --git a/project/bgms/Crawler.mp3 b/project/bgms/Crawler.mp3 deleted file mode 100644 index befdc68..0000000 Binary files a/project/bgms/Crawler.mp3 and /dev/null differ diff --git a/project/bgms/Crawler.opus b/project/bgms/Crawler.opus new file mode 100644 index 0000000..877e0cf Binary files /dev/null and b/project/bgms/Crawler.opus differ diff --git a/project/bgms/op.mp3 b/project/bgms/op.mp3 deleted file mode 100644 index 84c7071..0000000 Binary files a/project/bgms/op.mp3 and /dev/null differ diff --git a/project/bgms/theme.mp3 b/project/bgms/theme.mp3 deleted file mode 100644 index efb307d..0000000 Binary files a/project/bgms/theme.mp3 and /dev/null differ diff --git a/project/bgms/theme.opus b/project/bgms/theme.opus new file mode 100644 index 0000000..5a178d6 Binary files /dev/null and b/project/bgms/theme.opus differ diff --git a/project/data.js b/project/data.js index d81181a..04a1131 100644 --- a/project/data.js +++ b/project/data.js @@ -897,12 +897,11 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "zone" ], "bgms": [ - "Asphodelus_Ceui.mp3", - "Blind_Alley.mp3", - "Crawler.mp3", - "op.mp3", + "Asphodelus_Ceui.opus", + "Blind_Alley.opus", + "Crawler.opus", "op.opus", - "theme.mp3" + "theme.opus" ], "sounds": [ "aiy010000010.mp3", @@ -995,6 +994,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "aiy820000010.mp3", "aiy820000020.mp3", "attack.mp3", + "attack.opus", "bomb.mp3", "cancel.mp3", "centerFly.mp3", @@ -1057,7 +1057,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "饰品", "饰品" ], - "startBgm": "theme.mp3", + "startBgm": "theme.opus", "styles": { "startBackground": "project/images/background.webp", "startVerticalBackground": "project/images/backgroundvertical.webp", diff --git a/project/plugins.js b/project/plugins.js index ad52373..317ee03 100644 --- a/project/plugins.js +++ b/project/plugins.js @@ -4196,279 +4196,278 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } }, "编辑器显伤": function () { - // 在此增加新插件 - /////// 用户设置 /////// - // 将__enable置为false将关闭插件 - var __enable = true; - // 魔防攻速之类的属性可以在这里加 ['atk', 'def', 'mdef'] - var heroStatus = ["atk", "def", "mdef", "hp"]; - // saveHero为true 将会把每次造塔测试时的角色数据存下来 否则会读取初始属性 - // 用不着可以关了 节约缓存空间 (虽然根本没多少 还没一个存档大 - // 也可以手动清理 控制台输入core.removeLocalStorage('editorHero')即可 - var saveHero = true; + // 在此增加新插件 + /////// 用户设置 /////// + // 将__enable置为false将关闭插件 + var __enable = true; + // 魔防攻速之类的属性可以在这里加 ['atk', 'def', 'mdef'] + var heroStatus = ["atk", "def", "mdef", "hp"]; + // saveHero为true 将会把每次造塔测试时的角色数据存下来 否则会读取初始属性 + // 用不着可以关了 节约缓存空间 (虽然根本没多少 还没一个存档大 + // 也可以手动清理 控制台输入core.removeLocalStorage('editorHero')即可 + var saveHero = true; - // 下为具体实现 懒得写注释了 大概就是写HTML然后注册交互 - if (!__enable || main.mode != "editor") return; - core.plugin.initEditorDamage = false; - if (heroStatus.length >= 4 && !editor.isMobile) - editor.dom.mid2.style.top = 650 + 30 * (heroStatus.length - 3) + "px"; - editor.statusRatio = core.getLocalStorage("statusRatio", 1); - editor.saveHero = saveHero; - editor._heroStatus = heroStatus; - editor.dom.mapEdit.appendChild(core.canvas.damage.canvas); - var HTML = - ""; + // 下为具体实现 懒得写注释了 大概就是写HTML然后注册交互 + if (!__enable || main.mode != "editor") return; + core.plugin.initEditorDamage = false; + if (heroStatus.length >= 4 && !editor.isMobile) + editor.dom.mid2.style.top = 650 + 30 * (heroStatus.length - 3) + "px"; + editor.statusRatio = core.getLocalStorage("statusRatio", 1); + editor.saveHero = saveHero; + editor._heroStatus = heroStatus; + editor.dom.mapEdit.appendChild(core.canvas.damage.canvas); + var HTML = + ""; - //if (heroStatus.length >= 4 && !editor.isMobile) editor.dom.mid2.style.top = 650 + 30 * (heroStatus.length - 3) + 'px'; - heroStatus.forEach(function (status) { - var id = status + "set", - id2 = status + "add", - id3 = status + "rec", - id4 = status + "help"; - HTML += - "
"; - }); - document.getElementById("viewportButtons").innerHTML = HTML; - ["set", "add", "rec", "help"].forEach(function (e) { - heroStatus.forEach(function (status) { - editor.dom[status + e] = document.getElementById(status + e); - }); - }); - var _hasItem = core.items.hasItem; - core.items.hasItem = function (itemId) { - if (itemId == "book" && main.mode == "editor") return true; - return _hasItem.call(core.items, itemId); - }; - if (main.mode == "editor") { - var applyList = [ - "getDamageString", - "nextCriticals", - "getEnemyInfo", - "getEnemyValue", - ]; - applyList.forEach(function (name) { - var func = core.enemys[name]; - core.enemys[name] = function () { - var args = - arguments.length === 1 - ? [arguments[0]] - : Array.apply(null, arguments); - if (typeof args[0] == "string") args[0] = core.enemys.enemys[args[0]]; - return func.apply(core.enemys, args); - }; - }); - } + //if (heroStatus.length >= 4 && !editor.isMobile) editor.dom.mid2.style.top = 650 + 30 * (heroStatus.length - 3) + 'px'; + heroStatus.forEach(function (status) { + var id = status + "set", + id2 = status + "add", + id3 = status + "rec", + id4 = status + "help"; + HTML += + "
"; + }); + document.getElementById("viewportButtons").innerHTML = HTML; + ["set", "add", "rec", "help"].forEach(function (e) { + heroStatus.forEach(function (status) { + editor.dom[status + e] = document.getElementById(status + e); + }); + }); + var _hasItem = core.items.hasItem; + core.items.hasItem = function (itemId) { + if (itemId == "book" && main.mode == "editor") return true; + return _hasItem.call(core.items, itemId); + }; + if (main.mode == "editor") { + var applyList = [ + "getDamageString", + "nextCriticals", + "getEnemyInfo", + "getEnemyValue", + ]; + applyList.forEach(function (name) { + var func = core.enemys[name]; + core.enemys[name] = function () { + var args = + arguments.length === 1 ? [arguments[0]] : + Array.apply(null, arguments); + if (typeof args[0] == "string") args[0] = core.enemys.enemys[args[0]]; + return func.apply(core.enemys, args); + }; + }); + } - ////// 获得勇士属性 ////// - core.control.getStatus = function (name) { - if (!core.status.hero) return null; - if (name == "x" || name == "y" || name == "direction") - return this.getHeroLoc(name); - /*if ( main.mode == 'editor' && !core.hasFlag('__statistics__')) { + ////// 获得勇士属性 ////// + core.control.getStatus = function (name) { + if (!core.status.hero) return null; + if (name == "x" || name == "y" || name == "direction") + return this.getHeroLoc(name); + /*if ( main.mode == 'editor' && !core.hasFlag('__statistics__')) { return data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.hero[name]; }*/ - return core.status.hero[name]; - }; + return core.status.hero[name]; + }; - core.control.updateDamage = function (floorId, ctx) { - floorId = floorId || core.status.floorId; - if (!floorId || core.status.gameOver) return; - var onMap = ctx == null; - if (main.mode == "editor") { - ctx = core.canvas.damage; - core.updateCheckBlock(); - core.clearMap(ctx); - if (editor.uivalues.bigmap) return; - } + core.control.updateDamage = function (floorId, ctx) { + floorId = floorId || core.status.floorId; + if (!floorId || core.status.gameOver) return; + var onMap = ctx == null; + if (main.mode == "editor") { + ctx = core.canvas.damage; + core.updateCheckBlock(); + core.clearMap(ctx); + if (editor.uivalues.bigmap) return; + } - // 没有怪物手册 - if (!core.hasItem("book")) return; - core.status.damage.posX = core.bigmap.posX; - core.status.damage.posY = core.bigmap.posY; - if (!onMap) { - var width = core.floors[floorId].width, - height = core.floors[floorId].height; - // 地图过大的缩略图不绘制显伤 - if (width * height > core.bigmap.threshold) return; - } - this._updateDamage_damage(floorId, onMap); - this._updateDamage_extraDamage(floorId, onMap); - this.drawDamage(ctx); - }; + // 没有怪物手册 + if (!core.hasItem("book")) return; + core.status.damage.posX = core.bigmap.posX; + core.status.damage.posY = core.bigmap.posY; + if (!onMap) { + var width = core.floors[floorId].width, + height = core.floors[floorId].height; + // 地图过大的缩略图不绘制显伤 + if (width * height > core.bigmap.threshold) return; + } + this._updateDamage_damage(floorId, onMap); + this._updateDamage_extraDamage(floorId, onMap); + this.drawDamage(ctx); + }; - core.control.drawDamage = function (ctx) { - if ( - core.status.gameOver || - !core.status.damage /* || main.mode != 'play'*/ - ) - return; - var onMap = false; - if (ctx == null) { - ctx = core.canvas.damage; - core.clearMap("damage"); - onMap = true; - } + core.control.drawDamage = function (ctx) { + if ( + core.status.gameOver || + !core.status.damage /* || main.mode != 'play'*/ + ) + return; + var onMap = false; + if (ctx == null) { + ctx = core.canvas.damage; + core.clearMap("damage"); + onMap = true; + } - if (onMap && core.bigmap.v2) { - // 检查是否需要重算... - if ( - Math.abs(core.bigmap.posX - core.status.damage.posX) >= - core.bigmap.extend - 1 || - Math.abs(core.bigmap.posY - core.status.damage.posY) >= - core.bigmap.extend - 1 - ) { - return this.updateDamage(); - } - } - return this._drawDamage_draw(ctx, onMap); - }; + if (onMap && core.bigmap.v2) { + // 检查是否需要重算... + if ( + Math.abs(core.bigmap.posX - core.status.damage.posX) >= + core.bigmap.extend - 1 || + Math.abs(core.bigmap.posY - core.status.damage.posY) >= + core.bigmap.extend - 1 + ) { + return this.updateDamage(); + } + } + return this._drawDamage_draw(ctx, onMap); + }; - ////// 以x,y的形式返回每个点的事件 ////// - core.maps.getMapBlocksObj = function (floorId, noCache) { - floorId = floorId || core.status.floorId; - if ( - core.status.mapBlockObjs[floorId] && - !noCache && - main.mode != "editor" - ) - return core.status.mapBlockObjs[floorId]; + ////// 以x,y的形式返回每个点的事件 ////// + core.maps.getMapBlocksObj = function (floorId, noCache) { + floorId = floorId || core.status.floorId; + if ( + core.status.mapBlockObjs[floorId] && + !noCache && + main.mode != "editor" + ) + return core.status.mapBlockObjs[floorId]; - var obj = {}; - core.extractBlocks(floorId); - core.status.maps[floorId].blocks.forEach(function (block) { - obj[block.x + "," + block.y] = block; - }); - core.status.mapBlockObjs[floorId] = obj; - return obj; - }; + var obj = {}; + core.extractBlocks(floorId); + core.status.maps[floorId].blocks.forEach(function (block) { + obj[block.x + "," + block.y] = block; + }); + core.status.mapBlockObjs[floorId] = obj; + return obj; + }; - this.bignum = function (num, defaultValue) { - if (num == null || num == "") return defaultValue; - num = num + ""; - var list = { - w: 1e4, - e: 1e8, - z: 1e12, - j: 1e16, - g: 1e20, - }; - // 浮点数问题 - function checkFloat(num) { - if (!core.isset(num)) return 0; - num = num + ""; - var index = num.indexOf("."); - if (index < 0) return 0; - else return num.slice(index + 1).length; - } - var index = num.search(/w|e|z|j|g/); - if (index <= 0) { - num = parseInt(num); - if (core.isset(num)) return num; - else { - alert("不正确的输入"); - return defaultValue; - } - } - for (; index > 0; index = num.search(/w|e|z|j|g/)) { - var p = num[index], - q = list[p], - n = num.slice(0, index), - m = Math.pow(10, checkFloat(n)); - num = (n * m * q) / m + num.slice(index + 1); - } - return parseInt(num); - }; + this.bignum = function (num, defaultValue) { + if (num == null || num == "") return defaultValue; + num = num + ""; + var list = { + w: 1e4, + e: 1e8, + z: 1e12, + j: 1e16, + g: 1e20, + }; + // 浮点数问题 + function checkFloat(num) { + if (!core.isset(num)) return 0; + num = num + ""; + var index = num.indexOf("."); + if (index < 0) return 0; + else return num.slice(index + 1).length; + } + var index = num.search(/w|e|z|j|g/); + if (index <= 0) { + num = parseInt(num); + if (core.isset(num)) return num; + else { + alert("不正确的输入"); + return defaultValue; + } + } + for (; index > 0; index = num.search(/w|e|z|j|g/)) { + var p = num[index], + q = list[p], + n = num.slice(0, index), + m = Math.pow(10, checkFloat(n)); + num = (n * m * q) / m + num.slice(index + 1); + } + return parseInt(num); + }; - this.updateEditorDamage = function (noSave) { - core.updateDamage(); - heroStatus.forEach(function (status) { - editor.dom[status + "set"].value = core.status.hero[status]; - }); - if (!noSave && editor.saveHero) - core.setLocalStorage("editorHero", core.status.hero); - }; + this.updateEditorDamage = function (noSave) { + core.updateDamage(); + heroStatus.forEach(function (status) { + editor.dom[status + "set"].value = core.status.hero[status]; + }); + if (!noSave && editor.saveHero) + core.setLocalStorage("editorHero", core.status.hero); + }; - var _resizeMap = core.maps.resizeMap; - core.maps.resizeMap = function (floorId) { - _resizeMap.call(core.maps, floorId); - if (!core.plugin.initEditorDamage && main.mode == "editor") { - core.plugin.initEditorDamage = true; - var editorHero = core.getLocalStorage("editorHero"); - if (editorHero && saveHero) core.status.hero = editorHero; - else core.removeLocalStorage("editorHero"); - editor._heroStatus.forEach(function (e) { - editor.dom[e + "set"].onchange = function () { - var status = this.id.slice(0, -3); - core.status.hero[status] = core.bignum( - this.value, - core.status.hero[status] - ); - core.updateEditorDamage(); - }; - editor.dom[e + "add"].onclick = function () { - var status = this.id.slice(0, -3); - core.status.hero[status] += editor.statusRatio; - core.updateEditorDamage(); - }; - editor.dom[e + "rec"].onclick = function () { - var status = this.id.slice(0, -3); - core.status.hero[status] -= editor.statusRatio; - core.updateEditorDamage(); - }; - editor.dom[e + "help"].onclick = function () { - var status = this.id.slice(0, -4), - name = core.getStatusLabel(status); - var ratio = parseInt( - prompt( - "当前属性:" + - name + - "\n现在的点击按钮变化值:" + - editor.statusRatio + - ",请输入按下一次+/-按钮的属性变化量,可以写4w 10.2e这种字母缩写" - ) - ); - if (!core.isset(ratio)) { - printe("不合法的输入"); - return; - } - editor.statusRatio = ratio; - core.setLocalStorage("statusRatio", ratio); - }; - }); - var _updateMap = editor.updateMap; - editor.updateMap = function () { - _updateMap.call(editor); - core.updateEditorDamage(true); - }; - editor.mode.onmode = function (mode, callback) { - if (editor_mode.mode != mode) { - if (mode === "save") { - editor_mode.doActionList( - editor_mode.mode, - editor_mode.actionList, - function () { - if (callback) callback(); - core.updateEditorDamage(); - } - ); - } - if (editor_mode.mode === "nextChange" && mode) - editor_mode.showMode(mode); - if (mode !== "save") editor_mode.mode = mode; - editor_mode.actionList = []; - } - }; - } - }; - }, + var _resizeMap = core.maps.resizeMap; + core.maps.resizeMap = function (floorId) { + _resizeMap.call(core.maps, floorId); + if (!core.plugin.initEditorDamage && main.mode == "editor") { + core.plugin.initEditorDamage = true; + var editorHero = core.getLocalStorage("editorHero"); + if (editorHero && saveHero) core.status.hero = editorHero; + else core.removeLocalStorage("editorHero"); + editor._heroStatus.forEach(function (e) { + editor.dom[e + "set"].onchange = function () { + var status = this.id.slice(0, -3); + core.status.hero[status] = core.bignum( + this.value, + core.status.hero[status] + ); + core.updateEditorDamage(); + }; + editor.dom[e + "add"].onclick = function () { + var status = this.id.slice(0, -3); + core.status.hero[status] += editor.statusRatio; + core.updateEditorDamage(); + }; + editor.dom[e + "rec"].onclick = function () { + var status = this.id.slice(0, -3); + core.status.hero[status] -= editor.statusRatio; + core.updateEditorDamage(); + }; + editor.dom[e + "help"].onclick = function () { + var status = this.id.slice(0, -4), + name = core.getStatusLabel(status); + var ratio = parseInt( + prompt( + "当前属性:" + + name + + "\n现在的点击按钮变化值:" + + editor.statusRatio + + ",请输入按下一次+/-按钮的属性变化量,可以写4w 10.2e这种字母缩写" + ) + ); + if (!core.isset(ratio)) { + printe("不合法的输入"); + return; + } + editor.statusRatio = ratio; + core.setLocalStorage("statusRatio", ratio); + }; + }); + var _updateMap = editor.updateMap; + editor.updateMap = function () { + _updateMap.call(editor); + core.updateEditorDamage(true); + }; + editor.mode.onmode = function (mode, callback) { + if (editor_mode.mode != mode) { + if (mode === "save") { + editor_mode.doActionList( + editor_mode.mode, + editor_mode.actionList, + function () { + if (callback) callback(); + core.updateEditorDamage(); + } + ); + } + if (editor_mode.mode === "nextChange" && mode) + editor_mode.showMode(mode); + if (mode !== "save") editor_mode.mode = mode; + editor_mode.actionList = []; + } + }; + } + }; +}, "手册区分特殊属性": function () { // 在此增加新插件 this.arrsame = function (Arraya, Arrayb) { @@ -7377,51 +7376,46 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = if (main.replayChecking) return (core.plugin.animate = {}); var M = Object.defineProperty; - var E = (n, s, t) => - s in n - ? M(n, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) - : (n[s] = t); - var o = (n, s, t) => (E(n, typeof s != "symbol" ? s + "" : s, t), t); - let b = []; + var E = (n, i, t) => + i in n + ? M(n, i, { enumerable: !0, configurable: !0, writable: !0, value: t }) + : (n[i] = t); + var o = (n, i, t) => (E(n, typeof i != "symbol" ? i + "" : i, t), t); + let w = []; const k = (n) => { - for (const s of b) - if (s.status === "running") + for (const i of w) + if (i.status === "running") try { - for (const t of s.funcs) t(n - s.startTime); + for (const t of i.funcs) t(n - i.startTime); } catch (t) { - s.destroy(), console.error(t); + i.destroy(), console.error(t); } requestAnimationFrame(k); }; requestAnimationFrame(k); class I { constructor() { - o(this, "funcs", []); + o(this, "funcs", /* @__PURE__ */ new Set()); o(this, "status", "stop"); o(this, "startTime", 0); (this.status = "running"), - b.push(this), - requestAnimationFrame((s) => (this.startTime = s)); + w.push(this), + requestAnimationFrame((i) => (this.startTime = i)); } - add(s, t = !1) { - return t ? this.funcs.unshift(s) : this.funcs.push(s), this; + add(i) { + return this.funcs.add(i), this; } - remove(s) { - const t = this.funcs.findIndex((e) => e === s); - if (t === -1) - throw new ReferenceError( - "You are going to remove nonexistent ticker function." - ); - return this.funcs.splice(t, 1), this; + remove(i) { + return this.funcs.delete(i), this; } clear() { - this.funcs = []; + this.funcs.clear(); } destroy() { this.clear(), this.stop(); } stop() { - (this.status = "stop"), (b = b.filter((s) => s !== this)); + (this.status = "stop"), (w = w.filter((i) => i !== this)); } } class F { @@ -7434,70 +7428,70 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = o(this, "ticker", new I()); o(this, "value", {}); o(this, "listener", {}); - this.timing = (s) => s; + this.timing = (i) => i; } async all() { - if (Object.values(this.applying).every((s) => s === !0)) + if (Object.values(this.applying).every((i) => i === !0)) throw new ReferenceError("There is no animates to be waited."); - await new Promise((s) => { + await new Promise((i) => { const t = () => { Object.values(this.applying).every((e) => e === !1) && - (this.unlisten("end", t), s("all animated.")); + (this.unlisten("end", t), i("all animated.")); }; this.listen("end", t); }); } - async n(s) { - const t = Object.values(this.applying).filter((i) => i === !0).length; - if (t < s) + async n(i) { + const t = Object.values(this.applying).filter((s) => s === !0).length; + if (t < i) throw new ReferenceError( - `You are trying to wait ${s} animate, but there are only ${t} animate animating.` + `You are trying to wait ${i} animate, but there are only ${t} animate animating.` ); let e = 0; - await new Promise((i) => { + await new Promise((s) => { const r = () => { - e++, e === s && (this.unlisten("end", r), i(`${s} animated.`)); + e++, e === i && (this.unlisten("end", r), s(`${i} animated.`)); }; this.listen("end", r); }); } - async w(s) { - if (this.applying[s] === !1) - throw new ReferenceError(`The ${s} animate is not animating.`); + async w(i) { + if (this.applying[i] === !1) + throw new ReferenceError(`The ${i} animate is not animating.`); await new Promise((t) => { const e = () => { - this.applying[s] === !1 && - (this.unlisten("end", e), t(`${s} animated.`)); + this.applying[i] === !1 && + (this.unlisten("end", e), t(`${i} animated.`)); }; this.listen("end", e); }); } - listen(s, t) { - var e, i; - (i = (e = this.listener)[s]) != null || (e[s] = []), - this.listener[s].push(t); + listen(i, t) { + var e, s; + (s = (e = this.listener)[i]) != null || (e[i] = []), + this.listener[i].push(t); } - unlisten(s, t) { - const e = this.listener[s].findIndex((i) => i === t); + unlisten(i, t) { + const e = this.listener[i].findIndex((s) => s === t); if (e === -1) throw new ReferenceError( "You are trying to remove a nonexistent listener." ); - this.listener[s].splice(e, 1); + this.listener[i].splice(e, 1); } - hook(...s) { - const t = Object.entries(this.listener).filter((e) => s.includes(e[0])); - for (const [e, i] of t) for (const r of i) r(this, e); + hook(...i) { + const t = Object.entries(this.listener).filter((e) => i.includes(e[0])); + for (const [e, s] of t) for (const r of s) r(this, e); } } - function T(n) { + function y(n) { return n != null; } async function R(n) { - return new Promise((s) => setTimeout(s, n)); + return new Promise((i) => setTimeout(i, n)); } - class Y extends F { + class j extends F { constructor() { super(); o(this, "shakeTiming"); @@ -7545,7 +7539,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = }), this.ticker.add(() => { const { running: t } = this.listener; - if (T(t)) for (const e of t) e(this, "running"); + if (y(t)) for (const e of t) e(this, "running"); }); } get x() { @@ -7604,58 +7598,58 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = shake(t, e) { this.applying.shake === !0 && this.end(!0, "shake"), (this.applying.shake = !0); - const { easeTime: i, shakeTiming: r } = this, - h = this.getTime(); - if ((this.hook("start", "shakestart"), i <= 0)) + const { easeTime: s, shakeTiming: r } = this, + l = this.getTime(); + if ((this.hook("start", "shakestart"), s <= 0)) return this.end(!1, "shake"), this; - const l = () => { - const c = this.getTime() - h; - if (c > i) { - this.ticker.remove(l), + const a = () => { + const c = this.getTime() - l; + if (c > s) { + this.ticker.remove(a), (this.applying.shake = !1), (this.sx = 0), (this.sy = 0), this.hook("end", "shakeend"); return; } - const a = c / i, - m = r(a); + const h = c / s, + m = r(h); (this.sx = m * t), (this.sy = m * e); }; - return this.ticker.add(l), (this.animateFn.system.shake = l), this; + return this.ticker.add(a), (this.animateFn.system.shake = a), this; } moveAs(t) { this.applying.moveAs && this.end(!0, "moveAs"), (this.applying.moveAs = !0), (this.path = t); - const { easeTime: e, relation: i, timing: r } = this, - h = this.getTime(), - [l, u] = [this.x, this.y], - [c, a] = (() => { - if (i === "absolute") return t(1); + const { easeTime: e, relation: s, timing: r } = this, + l = this.getTime(), + [a, u] = [this.x, this.y], + [c, h] = (() => { + if (s === "absolute") return t(1); { const [d, f] = t(1); - return [l + d, u + f]; + return [a + d, u + f]; } })(); if ((this.hook("start", "movestart"), e <= 0)) return this.end(!1, "moveAs"), this; const m = () => { - const f = this.getTime() - h; + const f = this.getTime() - l; if (f > e) { this.end(!0, "moveAs"); return; } - const v = f / e, - [g, w] = t(r(v)); - i === "absolute" - ? ((this.ox = g), (this.oy = w)) - : ((this.ox = l + g), (this.oy = u + w)); + const g = f / e, + [v, x] = t(r(g)); + s === "absolute" + ? ((this.ox = v), (this.oy = x)) + : ((this.ox = a + v), (this.oy = u + x)); }; return ( - this.ticker.add(m, !0), + this.ticker.add(m), (this.animateFn.system.moveAs = m), - (this.targetValue.system.moveAs = [c, a]), + (this.targetValue.system.moveAs = [c, h]), this ); } @@ -7667,97 +7661,97 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = ); (this.value[t] = e), (this.applying[t] = !1); } - apply(t, e, i = !1) { + apply(t, e) { this.applying[t] === !0 && this.end(!1, t), t in this.value || this.error(`You are trying to execute nonexistent property ${t}.`), (this.applying[t] = !0); - const r = this.value[t], - h = this.getTime(), - { timing: l, relation: u, easeTime: c } = this, - a = u === "absolute" ? e - r : e; - if ((this.hook("start"), c <= 0)) return this.end(!1, t), this; - const m = () => { - const f = this.getTime() - h; - if (f > c) { + const s = this.value[t], + r = this.getTime(), + { timing: l, relation: a, easeTime: u } = this, + c = a === "absolute" ? e - s : e; + if ((this.hook("start"), u <= 0)) return this.end(!1, t), this; + const h = () => { + const d = this.getTime() - r; + if (d > u) { this.end(!1, t); return; } - const v = f / c, - g = l(v); - this.value[t] = r + g * a; + const f = d / u, + g = l(f); + this.value[t] = s + g * c; }; return ( - this.ticker.add(m, i), - (this.animateFn.custom[t] = m), - (this.targetValue.custom[t] = a + r), + this.ticker.add(h), + (this.animateFn.custom[t] = h), + (this.targetValue.custom[t] = c + s), this ); } - applyMulti(t = !1) { + applyMulti() { this.applying["@@bind"] === !0 && this.end(!1, "@@bind"), (this.applying["@@bind"] = !0); - const e = this.bindInfo, - i = e.map((m) => this.value[m]), - r = this.getTime(), - { multiTiming: h, relation: l, easeTime: u } = this, - c = h(1); - if (c.length !== i.length) + const t = this.bindInfo, + e = t.map((h) => this.value[h]), + s = this.getTime(), + { multiTiming: r, relation: l, easeTime: a } = this, + u = r(1); + if (u.length !== e.length) throw new TypeError( - `The number of binded animate attributes and timing function returns's length does not match. binded: ${e.length}, timing: ${c.length}` + `The number of binded animate attributes and timing function returns's length does not match. binded: ${t.length}, timing: ${u.length}` ); - if ((this.hook("start"), u <= 0)) return this.end(!1, "@@bind"), this; - const a = () => { - const d = this.getTime() - r; - if (d > u) { + if ((this.hook("start"), a <= 0)) return this.end(!1, "@@bind"), this; + const c = () => { + const m = this.getTime() - s; + if (m > a) { this.end(!1, "@@bind"); return; } - const f = d / u, - v = h(f); - e.forEach((g, w) => { + const d = m / a, + f = r(d); + t.forEach((g, v) => { l === "absolute" - ? (this.value[g] = v[w]) - : (this.value[g] = i[w] + v[w]); + ? (this.value[g] = f[v]) + : (this.value[g] = e[v] + f[v]); }); }; return ( - this.ticker.add(a, t), - (this.animateFn.custom["@@bind"] = a), - (this.targetValue.system["@@bind"] = c), + this.ticker.add(c), + (this.animateFn.custom["@@bind"] = c), + (this.targetValue.system["@@bind"] = u), this ); } - applySys(t, e, i) { - i !== "move" && this.applying[i] === !0 && this.end(!0, i), - (this.applying[i] = !0); + applySys(t, e, s) { + s !== "move" && this.applying[s] === !0 && this.end(!0, s), + (this.applying[s] = !0); const r = this[t], - h = this.getTime(), - l = this.timing, + l = this.getTime(), + a = this.timing, u = this.relation, c = this.easeTime, - a = u === "absolute" ? e - r : e; - if ((this.hook("start", `${i}start`), c <= 0)) return this.end(!1, i); + h = u === "absolute" ? e - r : e; + if ((this.hook("start", `${s}start`), c <= 0)) return this.end(!0, s); const m = () => { - const f = this.getTime() - h; + const f = this.getTime() - l; if (f > c) { - this.end(!0, i); + this.end(!0, s); return; } - const v = f / c, - g = l(v); - (this[t] = r + a * g), t !== "oy" && this.hook(i); + const g = f / c, + v = a(g); + (this[t] = r + h * v), t !== "oy" && this.hook(s); }; - this.ticker.add(m, !0), + this.ticker.add(m), t === "ox" ? (this.animateFn.system.move[0] = m) : t === "oy" ? (this.animateFn.system.move[1] = m) - : (this.animateFn.system[i] = m), - i === "move" - ? (t === "ox" && (this.targetValue.system.move[0] = a + r), - t === "oy" && (this.targetValue.system.move[1] = a + r)) - : i !== "shake" && (this.targetValue.system[i] = a + r); + : (this.animateFn.system[s] = m), + s === "move" + ? (t === "ox" && (this.targetValue.system.move[0] = h + r), + t === "oy" && (this.targetValue.system.move[1] = h + r)) + : s !== "shake" && (this.targetValue.system[s] = h + r); } error(t, e) { throw e === "repeat" @@ -7780,11 +7774,11 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = : this.ticker.remove(this.animateFn.system[e]), e === "move") ) { - const [i, r] = this.targetValue.system.move; - (this.ox = i), (this.oy = r), this.hook("moveend", "end"); + const [s, r] = this.targetValue.system.move; + (this.ox = s), (this.oy = r), this.hook("moveend", "end"); } else if (e === "moveAs") { - const [i, r] = this.targetValue.system.moveAs; - (this.ox = i), (this.oy = r), this.hook("moveend", "end"); + const [s, r] = this.targetValue.system.moveAs; + (this.ox = s), (this.oy = r), this.hook("moveend", "end"); } else e === "rotate" ? ((this.angle = this.targetValue.system.rotate), @@ -7793,8 +7787,8 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = ? ((this.size = this.targetValue.system.resize), this.hook("resizeend", "end")) : e === "@@bind" - ? this.bindInfo.forEach((r, h) => { - this.value[r] = this.targetValue.system["@@bind"][h]; + ? this.bindInfo.forEach((r, l) => { + this.value[r] = this.targetValue.system["@@bind"][l]; }) : ((this.sx = 0), (this.sy = 0), this.hook("shakeend", "end")); else @@ -7804,14 +7798,14 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = this.hook("end"); } } - class j extends F { + class O extends F { constructor() { super(); o(this, "now", {}); o(this, "target", {}); o(this, "transitionFn", {}); o(this, "value"); - o(this, "handleSet", (t, e, i) => (this.transition(e, i), !0)); + o(this, "handleSet", (t, e, s) => (this.transition(e, s), !0)); o(this, "handleGet", (t, e) => this.now[e]); (this.timing = (t) => t), (this.value = new Proxy(this.target, { @@ -7833,34 +7827,35 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } transition(t, e) { if (e === this.target[t]) return this; - if (!T(this.now[t])) return (this.now[t] = e), this; + if (!y(this.now[t])) return (this.now[t] = e), this; this.applying[t] && this.end(t, !0), (this.applying[t] = !0), this.hook("start"); - const i = this.getTime(), + const s = this.getTime(), r = this.easeTime, - h = this.timing, - l = this.now[t], - u = e + (this.relation === "absolute" ? 0 : l), - c = u - l; + l = this.timing, + a = this.now[t], + u = e + (this.relation === "absolute" ? 0 : a), + c = u - a; this.target[t] = u; - const a = () => { - const d = this.getTime() - i; + const h = () => { + const d = this.getTime() - s; if (d >= r) { this.end(t); return; } const f = d / r; - (this.now[t] = h(f) * c + l), this.hook("running"); + (this.now[t] = l(f) * c + a), this.hook("running"); }; return ( - (this.transitionFn[t] = a), - r <= 0 ? (this.end(t), this) : (this.ticker.add(a), this) + (this.transitionFn[t] = h), + this.ticker.add(h), + r <= 0 ? (this.end(t), this) : this ); } end(t, e = !1) { - const i = this.transitionFn[t]; - if (!T(i)) + const s = this.transitionFn[t]; + if (!y(s)) throw new ReferenceError( `You are trying to end an ended transition: ${t}` ); @@ -7871,146 +7866,145 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = e || (this.now[t] = this.target[t]); } } - const x = (...n) => n.reduce((s, t) => s + t, 0), - y = (n) => { + const T = (...n) => n.reduce((i, t) => i + t, 0), + b = (n) => { if (n === 0) return 1; - let s = n; - for (; n > 1; ) n--, (s *= n); - return s; + let i = n; + for (; n > 1; ) n--, (i *= n); + return i; }, - A = (n, s) => Math.round(y(s) / (y(n) * y(s - n))), - p = (n, s, t = (e) => 1 - s(1 - e)) => + A = (n, i) => Math.round(b(i) / (b(n) * b(i - n))), + p = (n, i, t = (e) => 1 - i(1 - e)) => n === "in" - ? s + ? i : n === "out" ? t : n === "in-out" - ? (e) => (e < 0.5 ? s(e * 2) / 2 : 0.5 + t((e - 0.5) * 2) / 2) - : (e) => (e < 0.5 ? t(e * 2) / 2 : 0.5 + s((e - 0.5) * 2) / 2), + ? (e) => (e < 0.5 ? i(e * 2) / 2 : 0.5 + t((e - 0.5) * 2) / 2) + : (e) => (e < 0.5 ? t(e * 2) / 2 : 0.5 + i((e - 0.5) * 2) / 2), $ = Math.cosh(2), z = Math.acosh(2), V = Math.tanh(3), P = Math.atan(5); - function O() { + function Y() { return (n) => n; } function q(...n) { - const s = [0].concat(n); - s.push(1); - const t = s.length, + const i = [0].concat(n); + i.push(1); + const t = i.length, e = Array(t) .fill(0) - .map((i, r) => A(r, t - 1)); - return (i) => { - const r = e.map((h, l) => h * s[l] * (1 - i) ** (t - l - 1) * i ** l); - return x(...r); + .map((s, r) => A(r, t - 1)); + return (s) => { + const r = e.map((l, a) => l * i[a] * (1 - s) ** (t - a - 1) * s ** a); + return T(...r); }; } - function U(n, s) { + function U(n, i) { if (n === "sin") { - const t = (i) => Math.sin((i * Math.PI) / 2); - return p(s, (i) => 1 - t(1 - i), t); + const t = (s) => Math.sin((s * Math.PI) / 2); + return p(i, (s) => 1 - t(1 - s), t); } if (n === "sec") { - const t = (i) => 1 / Math.cos(i); - return p(s, (i) => t((i * Math.PI) / 3) - 1); + const t = (s) => 1 / Math.cos(s); + return p(i, (s) => t((s * Math.PI) / 3) - 1); } throw new TypeError( "Unexpected parameters are delivered in trigo timing function." ); } - function C(n, s) { + function C(n, i) { if (!Number.isInteger(n)) throw new TypeError( "The first parameter of power timing function only allow integer." ); - return p(s, (e) => e ** n); + return p(i, (e) => e ** n); } - function G(n, s) { - if (n === "sin") return p(s, (e) => (Math.cosh(e * 2) - 1) / ($ - 1)); + function G(n, i) { + if (n === "sin") return p(i, (e) => (Math.cosh(e * 2) - 1) / ($ - 1)); if (n === "tan") { - const t = (i) => (Math.tanh(i * 3) * 1) / V; - return p(s, (i) => 1 - t(1 - i), t); + const t = (s) => (Math.tanh(s * 3) * 1) / V; + return p(i, (s) => 1 - t(1 - s), t); } if (n === "sec") { - const t = (i) => 1 / Math.cosh(i); - return p(s, (i) => 1 - (t(i * z) - 0.5) * 2); + const t = (s) => 1 / Math.cosh(s); + return p(i, (s) => 1 - (t(s * z) - 0.5) * 2); } throw new TypeError( "Unexpected parameters are delivered in hyper timing function." ); } - function N(n, s) { + function N(n, i) { if (n === "sin") { - const t = (i) => (Math.asin(i) / Math.PI) * 2; - return p(s, (i) => 1 - t(1 - i), t); + const t = (s) => (Math.asin(s) / Math.PI) * 2; + return p(i, (s) => 1 - t(1 - s), t); } if (n === "tan") { - const t = (i) => Math.atan(i * 5) / P; - return p(s, (i) => 1 - t(1 - i), t); + const t = (s) => Math.atan(s * 5) / P; + return p(i, (s) => 1 - t(1 - s), t); } throw new TypeError( "Unexpected parameters are delivered in inverse trigo timing function." ); } - function B(n, s = () => 1) { + function B(n, i = () => 1) { let t = -1; return (e) => ( - (t *= -1), e < 0.5 ? n * s(e * 2) * t : n * s((1 - e) * 2) * t + (t *= -1), e < 0.5 ? n * i(e * 2) * t : n * i((1 - e) * 2) * t ); } - function D(n, s = 1, t = [0, 0], e = 0, i = (h) => 1, r = !1) { - return (h) => { - const l = s * h * Math.PI * 2 + (e * Math.PI) / 180, - u = Math.cos(l), - c = Math.sin(l), - a = n * i(i(r ? 1 - h : h)); - return [a * u + t[0], a * c + t[1]]; + function D(n, i = 1, t = [0, 0], e = 0, s = (l) => 1, r = !1) { + return (l) => { + const a = i * l * Math.PI * 2 + (e * Math.PI) / 180, + u = Math.cos(a), + c = Math.sin(a), + h = n * s(s(r ? 1 - l : l)); + return [h * u + t[0], h * c + t[1]]; }; } - function H(n, s, ...t) { + function H(n, i, ...t) { const e = [n].concat(t); - e.push(s); - const i = e.length, - r = Array(i) + e.push(i); + const s = e.length, + r = Array(s) .fill(0) - .map((h, l) => A(l, i - 1)); - return (h) => { - const l = r.map( - (c, a) => c * e[a][0] * (1 - h) ** (i - a - 1) * h ** a + .map((l, a) => A(a, s - 1)); + return (l) => { + const a = r.map( + (c, h) => c * e[h][0] * (1 - l) ** (s - h - 1) * l ** h ), - u = r.map((c, a) => c * e[a][1] * (1 - h) ** (i - a - 1) * h ** a); - return [x(...l), x(...u)]; + u = r.map((c, h) => c * e[h][1] * (1 - l) ** (s - h - 1) * l ** h); + return [T(...a), T(...u)]; }; } - if ("animate" in core.plugin) throw new ReferenceError(`插件中已存在名为animate的属性!`); core.plugin.animate = { - Animation: Y, + Animation: j, AnimationBase: F, Ticker: I, - Transition: j, - sleep: R, - circle: D, - bezierPath: H, - linear: O, + Transition: O, bezier: q, - trigo: U, - power: C, + bezierPath: H, + circle: D, hyper: G, - inverseTrigo: N, + linear: Y, + power: C, shake: B, + sleep: R, + trigo: U, + inverseTrigo: N, }; }, "func": function () { @@ -14262,1100 +14256,1097 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = }; }, "musicMode": function () { - // 在此增加新插件 - const music = document.createElement("canvas"); - music.style.position = "absolute"; - music.style.zIndex = 300; - music.style.display = "none"; - music.id = "music"; - main.dom.gameGroup.insertAdjacentElement("afterend", music); - music.style.top = "50%"; - music.style.left = "50%"; - music.style.transform = "translate(-50%,-50%)"; - const ctx = music.getContext("2d"); - main.dom.music = music; + // 在此增加新插件 + const music = document.createElement("canvas"); + music.style.position = "absolute"; + music.style.zIndex = 300; + music.style.display = "none"; + music.id = "music"; + main.dom.gameGroup.insertAdjacentElement("afterend", music); + music.style.top = "50%"; + music.style.left = "50%"; + music.style.transform = "translate(-50%,-50%)"; + const ctx = music.getContext("2d"); + main.dom.music = music; - const audio = document.createElement("audio"); - audio.autoplay = true; - audio.preload = "auto"; + const audio = document.createElement("audio"); + audio.autoplay = true; + audio.preload = "auto"; - function getRandomInt(min, max) { - const minCeiled = Math.ceil(min); - const maxFloored = Math.floor(max); - return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); - } - let page = 0; //初始页面 - let ischange = false; - let isvolume = false; + function getRandomInt(min, max) { + const minCeiled = Math.ceil(min); + const maxFloored = Math.floor(max); + return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); + } + let page = 0; //初始页面 + let ischange = false; + let isvolume = false; - function shuffle(arr) { - let n = arr.length, - random; - while (n) { - random = (Math.random() * n--) >>> 0; - [arr[n], arr[random]] = [arr[random], arr[n]]; - } - return arr; - } - music.addEventListener("mousedown", function (e) { - e.stopPropagation(); - const left = core.dom.gameGroup.offsetLeft; - const top = core.dom.gameGroup.offsetTop; - const px = Math.floor((e.clientX - left) / core.domStyle.scale), - py = Math.floor((e.clientY - top) / core.domStyle.scale); - core.ui.music.mousedown(px * 3, py * 3); - }); - music.addEventListener("mousemove", function (e) { - e.stopPropagation(); - const left = core.dom.gameGroup.offsetLeft; - const top = core.dom.gameGroup.offsetTop; - const px = Math.floor((e.clientX - left) / core.domStyle.scale), - py = Math.floor((e.clientY - top) / core.domStyle.scale); - core.ui.music.mousemove(px * 3, py * 3); - }); - music.addEventListener("mouseup", function (e) { - e.stopPropagation(); - ischange = false; - isvolume = false; - if (!main.core.ui.music.stop) audio.play(); - }); - music.addEventListener("mouseleave", function (e) { - e.stopPropagation(); - ischange = false; - isvolume = false; - if (!main.core.ui.music.stop) audio.play(); - }); - music.addEventListener("touchstart", function (e) { - e.preventDefault(); - const left = core.dom.gameGroup.offsetLeft; - const top = core.dom.gameGroup.offsetTop; - const px = Math.floor( - (e.touches[0].clientX - left) / core.domStyle.scale - ), - py = Math.floor((e.touches[0].clientY - top) / core.domStyle.scale); - core.ui.music.mousedown(px * 3, py * 3); - }); - music.addEventListener("touchmove", function (e) { - e.stopPropagation(); - const left = core.dom.gameGroup.offsetLeft; - const top = core.dom.gameGroup.offsetTop; - const px = Math.floor( - (e.touches[0].clientX - left) / core.domStyle.scale - ), - py = Math.floor((e.touches[0].clientY - top) / core.domStyle.scale); - core.ui.music.mousemove(px * 3, py * 3); - }); - music.addEventListener("touchend", function (e) { - e.stopPropagation(); - ischange = false; - isvolume = false; - if (!main.core.ui.music.stop) audio.play(); - }); - music.addEventListener("touchcancel", function (e) { - e.stopPropagation(); - ischange = false; - isvolume = false; - }); + function shuffle(arr) { + let n = arr.length, + random; + while (n) { + random = (Math.random() * n--) >>> 0; + [arr[n], arr[random]] = [arr[random], arr[n]]; + } + return arr; + } + music.addEventListener("mousedown", function (e) { + e.stopPropagation(); + const left = core.dom.gameGroup.offsetLeft; + const top = core.dom.gameGroup.offsetTop; + const px = Math.floor((e.clientX - left) / core.domStyle.scale), + py = Math.floor((e.clientY - top) / core.domStyle.scale); + core.ui.music.mousedown(px * 3, py * 3); + }); + music.addEventListener("mousemove", function (e) { + e.stopPropagation(); + const left = core.dom.gameGroup.offsetLeft; + const top = core.dom.gameGroup.offsetTop; + const px = Math.floor((e.clientX - left) / core.domStyle.scale), + py = Math.floor((e.clientY - top) / core.domStyle.scale); + core.ui.music.mousemove(px * 3, py * 3); + }); + music.addEventListener("mouseup", function (e) { + e.stopPropagation(); + ischange = false; + isvolume = false; + if (!main.core.ui.music.stop) audio.play(); + }); + music.addEventListener("mouseleave", function (e) { + e.stopPropagation(); + ischange = false; + isvolume = false; + if (!main.core.ui.music.stop) audio.play(); + }); + music.addEventListener("touchstart", function (e) { + e.preventDefault(); + const left = core.dom.gameGroup.offsetLeft; + const top = core.dom.gameGroup.offsetTop; + const px = Math.floor( + (e.touches[0].clientX - left) / core.domStyle.scale + ), + py = Math.floor((e.touches[0].clientY - top) / core.domStyle.scale); + core.ui.music.mousedown(px * 3, py * 3); + }); + music.addEventListener("touchmove", function (e) { + e.stopPropagation(); + const left = core.dom.gameGroup.offsetLeft; + const top = core.dom.gameGroup.offsetTop; + const px = Math.floor( + (e.touches[0].clientX - left) / core.domStyle.scale + ), + py = Math.floor((e.touches[0].clientY - top) / core.domStyle.scale); + core.ui.music.mousemove(px * 3, py * 3); + }); + music.addEventListener("touchend", function (e) { + e.stopPropagation(); + ischange = false; + isvolume = false; + if (!main.core.ui.music.stop) audio.play(); + }); + music.addEventListener("touchcancel", function (e) { + e.stopPropagation(); + ischange = false; + isvolume = false; + }); - audio.addEventListener("ended", function () { - switch (main.core.ui.music.type) { - case "danqu": - audio.currentTime = 0; - if (!main.core.ui.music.stop) audio.play(); - main.core.ui.music.stop = false; - page = main.core.ui.music.selection[0]; + audio.addEventListener("ended", function () { + switch (main.core.ui.music.type) { + case "danqu": + audio.currentTime = 0; + if (!main.core.ui.music.stop) audio.play(); + main.core.ui.music.stop = false; + page = main.core.ui.music.selection[0]; - break; - case "xunhuan": - if ( - main.core.ui.music.selection[1] === - main.core.ui.music.musicMx[main.core.ui.music.selection[0]].length - - 1 - ) { - if ( - main.core.ui.music.selection[0] === - main.core.ui.music.musicMx.length - 1 - ) { - main.core.ui.music.selection[0] = 0; - main.core.ui.music.selection[1] = 0; - } else { - main.core.ui.music.selection[0] += 1; - main.core.ui.music.selection[1] = 0; - } - } else { - main.core.ui.music.selection[1] += 1; - } - main.core.ui.music.randomList.indexOf( - (v) => - v === - main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ - main.core.ui.music.selection[1] - ] - ); - page = main.core.ui.music.selection[0]; - audio.src = - "project/bgms/" + - main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ - main.core.ui.music.selection[1] - ]; + break; + case "xunhuan": + if ( + main.core.ui.music.selection[1] === + main.core.ui.music.musicMx[main.core.ui.music.selection[0]].length - + 1 + ) { + if ( + main.core.ui.music.selection[0] === + main.core.ui.music.musicMx.length - 1 + ) { + main.core.ui.music.selection[0] = 0; + main.core.ui.music.selection[1] = 0; + } else { + main.core.ui.music.selection[0] += 1; + main.core.ui.music.selection[1] = 0; + } + } else { + main.core.ui.music.selection[1] += 1; + } + main.core.ui.music.randomList.indexOf( + (v) => + v === + main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ + main.core.ui.music.selection[1] + ] + ); + page = main.core.ui.music.selection[0]; + audio.src = + "project/bgms/" + + main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ + main.core.ui.music.selection[1] + ]; - if (!main.core.ui.music.stop) audio.play(); - main.core.ui.music.stop = false; - break; - case "suiji": - if ( - main.core.ui.music.random < - main.core.ui.music.randomList.length - 1 - ) { - main.core.ui.music.random += 1; - } else { - main.core.ui.music.random = 0; - } - main.core.ui.music.selection[0] = - main.core.ui.music.musicMx.findIndex((v) => - v.includes( - main.core.ui.music.randomList[main.core.ui.music.random] - ) - ); - main.core.ui.music.selection[1] = main.core.ui.music.musicMx[ - main.core.ui.music.selection[0] - ].indexOf(main.core.ui.music.randomList[main.core.ui.music.random]); - audio.src = - "project/bgms/" + - main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ - main.core.ui.music.selection[1] - ]; - page = main.core.ui.music.selection[0]; + if (!main.core.ui.music.stop) audio.play(); + main.core.ui.music.stop = false; + break; + case "suiji": + if ( + main.core.ui.music.random < + main.core.ui.music.randomList.length - 1 + ) { + main.core.ui.music.random += 1; + } else { + main.core.ui.music.random = 0; + } + main.core.ui.music.selection[0] = + main.core.ui.music.musicMx.findIndex((v) => + v.includes( + main.core.ui.music.randomList[main.core.ui.music.random] + ) + ); + main.core.ui.music.selection[1] = main.core.ui.music.musicMx[ + main.core.ui.music.selection[0] + ].indexOf(main.core.ui.music.randomList[main.core.ui.music.random]); + audio.src = + "project/bgms/" + + main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ + main.core.ui.music.selection[1] + ]; + page = main.core.ui.music.selection[0]; - if (!main.core.ui.music.stop) audio.play(); - main.core.ui.music.stop = false; - break; - } - }); + if (!main.core.ui.music.stop) audio.play(); + main.core.ui.music.stop = false; + break; + } + }); - class musicclass { - constructor() { - //music列表 - //需全塔属性注册并保存在bgms文件夹,每个数组为显示的一页内容 - this.musicMx = [ - ["Asphodelus_Ceui.mp3", "Blind_Alley.mp3"], - ["Crawler.mp3", "op.mp3", "theme.mp3"], - ]; - //音乐别名(将在播放器内显示的音乐名,music列表内的都要有对应歌名) - this.musicname = { - "Asphodelus_Ceui.mp3": "Asphodelus", - "Blind_Alley.mp3": "Blind", - "Crawler.mp3": "Crawler", - "op.mp3": "op", - "theme.mp3": "theme", - }; - this.selection = [0, 0]; - this.stop = false; - this.type = "xunhuan"; - this.randomList = []; - this.random = 0; - } + class musicclass { + constructor() { + //music列表 + //需全塔属性注册并保存在bgms文件夹,每个数组为显示的一页内容 + this.musicMx = [ + ["Asphodelus_Ceui.mp3", "Blind_Alley.mp3"], + ["Crawler.mp3", "op.mp3", "theme.mp3"], + ]; + //音乐别名(将在播放器内显示的音乐名,music列表内的都要有对应歌名) + this.musicname = { + "Asphodelus_Ceui.mp3": "Asphodelus", + "Blind_Alley.mp3": "Blind", + "Crawler.mp3": "Crawler", + "op.mp3": "op", + "theme.mp3": "theme", + }; + this.selection = [0, 0]; + this.stop = false; + this.type = "xunhuan"; + this.randomList = []; + this.random = 0; + } - //更新 - update() { - this.background(); - this.drawUI(); - } - background() { - //画布大小设置 - if (core.domStyle.isVertical) { - music.width = 1248; - music.height = 2028; - } else { - music.width = 2028; - music.height = 1248; - } - } - mousedown(px, py) { - //鼠标按下时 - //console.log(px, py) - const makeBox = ([x, y], [w, h]) => { - return [ - [x, y], - [x + w, y + h], - ]; - }; - const inRect = ([x, y], [ - [sx, sy], - [dx, dy] - ]) => { - return sx <= x && x <= dx && sy <= y && y <= dy; - }; - const pos = [px, py]; - const backbox = makeBox([15, 35], [210, 90]); - if (inRect(pos, backbox)) { - //离开按钮是一致的,其余的记区分横竖屏 - music.style.display = "none"; - core.clearMap(ctx); - core.unregisterAnimationFrame("music"); - audio.src = ""; - core.restart(); + //更新 + update() { + this.background(); + this.drawUI(); + } + background() { + //画布大小设置 + if (core.domStyle.isVertical) { + music.width = 1248; + music.height = 2028; + } else { + music.width = 2028; + music.height = 1248; + } + } + mousedown(px, py) { + //鼠标按下时 + //console.log(px, py) + const makeBox = ([x, y], [w, h]) => { + return [ + [x, y], + [x + w, y + h], + ]; + }; + const inRect = ([x, y], [[sx, sy], [dx, dy]]) => { + return sx <= x && x <= dx && sy <= y && y <= dy; + }; + const pos = [px, py]; + const backbox = makeBox([15, 35], [210, 90]); + if (inRect(pos, backbox)) { + //离开按钮是一致的,其余的记区分横竖屏 + music.style.display = "none"; + core.clearMap(ctx); + core.unregisterAnimationFrame("music"); + audio.src = ""; + core.restart(); - return; - } - if (core.domStyle.isVertical) { - //竖屏 + return; + } + if (core.domStyle.isVertical) { + //竖屏 - const pageupbox = makeBox([100, 1230], [200, 100]); - const pagedownbox = makeBox([950, 1230], [200, 100]); - const musicbox = makeBox( - [100, 200], - [1048, this.musicMx[page].length * 100] - ); - const beforebox = makeBox([120, 1720], [100, 100]); - const afterbox = makeBox([780, 1720], [100, 100]); - const playbox = makeBox([420, 1680], [200, 200]); - const typebox = makeBox([1040, 1700], [120, 120]); - const changebox = makeBox([100, 1590], [1048, 20]); - const volumebox = makeBox([250, 1940], [1050, 20]); - if (inRect(pos, pageupbox)) { - if (page !== 0) page -= 1; - return; - } - if (inRect(pos, pagedownbox)) { - if (page !== this.musicMx.length - 1) page += 1; - return; - } - if (inRect(pos, playbox)) { - if (this.stop) { - this.stop = !this.stop; - audio.play(); - } else { - this.stop = !this.stop; - audio.pause(); - } - return; - } - if (inRect(pos, beforebox)) { - switch (this.type) { - case "danqu": - audio.currentTime = 0; - if (!this.stop) audio.play(); - this.stop = false; - page = this.selection[0]; + const pageupbox = makeBox([100, 1230], [200, 100]); + const pagedownbox = makeBox([950, 1230], [200, 100]); + const musicbox = makeBox( + [100, 200], + [1048, this.musicMx[page].length * 100] + ); + const beforebox = makeBox([120, 1720], [100, 100]); + const afterbox = makeBox([780, 1720], [100, 100]); + const playbox = makeBox([420, 1680], [200, 200]); + const typebox = makeBox([1040, 1700], [120, 120]); + const changebox = makeBox([100, 1590], [1048, 20]); + const volumebox = makeBox([250, 1940], [1050, 20]); + if (inRect(pos, pageupbox)) { + if (page !== 0) page -= 1; + return; + } + if (inRect(pos, pagedownbox)) { + if (page !== this.musicMx.length - 1) page += 1; + return; + } + if (inRect(pos, playbox)) { + if (this.stop) { + this.stop = !this.stop; + audio.play(); + } else { + this.stop = !this.stop; + audio.pause(); + } + return; + } + if (inRect(pos, beforebox)) { + switch (this.type) { + case "danqu": + audio.currentTime = 0; + if (!this.stop) audio.play(); + this.stop = false; + page = this.selection[0]; - break; - case "xunhuan": - if (this.selection[1] === 0) { - if (this.selection[0] === 0) { - this.selection[0] = this.musicMx.length - 1; - this.selection[1] = - this.musicMx[this.selection[0]].length - 1; - } else { - this.selection[0] -= 1; - this.selection[1] = - this.musicMx[this.selection[0]].length - 1; - } - } else { - this.selection[1] -= 1; - } - this.randomList.indexOf( - this.musicMx[this.selection[0]][this.selection[1]] - ); - page = this.selection[0]; - audio.src = - "project/bgms/" + - this.musicMx[this.selection[0]][this.selection[1]]; + break; + case "xunhuan": + if (this.selection[1] === 0) { + if (this.selection[0] === 0) { + this.selection[0] = this.musicMx.length - 1; + this.selection[1] = + this.musicMx[this.selection[0]].length - 1; + } else { + this.selection[0] -= 1; + this.selection[1] = + this.musicMx[this.selection[0]].length - 1; + } + } else { + this.selection[1] -= 1; + } + this.randomList.indexOf( + this.musicMx[this.selection[0]][this.selection[1]] + ); + page = this.selection[0]; + audio.src = + "project/bgms/" + + this.musicMx[this.selection[0]][this.selection[1]]; - if (!this.stop) audio.play(); - this.stop = false; - break; - case "suiji": - if (this.random > 0) { - this.random -= 1; - } else { - this.random = this.randomList.length - 1; - } - this.selection[0] = this.musicMx.findIndex((v) => - v.includes(this.randomList[this.random]) - ); - this.selection[1] = this.musicMx[this.selection[0]].indexOf( - this.randomList[this.random] - ); - audio.src = - "project/bgms/" + - this.musicMx[this.selection[0]][this.selection[1]]; - page = this.selection[0]; + if (!this.stop) audio.play(); + this.stop = false; + break; + case "suiji": + if (this.random > 0) { + this.random -= 1; + } else { + this.random = this.randomList.length - 1; + } + this.selection[0] = this.musicMx.findIndex((v) => + v.includes(this.randomList[this.random]) + ); + this.selection[1] = this.musicMx[this.selection[0]].indexOf( + this.randomList[this.random] + ); + audio.src = + "project/bgms/" + + this.musicMx[this.selection[0]][this.selection[1]]; + page = this.selection[0]; - if (!this.stop) audio.play(); - this.stop = false; - break; - } - return; - } - if (inRect(pos, afterbox)) { - switch (this.type) { - case "danqu": - audio.currentTime = 0; - if (!this.stop) audio.play(); - this.stop = false; - page = this.selection[0]; - break; - case "xunhuan": - if ( - this.selection[1] === - this.musicMx[this.selection[0]].length - 1 - ) { - if (this.selection[0] === this.musicMx.length - 1) { - this.selection[0] = 0; - this.selection[1] = 0; - } else { - this.selection[0] += 1; - this.selection[1] = 0; - } - } else { - this.selection[1] += 1; - } - this.random = this.randomList.indexOf( - this.musicMx[this.selection[0]][this.selection[1]] - ); - page = this.selection[0]; - audio.src = - "project/bgms/" + - this.musicMx[this.selection[0]][this.selection[1]]; + if (!this.stop) audio.play(); + this.stop = false; + break; + } + return; + } + if (inRect(pos, afterbox)) { + switch (this.type) { + case "danqu": + audio.currentTime = 0; + if (!this.stop) audio.play(); + this.stop = false; + page = this.selection[0]; + break; + case "xunhuan": + if ( + this.selection[1] === + this.musicMx[this.selection[0]].length - 1 + ) { + if (this.selection[0] === this.musicMx.length - 1) { + this.selection[0] = 0; + this.selection[1] = 0; + } else { + this.selection[0] += 1; + this.selection[1] = 0; + } + } else { + this.selection[1] += 1; + } + this.random = this.randomList.indexOf( + this.musicMx[this.selection[0]][this.selection[1]] + ); + page = this.selection[0]; + audio.src = + "project/bgms/" + + this.musicMx[this.selection[0]][this.selection[1]]; - if (!this.stop) audio.play(); - this.stop = false; - break; - case "suiji": - if (this.random < this.randomList.length - 1) { - this.random += 1; - } else { - this.random = 0; - } - this.selection[0] = this.musicMx.findIndex((v) => - v.includes(this.randomList[this.random]) - ); - this.selection[1] = this.musicMx[this.selection[0]].indexOf( - this.randomList[this.random] - ); - audio.src = - "project/bgms/" + - this.musicMx[this.selection[0]][this.selection[1]]; + if (!this.stop) audio.play(); + this.stop = false; + break; + case "suiji": + if (this.random < this.randomList.length - 1) { + this.random += 1; + } else { + this.random = 0; + } + this.selection[0] = this.musicMx.findIndex((v) => + v.includes(this.randomList[this.random]) + ); + this.selection[1] = this.musicMx[this.selection[0]].indexOf( + this.randomList[this.random] + ); + audio.src = + "project/bgms/" + + this.musicMx[this.selection[0]][this.selection[1]]; - page = this.selection[0]; - if (!this.stop) audio.play(); - this.stop = false; - break; - } - return; - } - if (inRect(pos, typebox)) { - switch (this.type) { - case "danqu": - this.type = "xunhuan"; - break; - case "xunhuan": - this.type = "suiji"; - break; - case "suiji": - this.type = "danqu"; - break; - } - return; - } - if (inRect(pos, musicbox)) { - const index = Math.floor((py - 200) / 100); - if (page !== this.selection[0] || index !== this.selection[1]) { - this.selection[0] = page; - this.selection[1] = index; - this.randomList.indexOf( - this.musicMx[this.selection[0]][this.selection[1]] - ); - audio.src = "project/bgms/" + this.musicMx[page][index]; + page = this.selection[0]; + if (!this.stop) audio.play(); + this.stop = false; + break; + } + return; + } + if (inRect(pos, typebox)) { + switch (this.type) { + case "danqu": + this.type = "xunhuan"; + break; + case "xunhuan": + this.type = "suiji"; + break; + case "suiji": + this.type = "danqu"; + break; + } + return; + } + if (inRect(pos, musicbox)) { + const index = Math.floor((py - 200) / 100); + if (page !== this.selection[0] || index !== this.selection[1]) { + this.selection[0] = page; + this.selection[1] = index; + this.randomList.indexOf( + this.musicMx[this.selection[0]][this.selection[1]] + ); + audio.src = "project/bgms/" + this.musicMx[page][index]; - if (!this.stop) audio.play(); - this.stop = false; - } else { - if (this.stop) { - this.stop = !this.stop; - audio.play(); - } else { - this.stop = !this.stop; - audio.pause(); - } - } - return; - } - if (inRect(pos, changebox)) { - const time = Math.floor(((px - 100) / 1000) * audio.duration); + if (!this.stop) audio.play(); + this.stop = false; + } else { + if (this.stop) { + this.stop = !this.stop; + audio.play(); + } else { + this.stop = !this.stop; + audio.pause(); + } + } + return; + } + if (inRect(pos, changebox)) { + const time = Math.floor(((px - 100) / 1000) * audio.duration); - audio.pause(); - audio.currentTime = time; + audio.pause(); + audio.currentTime = time; - ischange = true; - } - if (inRect(pos, volumebox)) { - const time = Math.min(Math.max((px - 250) / 800, 0), 1); - audio.volume = time; - isvolume = true; - } - } else { - //横屏 - const pageupbox = makeBox([1050, 1100], [200, 100]); - const pagedownbox = makeBox([1550, 1100], [200, 100]); - const musicbox = makeBox( - [900, 100], - [1000, this.musicMx[page].length * 100] - ); - const beforebox = makeBox([135, 740], [50, 50]); - const afterbox = makeBox([450, 740], [50, 50]); - const playbox = makeBox([250, 700], [200, 200]); - const typebox = makeBox([600, 700], [100, 100]); - const changebox = makeBox([100, 590], [600, 20]); - const volumebox = makeBox([100, 990], [600, 20]); - if (inRect(pos, pageupbox)) { - if (page !== 0) page -= 1; - return; - } - if (inRect(pos, pagedownbox)) { - if (page !== this.musicMx.length - 1) page += 1; - return; - } - if (inRect(pos, playbox)) { - if (this.stop) { - this.stop = !this.stop; - audio.play(); - } else { - this.stop = !this.stop; - audio.pause(); - } - return; - } - if (inRect(pos, beforebox)) { - switch (this.type) { - case "danqu": - audio.currentTime = 0; - if (!this.stop) audio.play(); - this.stop = false; - page = this.selection[0]; + ischange = true; + } + if (inRect(pos, volumebox)) { + const time = Math.min(Math.max((px - 250) / 800, 0), 1); + audio.volume = time; + isvolume = true; + } + } else { + //横屏 + const pageupbox = makeBox([1050, 1100], [200, 100]); + const pagedownbox = makeBox([1550, 1100], [200, 100]); + const musicbox = makeBox( + [900, 100], + [1000, this.musicMx[page].length * 100] + ); + const beforebox = makeBox([135, 740], [50, 50]); + const afterbox = makeBox([450, 740], [50, 50]); + const playbox = makeBox([250, 700], [200, 200]); + const typebox = makeBox([600, 700], [100, 100]); + const changebox = makeBox([100, 590], [600, 20]); + const volumebox = makeBox([100, 990], [600, 20]); + if (inRect(pos, pageupbox)) { + if (page !== 0) page -= 1; + return; + } + if (inRect(pos, pagedownbox)) { + if (page !== this.musicMx.length - 1) page += 1; + return; + } + if (inRect(pos, playbox)) { + if (this.stop) { + this.stop = !this.stop; + audio.play(); + } else { + this.stop = !this.stop; + audio.pause(); + } + return; + } + if (inRect(pos, beforebox)) { + switch (this.type) { + case "danqu": + audio.currentTime = 0; + if (!this.stop) audio.play(); + this.stop = false; + page = this.selection[0]; - break; - case "xunhuan": - if (this.selection[1] === 0) { - if (this.selection[0] === 0) { - this.selection[0] = this.musicMx.length - 1; - this.selection[1] = - this.musicMx[this.selection[0]].length - 1; - } else { - this.selection[0] -= 1; - this.selection[1] = - this.musicMx[this.selection[0]].length - 1; - } - } else { - this.selection[1] -= 1; - } - this.random = this.randomList.indexOf( - this.musicMx[this.selection[0]][this.selection[1]] - ); - page = this.selection[0]; - audio.src = - "project/bgms/" + - this.musicMx[this.selection[0]][this.selection[1]]; + break; + case "xunhuan": + if (this.selection[1] === 0) { + if (this.selection[0] === 0) { + this.selection[0] = this.musicMx.length - 1; + this.selection[1] = + this.musicMx[this.selection[0]].length - 1; + } else { + this.selection[0] -= 1; + this.selection[1] = + this.musicMx[this.selection[0]].length - 1; + } + } else { + this.selection[1] -= 1; + } + this.random = this.randomList.indexOf( + this.musicMx[this.selection[0]][this.selection[1]] + ); + page = this.selection[0]; + audio.src = + "project/bgms/" + + this.musicMx[this.selection[0]][this.selection[1]]; - if (!this.stop) audio.play(); - this.stop = false; - break; - case "suiji": - if (this.random > 0) { - this.random -= 1; - } else { - this.random = this.randomList.length - 1; - } - this.selection[0] = this.musicMx.findIndex((v) => - v.includes(this.randomList[this.random]) - ); - this.selection[1] = this.musicMx[this.selection[0]].indexOf( - this.randomList[this.random] - ); - audio.src = - "project/bgms/" + - this.musicMx[this.selection[0]][this.selection[1]]; - page = this.selection[0]; + if (!this.stop) audio.play(); + this.stop = false; + break; + case "suiji": + if (this.random > 0) { + this.random -= 1; + } else { + this.random = this.randomList.length - 1; + } + this.selection[0] = this.musicMx.findIndex((v) => + v.includes(this.randomList[this.random]) + ); + this.selection[1] = this.musicMx[this.selection[0]].indexOf( + this.randomList[this.random] + ); + audio.src = + "project/bgms/" + + this.musicMx[this.selection[0]][this.selection[1]]; + page = this.selection[0]; - if (!this.stop) audio.play(); - this.stop = false; - break; - } - return; - } - if (inRect(pos, afterbox)) { - switch (this.type) { - case "danqu": - audio.currentTime = 0; - if (!this.stop) audio.play(); - this.stop = false; - page = this.selection[0]; - break; - case "xunhuan": - if ( - this.selection[1] === - this.musicMx[this.selection[0]].length - 1 - ) { - if (this.selection[0] === this.musicMx.length - 1) { - this.selection[0] = 0; - this.selection[1] = 0; - } else { - this.selection[0] += 1; - this.selection[1] = 0; - } - } else { - this.selection[1] += 1; - } - this.randomList.findIndex( - (v) => - v === this.musicMx[this.selection[0]][this.selection[1]] - ); - page = this.selection[0]; - audio.src = - "project/bgms/" + - this.musicMx[this.selection[0]][this.selection[1]]; + if (!this.stop) audio.play(); + this.stop = false; + break; + } + return; + } + if (inRect(pos, afterbox)) { + switch (this.type) { + case "danqu": + audio.currentTime = 0; + if (!this.stop) audio.play(); + this.stop = false; + page = this.selection[0]; + break; + case "xunhuan": + if ( + this.selection[1] === + this.musicMx[this.selection[0]].length - 1 + ) { + if (this.selection[0] === this.musicMx.length - 1) { + this.selection[0] = 0; + this.selection[1] = 0; + } else { + this.selection[0] += 1; + this.selection[1] = 0; + } + } else { + this.selection[1] += 1; + } + this.randomList.findIndex( + (v) => + v === this.musicMx[this.selection[0]][this.selection[1]] + ); + page = this.selection[0]; + audio.src = + "project/bgms/" + + this.musicMx[this.selection[0]][this.selection[1]]; - if (!this.stop) audio.play(); - this.stop = false; - break; - case "suiji": - if (this.random < this.randomList.length - 1) { - this.random += 1; - } else { - this.random = 0; - } - this.selection[0] = this.musicMx.findIndex((v) => - v.includes(this.randomList[this.random]) - ); - this.selection[1] = this.musicMx[this.selection[0]].indexOf( - main.core.ui.music.randomList[main.core.ui.music.random] - ); - audio.src = - "project/bgms/" + - this.musicMx[this.selection[0]][this.selection[1]]; + if (!this.stop) audio.play(); + this.stop = false; + break; + case "suiji": + if (this.random < this.randomList.length - 1) { + this.random += 1; + } else { + this.random = 0; + } + this.selection[0] = this.musicMx.findIndex((v) => + v.includes(this.randomList[this.random]) + ); + this.selection[1] = this.musicMx[this.selection[0]].indexOf( + main.core.ui.music.randomList[main.core.ui.music.random] + ); + audio.src = + "project/bgms/" + + this.musicMx[this.selection[0]][this.selection[1]]; - page = this.selection[0]; - if (!this.stop) audio.play(); - this.stop = false; - break; - } - return; - } - if (inRect(pos, typebox)) { - switch (this.type) { - case "danqu": - this.type = "xunhuan"; - break; - case "xunhuan": - this.type = "suiji"; - break; - case "suiji": - this.type = "danqu"; - break; - } - return; - } - if (inRect(pos, musicbox)) { - const index = Math.floor((py - 100) / 100); - if (page !== this.selection[0] || index !== this.selection[1]) { - this.selection[0] = page; - this.selection[1] = index; - this.randomList.indexOf( - (v) => v === this.musicMx[this.selection[0]][this.selection[1]] - ); - audio.src = "project/bgms/" + this.musicMx[page][index]; + page = this.selection[0]; + if (!this.stop) audio.play(); + this.stop = false; + break; + } + return; + } + if (inRect(pos, typebox)) { + switch (this.type) { + case "danqu": + this.type = "xunhuan"; + break; + case "xunhuan": + this.type = "suiji"; + break; + case "suiji": + this.type = "danqu"; + break; + } + return; + } + if (inRect(pos, musicbox)) { + const index = Math.floor((py - 100) / 100); + if (page !== this.selection[0] || index !== this.selection[1]) { + this.selection[0] = page; + this.selection[1] = index; + this.randomList.indexOf( + (v) => v === this.musicMx[this.selection[0]][this.selection[1]] + ); + audio.src = "project/bgms/" + this.musicMx[page][index]; - if (!this.stop) audio.play(); - this.stop = false; - } else { - if (this.stop) { - this.stop = !this.stop; - audio.play(); - } else { - this.stop = !this.stop; - audio.pause(); - } - } - return; - } - if (inRect(pos, changebox)) { - const time = Math.floor(((px - 100) / 600) * audio.duration); + if (!this.stop) audio.play(); + this.stop = false; + } else { + if (this.stop) { + this.stop = !this.stop; + audio.play(); + } else { + this.stop = !this.stop; + audio.pause(); + } + } + return; + } + if (inRect(pos, changebox)) { + const time = Math.floor(((px - 100) / 600) * audio.duration); - audio.pause(); - audio.currentTime = time; + audio.pause(); + audio.currentTime = time; - ischange = true; - } - if (inRect(pos, volumebox)) { - const time = Math.min(Math.max((px - 100) / 600, 0), 1); - audio.volume = time; - isvolume = true; - } - } - } - mousemove(px, py) { - if (ischange) { - if (core.domStyle.isVertical) { - const time = Math.min( - Math.max(Math.floor(((px - 100) / 600) * audio.duration), 0), - audio.duration - ); + ischange = true; + } + if (inRect(pos, volumebox)) { + const time = Math.min(Math.max((px - 100) / 600, 0), 1); + audio.volume = time; + isvolume = true; + } + } + } + mousemove(px, py) { + if (ischange) { + if (core.domStyle.isVertical) { + const time = Math.min( + Math.max(Math.floor(((px - 100) / 600) * audio.duration), 0), + audio.duration + ); - audio.currentTime = time; - } else { - const time = Math.min( - Math.max(Math.floor(((px - 100) / 600) * audio.duration), 0), - audio.duration - ); + audio.currentTime = time; + } else { + const time = Math.min( + Math.max(Math.floor(((px - 100) / 600) * audio.duration), 0), + audio.duration + ); - audio.currentTime = time; - } - } - if (isvolume) { - if (core.domStyle.isVertical) { - const time = Math.min(Math.max((px - 250) / 800, 0), 1); - audio.volume = time; - } else { - const time = Math.min(Math.max((px - 100) / 600, 0), 1); - audio.volume = time; - } - } - } + audio.currentTime = time; + } + } + if (isvolume) { + if (core.domStyle.isVertical) { + const time = Math.min(Math.max((px - 250) / 800, 0), 1); + audio.volume = time; + } else { + const time = Math.min(Math.max((px - 100) / 600, 0), 1); + audio.volume = time; + } + } + } - drawUI() { - //绘制页面 - core.clearMap(music); - const bgVertical = core.material.images.images["bg_2010.webp"]; //竖屏背景 - const bg = core.material.images.images["bg_5043.webp"]; //竖屏背景 - if (core.domStyle.isVertical) { - //竖屏 + drawUI() { + //绘制页面 + core.clearMap(music); + const bgVertical = core.material.images.images["bg_2010.webp"]; //竖屏背景 + const bg = core.material.images.images["bg_5043.webp"]; //竖屏背景 + if (core.domStyle.isVertical) { + //竖屏 - core.fillRect(ctx, 0, 0, 1248, 2028, "#000000"); //黑色背景 - ctx.globalAlpha = 0.3; //透明度 - if (bgVertical) - ctx.drawImage(bgVertical, 0, 0, 1280, 1500, 0, 0, 1248, 2028); //绘制半透明背景图片 - ctx.globalAlpha = 1; //恢复为不透明 + core.fillRect(ctx, 0, 0, 1248, 2028, "#000000"); //黑色背景 + ctx.globalAlpha = 0.3; //透明度 + if (bgVertical) + ctx.drawImage(bgVertical, 0, 0, 1280, 1500, 0, 0, 1248, 2028); //绘制半透明背景图片 + ctx.globalAlpha = 1; //恢复为不透明 - core.setTextAlign(ctx, "center"); - core.fillBoldText1( - ctx, - "◀离开", - 110, - 100, - "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(66, true) - ); + core.setTextAlign(ctx, "center"); + core.fillBoldText1( + ctx, + "◀离开", + 110, + 100, + "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(66, true) + ); - ctx.strokeStyle = "#FFFFFF"; - ctx.lineWidth = 3; - ctx.beginPath(); - ctx.moveTo(100, 200); - ctx.lineTo(1148, 200); + ctx.strokeStyle = "#FFFFFF"; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.moveTo(100, 200); + ctx.lineTo(1148, 200); - ctx.stroke(); - let posy = 300; - const indexList = this.musicMx[page]; - core.setTextAlign(ctx, "left"); - for (let i = 0; i < indexList.length; i++) { - const text = this.musicname[indexList[i]]; - core.fillBoldText1( - ctx, - text, - 150, - posy - 30, - page === this.selection[0] && i === this.selection[1] ? - "#FFFFFF" : - "#444444", - "#000000", - 6, - core.ui._buildFont(66, true) - ); - ctx.strokeStyle = "#FFFFFF"; - ctx.lineWidth = 3; - ctx.beginPath(); - ctx.moveTo(100, posy); - ctx.lineTo(1148, posy); - ctx.stroke(); - posy += 100; - } - ctx.beginPath(); - ctx.moveTo(100, 1210); - ctx.lineTo(1148, 1210); - ctx.moveTo(100, 1200); - ctx.lineTo(1148, 1200); - ctx.stroke(); + ctx.stroke(); + let posy = 300; + const indexList = this.musicMx[page]; + core.setTextAlign(ctx, "left"); + for (let i = 0; i < indexList.length; i++) { + const text = this.musicname[indexList[i]]; + core.fillBoldText1( + ctx, + text, + 150, + posy - 30, + page === this.selection[0] && i === this.selection[1] + ? "#FFFFFF" + : "#444444", + "#000000", + 6, + core.ui._buildFont(66, true) + ); + ctx.strokeStyle = "#FFFFFF"; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.moveTo(100, posy); + ctx.lineTo(1148, posy); + ctx.stroke(); + posy += 100; + } + ctx.beginPath(); + ctx.moveTo(100, 1210); + ctx.lineTo(1148, 1210); + ctx.moveTo(100, 1200); + ctx.lineTo(1148, 1200); + ctx.stroke(); - core.fillBoldText1( - ctx, - "上一页", - 100, - 1300, - page === 0 ? "#444444" : "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(66, true) - ); + core.fillBoldText1( + ctx, + "上一页", + 100, + 1300, + page === 0 ? "#444444" : "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(66, true) + ); - core.fillBoldText1( - ctx, - page + 1 + "/" + this.musicMx.length, - 580, - 1300, - "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(66, true) - ); - core.fillBoldText1( - ctx, - "下一页", - 950, - 1300, - page === this.musicMx.length - 1 ? "#444444" : "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(66, true) - ); + core.fillBoldText1( + ctx, + page + 1 + "/" + this.musicMx.length, + 580, + 1300, + "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(66, true) + ); + core.fillBoldText1( + ctx, + "下一页", + 950, + 1300, + page === this.musicMx.length - 1 ? "#444444" : "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(66, true) + ); - ctx.strokeStyle = "#ffffff"; - ctx.lineWidth = 3; - ctx.beginPath(); - ctx.moveTo(100, 1600); - ctx.lineTo(1148, 1600); - ctx.stroke(); - ctx.fillStyle = "#ffffff"; - ctx.font = "bold 96px Verdana"; - ctx.fillText("|", 100, 1797); - ctx.fillText("◀", 115, 1800); - ctx.beginPath(); - ctx.arc(505, 1770, 80, 0, 3 * Math.PI); - ctx.stroke(); - ctx.fillText("|", 835, 1797); - ctx.fillText("▶", 785, 1800); - if (this.stop) { - ctx.fillText("▶", 473, 1797); - } else { - ctx.fillText("||", 453, 1794); - } + ctx.strokeStyle = "#ffffff"; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.moveTo(100, 1600); + ctx.lineTo(1148, 1600); + ctx.stroke(); + ctx.fillStyle = "#ffffff"; + ctx.font = "bold 96px Verdana"; + ctx.fillText("|", 100, 1797); + ctx.fillText("◀", 115, 1800); + ctx.beginPath(); + ctx.arc(505, 1770, 80, 0, 3 * Math.PI); + ctx.stroke(); + ctx.fillText("|", 835, 1797); + ctx.fillText("▶", 785, 1800); + if (this.stop) { + ctx.fillText("▶", 473, 1797); + } else { + ctx.fillText("||", 453, 1794); + } - const img = core.material.images.images[this.type + ".webp"]; - if (img) ctx.drawImage(img, 1000, 1655, 200, 200); - core.setTextAlign(ctx, "center"); - ctx.font = "bold 52px Verdana"; - ctx.fillText("当前歌曲", 625, 1397); - ctx.fillText( - this.musicname[this.musicMx[this.selection[0]][this.selection[1]]], - 625, - 1507 - ); + const img = core.material.images.images[this.type + ".webp"]; + if (img) ctx.drawImage(img, 1000, 1655, 200, 200); + core.setTextAlign(ctx, "center"); + ctx.font = "bold 52px Verdana"; + ctx.fillText("当前歌曲", 625, 1397); + ctx.fillText( + this.musicname[this.musicMx[this.selection[0]][this.selection[1]]], + 625, + 1507 + ); - ctx.font = "bold 36px Verdana"; - const thistime = audio.currentTime; + ctx.font = "bold 36px Verdana"; + const thistime = audio.currentTime; - if (thistime) { - const timetext = - Math.floor(thistime / 60) - .toString() - .padStart(2, "0") + - ":" + - Math.floor(thistime % 60) - .toString() - .padStart(2, "0"); - ctx.fillText(timetext, 960, 1650); - } else { - const timetext = "00:00"; - ctx.fillText(timetext, 960, 1650); - } - ctx.fillText("/", 1030, 1650); - const fulltime = audio.duration; + if (thistime) { + const timetext = + Math.floor(thistime / 60) + .toString() + .padStart(2, "0") + + ":" + + Math.floor(thistime % 60) + .toString() + .padStart(2, "0"); + ctx.fillText(timetext, 960, 1650); + } else { + const timetext = "00:00"; + ctx.fillText(timetext, 960, 1650); + } + ctx.fillText("/", 1030, 1650); + const fulltime = audio.duration; - if (fulltime) { - const timetext = - Math.floor(fulltime / 60) - .toString() - .padStart(2, "0") + - ":" + - Math.floor(fulltime % 60) - .toString() - .padStart(2, "0"); - ctx.fillText(timetext, 1100, 1650); - } else { - const timetext = "00:00"; - ctx.fillText(timetext, 1100, 1650); - } - ctx.strokeStyle = "#ffffff"; - ctx.lineWidth = 9; - ctx.fillStyle = "rgba(255,255,255,0.5)"; - const pointx = (1048 * thistime) / fulltime + 100; - if (fulltime && thistime) { - ctx.beginPath(); - ctx.moveTo(100, 1600); - ctx.lineTo(pointx, 1600); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(pointx, 1600, 10, 0, 2 * Math.PI); - ctx.fill(); - } else { - ctx.beginPath(); - ctx.arc(100, 1600, 10, 0, 2 * Math.PI); - ctx.fill(); - } + if (fulltime) { + const timetext = + Math.floor(fulltime / 60) + .toString() + .padStart(2, "0") + + ":" + + Math.floor(fulltime % 60) + .toString() + .padStart(2, "0"); + ctx.fillText(timetext, 1100, 1650); + } else { + const timetext = "00:00"; + ctx.fillText(timetext, 1100, 1650); + } + ctx.strokeStyle = "#ffffff"; + ctx.lineWidth = 9; + ctx.fillStyle = "rgba(255,255,255,0.5)"; + const pointx = (1048 * thistime) / fulltime + 100; + if (fulltime && thistime) { + ctx.beginPath(); + ctx.moveTo(100, 1600); + ctx.lineTo(pointx, 1600); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(pointx, 1600, 10, 0, 2 * Math.PI); + ctx.fill(); + } else { + ctx.beginPath(); + ctx.arc(100, 1600, 10, 0, 2 * Math.PI); + ctx.fill(); + } - ctx.fillStyle = "#ffffff"; - ctx.font = "bold 48px Verdana"; - ctx.fillText("音量", 150, 1970); - ctx.lineWidth = 3; - ctx.beginPath(); - ctx.moveTo(250, 1950); - ctx.lineTo(1050, 1950); - ctx.stroke(); - ctx.strokeStyle = "#ffffff"; - ctx.lineWidth = 9; - ctx.fillStyle = "rgba(255,255,255,0.5)"; + ctx.fillStyle = "#ffffff"; + ctx.font = "bold 48px Verdana"; + ctx.fillText("音量", 150, 1970); + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.moveTo(250, 1950); + ctx.lineTo(1050, 1950); + ctx.stroke(); + ctx.strokeStyle = "#ffffff"; + ctx.lineWidth = 9; + ctx.fillStyle = "rgba(255,255,255,0.5)"; - ctx.beginPath(); - ctx.moveTo(250, 1950); - ctx.lineTo(800 * audio.volume + 250, 1950); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(800 * audio.volume + 250, 1950, 10, 0, 2 * Math.PI); - ctx.fill(); - core.fillBoldText1( - ctx, - Math.floor(100 * audio.volume), - 1120, - 1970, - "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(48, true) - ); - } else { - //横屏 - core.fillRect(ctx, 0, 0, 2028, 1248, "#000000"); //黑色背景 - ctx.globalAlpha = 0.5; //透明度 - if (bg) ctx.drawImage(bg, 0, 0, 1280, 720, 0, 0, 2028, 1248); //绘制半透明背景图片 - ctx.globalAlpha = 1; //恢复为不透明 - core.setTextAlign(ctx, "center"); + ctx.beginPath(); + ctx.moveTo(250, 1950); + ctx.lineTo(800 * audio.volume + 250, 1950); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(800 * audio.volume + 250, 1950, 10, 0, 2 * Math.PI); + ctx.fill(); + core.fillBoldText1( + ctx, + Math.floor(100 * audio.volume), + 1120, + 1970, + "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(48, true) + ); + } else { + //横屏 + core.fillRect(ctx, 0, 0, 2028, 1248, "#000000"); //黑色背景 + ctx.globalAlpha = 0.5; //透明度 + if (bg) ctx.drawImage(bg, 0, 0, 1280, 720, 0, 0, 2028, 1248); //绘制半透明背景图片 + ctx.globalAlpha = 1; //恢复为不透明 + core.setTextAlign(ctx, "center"); - core.fillBoldText1( - ctx, - "◀离开", - 110, - 100, - "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(66, true) - ); - //core.fillRect(ctx, 440, 760, 50, 50) - ctx.strokeStyle = "#FFFFFF"; - ctx.lineWidth = 3; - ctx.beginPath(); - ctx.moveTo(800, 100); - ctx.lineTo(800, 1148); - ctx.moveTo(900, 100); - ctx.lineTo(1900, 100); - ctx.stroke(); - let posy = 200; - const indexList = this.musicMx[page]; - core.setTextAlign(ctx, "left"); - for (let i = 0; i < indexList.length; i++) { - const text = this.musicname[indexList[i]]; - core.fillBoldText1( - ctx, - text, - 950, - posy - 30, - page === this.selection[0] && i === this.selection[1] ? - "#FFFFFF" : - "#444444", - "#000000", - 6, - core.ui._buildFont(66, true) - ); - ctx.strokeStyle = "#FFFFFF"; - ctx.lineWidth = 3; - ctx.beginPath(); - ctx.moveTo(900, posy); - ctx.lineTo(1900, posy); - ctx.stroke(); - posy += 100; - } - core.fillBoldText1( - ctx, - "上一页", - 1050, - 1200 - 30, - page === 0 ? "#444444" : "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(66, true) - ); + core.fillBoldText1( + ctx, + "◀离开", + 110, + 100, + "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(66, true) + ); + //core.fillRect(ctx, 440, 760, 50, 50) + ctx.strokeStyle = "#FFFFFF"; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.moveTo(800, 100); + ctx.lineTo(800, 1148); + ctx.moveTo(900, 100); + ctx.lineTo(1900, 100); + ctx.stroke(); + let posy = 200; + const indexList = this.musicMx[page]; + core.setTextAlign(ctx, "left"); + for (let i = 0; i < indexList.length; i++) { + const text = this.musicname[indexList[i]]; + core.fillBoldText1( + ctx, + text, + 950, + posy - 30, + page === this.selection[0] && i === this.selection[1] + ? "#FFFFFF" + : "#444444", + "#000000", + 6, + core.ui._buildFont(66, true) + ); + ctx.strokeStyle = "#FFFFFF"; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.moveTo(900, posy); + ctx.lineTo(1900, posy); + ctx.stroke(); + posy += 100; + } + core.fillBoldText1( + ctx, + "上一页", + 1050, + 1200 - 30, + page === 0 ? "#444444" : "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(66, true) + ); - core.fillBoldText1( - ctx, - page + 1 + "/" + this.musicMx.length, - 1350, - 1200 - 30, - "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(66, true) - ); - core.fillBoldText1( - ctx, - "下一页", - 1550, - 1200 - 30, - page === this.musicMx.length - 1 ? "#444444" : "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(66, true) - ); - ctx.strokeStyle = "#ffffff"; - ctx.lineWidth = 3; - ctx.beginPath(); - ctx.moveTo(100, 600); - ctx.lineTo(700, 600); - ctx.stroke(); - ctx.fillStyle = "#ffffff"; - ctx.font = "bold 48px Verdana"; - ctx.fillText("|", 130, 797); - ctx.fillText("◀", 140, 800); - ctx.beginPath(); - ctx.arc(310, 780, 50, 0, 2 * Math.PI); - ctx.stroke(); - if (this.stop) { - ctx.fillText("▶", 295, 797); - } else { - ctx.fillText("||", 285, 794); - } + core.fillBoldText1( + ctx, + page + 1 + "/" + this.musicMx.length, + 1350, + 1200 - 30, + "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(66, true) + ); + core.fillBoldText1( + ctx, + "下一页", + 1550, + 1200 - 30, + page === this.musicMx.length - 1 ? "#444444" : "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(66, true) + ); + ctx.strokeStyle = "#ffffff"; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.moveTo(100, 600); + ctx.lineTo(700, 600); + ctx.stroke(); + ctx.fillStyle = "#ffffff"; + ctx.font = "bold 48px Verdana"; + ctx.fillText("|", 130, 797); + ctx.fillText("◀", 140, 800); + ctx.beginPath(); + ctx.arc(310, 780, 50, 0, 2 * Math.PI); + ctx.stroke(); + if (this.stop) { + ctx.fillText("▶", 295, 797); + } else { + ctx.fillText("||", 285, 794); + } - ctx.fillText("|", 470, 797); - ctx.fillText("▶", 450, 800); - ctx.fillText("音量", 350, 900); - ctx.beginPath(); - ctx.moveTo(100, 1000); - ctx.lineTo(700, 1000); - ctx.stroke(); - ctx.strokeStyle = "#ffffff"; - ctx.lineWidth = 9; - ctx.fillStyle = "rgba(255,255,255,0.5)"; + ctx.fillText("|", 470, 797); + ctx.fillText("▶", 450, 800); + ctx.fillText("音量", 350, 900); + ctx.beginPath(); + ctx.moveTo(100, 1000); + ctx.lineTo(700, 1000); + ctx.stroke(); + ctx.strokeStyle = "#ffffff"; + ctx.lineWidth = 9; + ctx.fillStyle = "rgba(255,255,255,0.5)"; - ctx.beginPath(); - ctx.moveTo(100, 1000); - ctx.lineTo(600 * audio.volume + 100, 1000); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(600 * audio.volume + 100, 1000, 10, 0, 2 * Math.PI); - ctx.fill(); - core.fillBoldText1( - ctx, - Math.floor(100 * audio.volume), - 720, - 1010, - "#FFFFFF", - "#000000", - 6, - core.ui._buildFont(32, true) - ); - const img = core.material.images.images[this.type + ".webp"]; - if (img) ctx.drawImage(img, 580, 730, 100, 100); - core.setTextAlign(ctx, "center"); - ctx.font = "bold 48px Verdana"; - ctx.fillText("当前歌曲", 400, 297); - ctx.fillText( - this.musicname[this.musicMx[this.selection[0]][this.selection[1]]], - 400, - 397 - ); + ctx.beginPath(); + ctx.moveTo(100, 1000); + ctx.lineTo(600 * audio.volume + 100, 1000); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(600 * audio.volume + 100, 1000, 10, 0, 2 * Math.PI); + ctx.fill(); + core.fillBoldText1( + ctx, + Math.floor(100 * audio.volume), + 720, + 1010, + "#FFFFFF", + "#000000", + 6, + core.ui._buildFont(32, true) + ); + const img = core.material.images.images[this.type + ".webp"]; + if (img) ctx.drawImage(img, 580, 730, 100, 100); + core.setTextAlign(ctx, "center"); + ctx.font = "bold 48px Verdana"; + ctx.fillText("当前歌曲", 400, 297); + ctx.fillText( + this.musicname[this.musicMx[this.selection[0]][this.selection[1]]], + 400, + 397 + ); - ctx.font = "bold 36px Verdana"; - const thistime = audio.currentTime; + ctx.font = "bold 36px Verdana"; + const thistime = audio.currentTime; - if (thistime) { - const timetext = - Math.floor(thistime / 60) - .toString() - .padStart(2, "0") + - ":" + - Math.floor(thistime % 60) - .toString() - .padStart(2, "0"); - ctx.fillText(timetext, 510, 650); - } else { - const timetext = "00:00"; - ctx.fillText(timetext, 510, 650); - } - ctx.fillText("/", 580, 650); - const fulltime = audio.duration; + if (thistime) { + const timetext = + Math.floor(thistime / 60) + .toString() + .padStart(2, "0") + + ":" + + Math.floor(thistime % 60) + .toString() + .padStart(2, "0"); + ctx.fillText(timetext, 510, 650); + } else { + const timetext = "00:00"; + ctx.fillText(timetext, 510, 650); + } + ctx.fillText("/", 580, 650); + const fulltime = audio.duration; - if (fulltime) { - const timetext = - Math.floor(fulltime / 60) - .toString() - .padStart(2, "0") + - ":" + - Math.floor(fulltime % 60) - .toString() - .padStart(2, "0"); - ctx.fillText(timetext, 650, 650); - } else { - const timetext = "00:00"; - ctx.fillText(timetext, 650, 650); - } - ctx.strokeStyle = "#ffffff"; - ctx.lineWidth = 9; - ctx.fillStyle = "rgba(255,255,255,0.5)"; - const pointx = (600 * thistime) / fulltime + 100; - if (fulltime && thistime) { - ctx.beginPath(); - ctx.moveTo(100, 600); - ctx.lineTo(pointx, 600); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(pointx, 600, 10, 0, 2 * Math.PI); - ctx.fill(); - } else { - ctx.beginPath(); - ctx.arc(100, 600, 10, 0, 2 * Math.PI); - ctx.fill(); - } - } - } - } - core.ui.music = new musicclass(); - main.dom.musicMode.onclick = function () { - //点击开始页面的CG MODE进入cg回廊 - main.core.control.checkBgm(); - main.core.control.pauseBgm(); - audio.src = - "project/bgms/" + - main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ - main.core.ui.music.selection[1] - ]; - const arr = main.core.ui.music.musicMx.flat(Infinity); - main.core.ui.music.randomList = shuffle(arr); - main.core.ui.music.random = main.core.ui.music.randomList.indexOf( - main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ - main.core.ui.music.selection[1] - ] - ); - page = 0; - music.style.display = "block"; - let time = 0; - core.registerAnimationFrame("music", null, (temptime) => { - if (temptime > time + 1000 / 60) { - time = temptime; - main.core.ui.music.update(); - } - }); - }; -}, + if (fulltime) { + const timetext = + Math.floor(fulltime / 60) + .toString() + .padStart(2, "0") + + ":" + + Math.floor(fulltime % 60) + .toString() + .padStart(2, "0"); + ctx.fillText(timetext, 650, 650); + } else { + const timetext = "00:00"; + ctx.fillText(timetext, 650, 650); + } + ctx.strokeStyle = "#ffffff"; + ctx.lineWidth = 9; + ctx.fillStyle = "rgba(255,255,255,0.5)"; + const pointx = (600 * thistime) / fulltime + 100; + if (fulltime && thistime) { + ctx.beginPath(); + ctx.moveTo(100, 600); + ctx.lineTo(pointx, 600); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(pointx, 600, 10, 0, 2 * Math.PI); + ctx.fill(); + } else { + ctx.beginPath(); + ctx.arc(100, 600, 10, 0, 2 * Math.PI); + ctx.fill(); + } + } + } + } + core.ui.music = new musicclass(); + main.dom.musicMode.onclick = function () { + //点击开始页面的CG MODE进入cg回廊 + main.core.control.checkBgm(); + main.core.control.pauseBgm(); + audio.src = + "project/bgms/" + + main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ + main.core.ui.music.selection[1] + ]; + const arr = main.core.ui.music.musicMx.flat(Infinity); + main.core.ui.music.randomList = shuffle(arr); + main.core.ui.music.random = main.core.ui.music.randomList.indexOf( + main.core.ui.music.musicMx[main.core.ui.music.selection[0]][ + main.core.ui.music.selection[1] + ] + ); + page = 0; + music.style.display = "block"; + let time = 0; + core.registerAnimationFrame("music", null, (temptime) => { + if (temptime > time + 1000 / 60) { + time = temptime; + main.core.ui.music.update(); + } + }); + }; + }, "横屏切换": function () { // 在此增加新插件 this.triggerFullscreen = async function (full) { @@ -15629,10 +15620,13 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = */ - - const { OggOpusDecoder } = window["ogg-opus-decoder"]; - const { OggVorbisDecoder } = window["ogg-vorbis-decoder"]; + // 将__enable置为false将关闭插件 + let __enable = true; + if (!__enable || main.mode === "editor") return; + const { OggOpusDecoderWebWorker } = window["ogg-opus-decoder"]; + const { OggVorbisDecoderWebWorker } = window["ogg-vorbis-decoder"]; const { CodecParser } = window.CodecParser; + const { Transition, linear } = core.plugin.animate; const audio = new Audio(); @@ -15968,9 +15962,24 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = this.stream = stream; const reader = response.body?.getReader(); const targets = [...this.target]; - // try { - await Promise.all(targets.map((v) => v.start(stream, this, response))); + + await Promise.all(targets.map((v) => v.start(stream, this, response))); + if (reader && reader.read) { + // 开始流传输 + while (true) { + const { value, done } = await reader.read(); + await Promise.all( + targets.map(v => v.pump(value, done, response)) + ); + if (done) break; + } + } else { + // 如果不支持流传输 + const buffer = await response.arrayBuffer(); + const data = new Uint8Array(buffer); + await Promise.all(targets.map(v => v.pump(data, true, response))); + } // 开始流传输 while (true) { const { value, done } = await reader.read(); @@ -15980,9 +15989,8 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = this.loading = false; targets.forEach((v) => v.end(true)); - // } catch (e) { - // logger.error(26, this.url, String(e)); - // } + + // } cancel(reason) { @@ -15998,12 +16006,38 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = [AudioType.Wav, [52, 0x49, 0x46, 0x46]], [AudioType.Flac, [0x66, 0x4c, 0x61, 0x43]], [AudioType.Aac, [0xff, 0xf1]], - [AudioType.Aac, [0xff, 0xf9]], + [AudioType.Aac, [0xff, 0xf9]] ]; const oggHeaders = [ - [AudioType.Opus, [0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64]], + [AudioType.Opus, [0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64]] ]; + function checkAudioType(data) { + let audioType = ''; + // 检查头文件获取音频类型,仅检查前256个字节 + const toCheck = data.slice(0, 256); + for (const [type, value] of fileSignatures) { + if (value.every((v, i) => toCheck[i] === v)) { + audioType = type; + break; + } + } + if (audioType === AudioType.Ogg) { + // 如果是ogg的话,进一步判断是不是opus + for (const [key, value] of oggHeaders) { + const has = toCheck.some((_, i) => { + return value.every((v, ii) => toCheck[i + ii] === v); + }); + if (has) { + audioType = key; + break; + } + } + } + + return audioType; + } + const mimeTypeMap = { [AudioType.Aac]: "audio/aac", [AudioType.Flac]: "audio/flac", @@ -16017,29 +16051,11 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = return !isNil(data.isFirstPage); } class AudioStreamSource { - /** - * 注册一个解码器 - * @param type 要注册的解码器允许解码的类型 - * @param decoder 解码器对象 - */ - static registerDecoder(type, decoder) { - if (!this.decoderMap) this.decoderMap = new Map() - if (this.decoderMap.has(type)) { - console.warn( - "Audio stream decoder for audio type '" + - type + - "' has already existed." - ); - return; - } - this.decoderMap.set(type, decoder); - } - constructor(context) { - this.decoderMap = new Map(); this.output = context.createBufferSource(); /** 是否已经完全加载完毕 */ this.loaded = false; + /** 已经缓冲了多长时间,如果缓冲完那么跟歌曲时长一致 */ this.buffered = 0; /** 已经缓冲的采样点数量 */ @@ -16052,6 +16068,8 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = this.sampleRate = 0; //是否循环播放 this.loop = false; + /** 上一次播放是从何时开始的 */ + this.lastStartWhen = 0; /** 开始播放时刻 */ this.lastStartTime = 0; /** 上一次播放的缓存长度 */ @@ -16067,8 +16085,12 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = this.audioData = []; this.errored = false; + this.ac = context; + } + /** 当前已经播放了多长时间 */ + get currentTime() { + return this.ac.currentTime - this.lastStartTime + this.lastStartWhen; } - /** * 设置每个缓存数据的大小,默认为10秒钟一个缓存数据 * @param size 每个缓存数据的时长,单位秒 @@ -16087,24 +16109,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = if (!this.headerRecieved) { // 检查头文件获取音频类型,仅检查前256个字节 const toCheck = data.slice(0, 256); - for (const [type, value] of fileSignatures) { - if (value.every((v, i) => toCheck[i] === v)) { - this.audioType = type; - break; - } - } - if (this.audioType === AudioType.Ogg) { - // 如果是ogg的话,进一步判断是不是opus - for (const [key, value] of oggHeaders) { - const has = toCheck.some((_, i) => { - return value.every((v, ii) => toCheck[i + ii] === v); - }); - if (has) { - this.audioType = key; - break; - } - } - } + this.audioType = checkAudioType(data); if (!this.audioType) { console.error( "Unknown audio type. Header: '" + [...toCheck] @@ -16116,7 +16121,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = return; } // 创建解码器 - const Decoder = AudioStreamSource.decoderMap.get(this.audioType); + const Decoder = AudioDecoder.decoderMap.get(this.audioType); if (!Decoder) { this.errored = true; console.error( @@ -16258,7 +16263,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = return; } if (dt < this.bufferPlayDuration) return; - console.log(played, this.lastBufferSamples, this.sampleRate); + this.lastBufferSamples = this.bufferedSamples; // 需要播放 this.mergeBuffers(); @@ -16322,8 +16327,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = this.loaded = true; delete this.controller; this.mergeBuffers(); - // const played = this.lastBufferSamples / this.sampleRate; - // this.playAudio(played); + this.duration = this.buffered; this.audioData = []; this.decoder?.destroy(); @@ -16342,15 +16346,15 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = if (!this.buffer) return; this.lastStartTime = this.ac.currentTime; if (this.playing) this.output.stop(); - this.emit("play"); + this.createSourceNode(this.buffer); this.output.start(0, when); this.playing = true; - console.log(when); + this.output.addEventListener("ended", () => { this.playing = false; - this.emit("end"); + if (this.loop && !this.output.loop) this.play(0); }); } @@ -16402,22 +16406,25 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } } class AudioElementSource { - constructor(context) { const audio = new Audio(); - audio.preload = 'none'; + audio.preload = "none"; this.output = context.createMediaElementSource(audio); this.audio = audio; - audio.addEventListener('play', () => { + audio.addEventListener("play", () => { this.playing = true; - this.emit('play'); }); - audio.addEventListener('ended', () => { + audio.addEventListener("ended", () => { this.playing = false; - this.emit('end'); + this.ac = context; }); } - + get duration() { + return this.audio.duration; + } + get currentTime() { + return this.audio.currentTime; + } /** * 设置音频源的路径 * @param url 音频路径 @@ -16435,7 +16442,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = stop() { this.audio.pause(); this.playing = false; - this.emit('end'); + return this.audio.currentTime; } @@ -16448,17 +16455,19 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } } class AudioBufferSource { - - - constructor(context) { this.output = context.createBufferSource(); /** 是否循环 */ this.loop = false; - + /** 上一次播放是从何时开始的 */ + this.lastStartWhen = 0; /** 播放开始时刻 */ this.lastStartTime = 0; - + this.duration = 0; + this.ac = context; + } + get currentTime() { + return this.ac.currentTime - this.lastStartTime + this.lastStartWhen; } /** @@ -16471,18 +16480,18 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } else { this.buffer = buffer; } + this.duration = this.buffer.duration; } play(when) { if (this.playing || !this.buffer) return; this.playing = true; this.lastStartTime = this.ac.currentTime; - this.emit('play'); + this.createSourceNode(this.buffer); this.output.start(0, when); - this.output.addEventListener('ended', () => { + this.output.addEventListener("ended", () => { this.playing = false; - this.emit('end'); if (this.loop && !this.output.loop) this.play(0); }); } @@ -16516,9 +16525,15 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = /** 音量节点 */ this.gain = this.ac.createGain(); this.gain.connect(this.ac.destination); - this.audioRoutes = new Map() + this.audioRoutes = new Map(); + } + /** + * 解码音频数据 + * @param data 音频数据 + */ + decodeAudioData(data) { + return AudioDecoder.decodeAudioData(data, this); } - /** * 设置音量 * @param volume 音量 @@ -16658,7 +16673,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = * @param route 音频播放路由对象 */ addRoute(id, route) { - if (!this.audioRoutes) this.audioRoutes = new Map() + if (!this.audioRoutes) this.audioRoutes = new Map(); if (this.audioRoutes.has(id)) { console.warn( "Audio route with id of '" + @@ -16676,14 +16691,29 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = getRoute(id) { return this.audioRoutes.get(id); } - + /** + * 移除一个音频播放路由 + * @param id 要移除的播放路由的名称 + */ + removeRoute(id) { + this.audioRoutes.delete(id); + } /** * 播放音频 * @param id 音频名称 * @param when 从音频的哪个位置开始播放,单位秒 */ play(id, when) { - this.getRoute(id)?.play(when); + const route = this.getRoute(id); + if (!route) { + console.warn( + "Cannot play audio route '" + + id + + "', since there is not added route named it." + ); + return; + } + route.play(when); } /** @@ -16693,8 +16723,15 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = */ pause(id) { const route = this.getRoute(id); - if (!route) return Promise.resolve(); - else return route.pause(); + if (!route) { + console.warn( + "Cannot pause audio route '" + + id + + "', since there is not added route named it." + ); + return; + } + return route.pause(); } /** @@ -16704,8 +16741,15 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = */ stop(id) { const route = this.getRoute(id); - if (!route) return Promise.resolve(); - else return route.stop(); + if (!route) { + console.warn( + "Cannot stop audio route '" + + id + + "', since there is not added route named it." + ); + return; + } + return route.stop(); } /** @@ -16713,11 +16757,20 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = * @param id 音频名称 */ resume(id) { - this.getRoute(id)?.resume(); + const route = this.getRoute(id); + if (!route) { + console.warn( + "Cannot pause audio route '" + + id + + "', since there is not added route named it." + ); + return; + } + route.resume(); } /** - * 设置听者位置,x正方形水平向右,y正方形垂直于地面向上,z正方向垂直屏幕远离用户 + * 设置听者位置,x正方向水平向右,y正方向垂直于地面向上,z正方向垂直屏幕远离用户 * @param x 位置x坐标 * @param y 位置y坐标 * @param z 位置z坐标 @@ -16730,7 +16783,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } /** - * 设置听者朝向,x正方形水平向右,y正方形垂直于地面向上,z正方向垂直屏幕远离用户 + * 设置听者朝向,x正方向水平向右,y正方向垂直于地面向上,z正方向垂直屏幕远离用户 * @param x 朝向x坐标 * @param y 朝向y坐标 * @param z 朝向z坐标 @@ -16743,7 +16796,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } /** - * 设置听者头顶朝向,x正方形水平向右,y正方形垂直于地面向上,z正方向垂直屏幕远离用户 + * 设置听者头顶朝向,x正方向水平向右,y正方向垂直于地面向上,z正方向垂直屏幕远离用户 * @param x 头顶朝向x坐标 * @param y 头顶朝向y坐标 * @param z 头顶朝向z坐标 @@ -16755,6 +16808,13 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = listener.upZ.value = z; } } + const AudioStatus = { + Playing: 0, + Pausing: 1, + Paused: 2, + Stoping: 3, + Stoped: 4, + }; const AudioRouteEvent = { updateEffect: [], play: [], @@ -16770,15 +16830,37 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = /** 结束时长,当音频暂停或停止时,会经过这么长时间之后才真正终止播放,期间可以做音频淡入淡出等效果 */ this.endTime = 0; - - /** 是否已暂停,注意停止播放是不算暂停的 */ - this.paused = false; + /** 暂停时播放了多长时间 */ + this.pauseCurrentTime = 0; + /** 当前播放状态 */ + this.status = AudioStatus.Stoped; + this.shouldStop = false; + /** + * 每次暂停或停止时自增,用于判断当前正在处理的情况。 + * 假如暂停后很快播放,然后很快暂停,那么需要根据这个来判断实际是否应该执行暂停后操作 + */ + this.stopIdentifier = 0; /** 暂停时刻 */ this.pauseTime = 0; - this.source = source - this.player = player + this.source = source; + this.player = player; + } + /** 音频时长,单位秒 */ + get duration() { + return this.source.duration; + } + /** 当前播放了多长时间,单位秒 */ + get currentTime() { + if (this.status === AudioStatus.Paused) { + return this.pauseCurrentTime; + } else { + return this.source.currentTime; + } + } + set currentTime(time) { + this.source.stop(); + this.source.play(time); } - /** * 设置结束时间,暂停或停止时,会经过这么长时间才终止音频的播放,这期间可以做一下音频淡出的效果。 * @param time 暂停或停止时,经过多长时间之后才会结束音频的播放 @@ -16809,69 +16891,108 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = * @param when 从音频的什么时候开始播放,单位秒 */ play(when = 0) { - if (this.source.playing) return; + if (this.status === AudioStatus.Playing) return; this.link(); if (this.effectRoute.length > 0) { const first = this.effectRoute[0]; this.source.connect(first); + const last = this.effectRoute.at(-1); + last.connect({ input: this.player.getDestination() }); } else { this.source.connect({ input: this.player.getDestination() }); } this.source.play(when); - this.paused = false; + this.status = AudioStatus.Playing; this.pauseTime = 0; this.audioStartHook?.(this); this.startAllEffect(); - } /** * 暂停音频播放 */ async pause() { - if (this.paused || !this.source.playing) return; + if (this.status !== AudioStatus.Playing) return; + this.status = AudioStatus.Pausing; + this.stopIdentifier++; + const identifier = this.stopIdentifier; if (this.audioEndHook) { this.audioEndHook(this.endTime, this); await sleep(this.endTime); } + if ( + this.status !== AudioStatus.Pausing || + this.stopIdentifier !== identifier + ) { + return; + } + this.pauseCurrentTime = this.source.currentTime; const time = this.source.stop(); this.pauseTime = time; - this.paused = true; - this.endAllEffect(); + if (this.shouldStop) { + this.status = AudioStatus.Stoped; + this.endAllEffect(); + this.shouldStop = false; + } else { + this.status = AudioStatus.Paused; + this.endAllEffect(); + } + this.endAllEffect(); } /** * 继续音频播放 */ resume() { - if (this.source.playing) return; - if (this.paused) { + if (this.status === AudioStatus.Playing) return; + if ( + this.status === AudioStatus.Pausing || + this.status === AudioStatus.Stoping + ) { + + this.audioStartHook?.(this); + + return; + } + if (this.status === AudioStatus.Paused) { this.play(this.pauseTime); } else { this.play(0); } - this.paused = false; + this.status = AudioStatus.Playing; this.pauseTime = 0; this.audioStartHook?.(this); this.startAllEffect(); - } /** * 停止音频播放 */ async stop() { - if (!this.source.playing) return; + if (this.status !== AudioStatus.Playing) { + if (this.status === AudioStatus.Pausing) { + this.shouldStop = true; + } + return; + } + this.status = AudioStatus.Stoping; + this.stopIdentifier++; + const identifier = this.stopIdentifier; if (this.audioEndHook) { this.audioEndHook(this.endTime, this); await sleep(this.endTime); } + if ( + this.status !== AudioStatus.Stoping || + this.stopIdentifier !== identifier + ) { + return; + } this.source.stop(); - this.paused = false; + this.status = AudioStatus.Stoped; this.pauseTime = 0; this.endAllEffect(); - } /** @@ -16895,7 +17016,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } this.setOutput(); if (this.source.playing) this.link(); - } /** @@ -16909,7 +17029,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = effect.disconnect(); this.setOutput(); if (this.source.playing) this.link(); - } setOutput() { @@ -16940,15 +17059,83 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = } } - core.plugin.audioPlayer = new AudioPlayer(); - const audioPlayer = core.plugin.audioPlayer; + + const audioPlayer = new AudioPlayer() + + class AudioDecoder { + /** + * 注册一个解码器 + * @param type 要注册的解码器允许解码的类型 + * @param decoder 解码器对象 + */ + static registerDecoder(type, decoder) { + if (!this.decoderMap) this.decoderMap = new Map(); + if (this.decoderMap.has(type)) { + console.warn( + "Audio stream decoder for audio type '" + + type + + "' has already existed." + ); + return; + } + + this.decoderMap.set(type, decoder); + } + + /** + * 解码音频数据 + * @param data 音频文件数据 + * @param player AudioPlayer实例 + */ + static async decodeAudioData(data, player) { + // 检查头文件获取音频类型,仅检查前256个字节 + const toCheck = data.slice(0, 256); + const type = checkAudioType(data); + if (type === "") { + console.error( + "Unknown audio type. Header: '" + [...toCheck] + .map((v) => v.toString().padStart(2, "0")) + .join(" ") + .toUpperCase() + + "'" + ); + return null; + } + if (isAudioSupport(type)) { + if (data.buffer instanceof ArrayBuffer) { + return player.ac.decodeAudioData(data.buffer); + } else { + return null; + } + } else { + const Decoder = this.decoderMap.get(type); + if (!Decoder) { + return null; + } else { + const decoder = new Decoder(); + await decoder.create(); + const decodedData = await decoder.decode(data); + if (!decodedData) return null; + const buffer = player.ac.createBuffer( + decodedData.channelData.length, + decodedData.channelData[0].length, + decodedData.sampleRate + ); + decodedData.channelData.forEach((v, i) => { + buffer.copyToChannel(v, i); + }); + return buffer; + } + } + } + } class VorbisDecoder { /** * 创建音频解码器 */ async create() { - this.decoder = new OggVorbisDecoder(); + this.decoder = new OggVorbisDecoderWebWorker(); await this.decoder.ready; } /** @@ -16965,11 +17152,14 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = async decode(data) { return this.decoder?.decode(data); } + async decodeAll(data) { + return this.decoder?.decodeFile(data); + } /** * 当音频解码完成后,会调用此函数,需要返回之前还未解析或未返回的音频数据。调用后,该解码器将不会被再次使用 */ async flush() { - return await this.decoder?.flush(); + return this.decoder?.flush(); } } class OpusDecoder { @@ -16977,7 +17167,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = * 创建音频解码器 */ async create() { - this.decoder = new OggOpusDecoder(); + this.decoder = new OggOpusDecoderWebWorker(); await this.decoder.ready; } /** @@ -16993,6 +17183,10 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = async decode(data) { return this.decoder?.decode(data); } + + async decodeAll(data) { + return this.decoder?.decodeFile(data); + } /** * 当音频解码完成后,会调用此函数,需要返回之前还未解析或未返回的音频数据。调用后,该解码器将不会被再次使用 */ @@ -17000,38 +17194,367 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = return await this.decoder?.flush(); } } + class BgmController { + constructor(player) { + this.mainGain = player.createVolumeEffect(); + this.player = player; + /** bgm音频名称的前缀 */ + this.prefix = "bgms."; + /** 每个 bgm 的音量控制器 */ + this.gain = new Map(); - function loadAllBgm() { + /** 正在播放的 bgm */ + this.playingBgm = ""; + /** 是否正在播放 */ + this.playing = false; - const data = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d; - for (const bgm of data.main.bgms) { - const type = guessTypeByExt(bgm); - if (!type) continue; + /** 是否已经启用 */ + this.enabled = true; + /** 是否屏蔽所有的音乐切换 */ + this.blocking = false; + /** 渐变时长 */ + this.transitionTime = 2000; + } + + /** + * 设置音频渐变时长 + * @param time 渐变时长 + */ + setTransitionTime(time) { + this.transitionTime = time; + for (const [, value] of this.gain) { + value.transition.time(time); + } + } + + /** + * 屏蔽音乐切换 + */ + blockChange() { + this.blocking = true; + } + + /** + * 取消屏蔽音乐切换 + */ + unblockChange() { + this.blocking = false; + } + + /** + * 设置总音量大小 + * @param volume 音量大小 + */ + setVolume(volume) { + this.mainGain.setVolume(volume); + } + + /** + * 设置是否启用 + * @param enabled 是否启用 + */ + setEnabled(enabled) { + if (enabled) this.resume(); + else this.stop(); + this.enabled = enabled; + } + + /** + * 设置 bgm 音频名称的前缀 + */ + setPrefix(prefix) { + this.prefix = prefix; + } + + getId(name) { + return `${this.prefix}${name}`; + } + + /** + * 根据 bgm 名称获取其 AudioRoute 实例 + * @param id 音频名称 + */ + get(id) { + return this.player.getRoute(this.getId(id)); + } + + /** + * 添加一个 bgm + * @param id 要添加的 bgm 的名称 + * @param url 指定 bgm 的加载地址 + */ + addBgm(id, url = `project/bgms/${id}`) { + const type = guessTypeByExt(id); + if (!type) { + console.warn( + "Unknown audio extension name: '" + + id.split(".").slice(0, -1).join(".") + + "'" + ); + return; + } + const gain = this.player.createVolumeEffect(); if (isAudioSupport(type)) { const source = audioPlayer.createElementSource(); - source.setSource(`project/bgms/${bgm}`); + source.setSource(url); source.setLoop(true); const route = new AudioRoute(source, audioPlayer); - audioPlayer.addRoute(`bgms.${bgm}`, route); + route.addEffect([gain, this.mainGain]); + audioPlayer.addRoute(this.getId(id), route); + this.setTransition(id, route, gain); } else { const source = audioPlayer.createStreamSource(); - const stream = new StreamLoader(`project/bgms/${bgm}`); + const stream = new StreamLoader(url); stream.pipe(source); source.setLoop(true); const route = new AudioRoute(source, audioPlayer); - audioPlayer.addRoute(`bgms.${bgm}`, route); + route.addEffect([gain, this.mainGain]); + audioPlayer.addRoute(this.getId(id), route); + this.setTransition(id, route, gain); } } + /** + * 移除一个 bgm + * @param id 要移除的 bgm 的名称 + */ + removeBgm(id) { + this.player.removeRoute(this.getId(id)); + const gain = this.gain.get(id); + gain?.transition.ticker.destroy(); + this.gain.delete(id); + } + + setTransition(id, route, gain) { + const transition = new Transition(); + transition + .time(this.transitionTime) + .mode(linear()) + .transition("volume", 0); + + const tick = () => { + gain.setVolume(transition.value.volume); + }; + + /** + * @param expect 在结束时应该是正在播放还是停止 + */ + const setTick = async (expect) => { + transition.ticker.remove(tick); + transition.ticker.add(tick); + const identifier = route.stopIdentifier; + await sleep(this.transitionTime + 500); + if (route.status === expect && identifier === route.stopIdentifier) { + transition.ticker.remove(tick); + if (route.status === AudioStatus.Playing) { + gain.setVolume(1); + } else { + gain.setVolume(0); + } + } + }; + + route.onStart(async () => { + transition.transition("volume", 1); + setTick(AudioStatus.Playing); + }); + route.onEnd(() => { + transition.transition("volume", 0); + setTick(AudioStatus.Paused); + }); + route.setEndTime(this.transitionTime); + + this.gain.set(id, { effect: gain, transition }); + } + + /** + * 播放一个 bgm + * @param id 要播放的 bgm 名称 + */ + play(id, when) { + if (this.blocking) return; + if (id !== this.playingBgm && this.playingBgm) { + this.player.pause(this.getId(this.playingBgm)); + } + this.playingBgm = id; + if (!this.enabled) return; + this.player.play(this.getId(id), when); + this.playing = true; + } + + /** + * 继续当前的 bgm + */ + resume() { + if (this.blocking || !this.enabled || this.playing) return; + if (this.playingBgm) { + this.player.resume(this.getId(this.playingBgm)); + } + this.playing = true; + } + + /** + * 暂停当前的 bgm + */ + pause() { + if (this.blocking || !this.enabled) return; + if (this.playingBgm) { + this.player.pause(this.getId(this.playingBgm)); + } + this.playing = false; + } + + /** + * 停止当前的 bgm + */ + stop() { + if (this.blocking || !this.enabled) return; + if (this.playingBgm) { + this.player.stop(this.getId(this.playingBgm)); + } + this.playing = false; + } + } + const bgmController = new BgmController(audioPlayer); + + + class SoundPlayer { + constructor(player) { + /** 每个音效的唯一标识符 */ + this.num = 0; + this.enabled = true; + this.gain = player.createVolumeEffect(); + /** 每个音效的数据 */ + this.buffer = new Map(); + /** 所有正在播放的音乐 */ + this.playing = new Set(); + this.player = player; + } + /** + * 设置是否启用音效 + * @param enabled 是否启用音效 + */ + setEnabled(enabled) { + if (!enabled) this.stopAllSounds(); + this.enabled = enabled; + } + + /** + * 设置音量大小 + * @param volume 音量大小 + */ + setVolume(volume) { + this.gain.setVolume(volume); + } + /** + * 添加一个音效 + * @param id 音效名称 + * @param data 音效的Uint8Array数据 + */ + async add(id, data) { + const buffer = await this.player.decodeAudioData(data); + if (!buffer) { + console.warn( + "Cannot decode sound '" + + id + + "', since audio file may not supported by 2.b." + ); + return; + } + this.buffer.set(id, buffer); + } + + /** + * 播放一个音效 + * @param id 音效名称 + * @param position 音频位置,[0, 0, 0]表示正中心,x轴指向水平向右,y轴指向水平向上,z轴指向竖直向上 + * @param orientation 音频朝向,[0, 1, 0]表示朝向前方 + */ + play(id, position = [0, 0, 0], orientation = [1, 0, 0]) { + if (!this.enabled) return -1; + const buffer = this.buffer.get(id); + if (!buffer) { + console.warn( + "Cannot play sound '" + + id + + "', since there is no added data named it." + ); + return -1; + } + const soundNum = this.num++; + + const source = this.player.createBufferSource(); + source.setBuffer(buffer); + const route = this.player.createRoute(source); + const stereo = this.player.createStereoEffect(); + stereo.setPosition(position[0], position[1], position[2]); + stereo.setOrientation(orientation[0], orientation[1], orientation[2]); + route.addEffect([stereo, this.gain]); + this.player.addRoute(`sounds.${soundNum}`, route); + route.play(); + source.output.addEventListener("ended", () => { + this.playing.delete(soundNum); + }); + this.playing.add(soundNum); + return soundNum; + } + + /** + * 停止一个音效 + * @param num 音效的唯一 id + */ + stop(num) { + const id = `sounds.${num}`; + const route = this.player.getRoute(id); + if (route) { + route.stop(); + this.player.removeRoute(id); + this.playing.delete(num); + } + } + + /** + * 停止播放所有音效 + */ + stopAllSounds() { + this.playing.forEach((v) => { + const id = `sounds.${v}`; + const route = this.player.getRoute(id); + if (route) { + route.stop(); + this.player.removeRoute(id); + } + }); + this.playing.clear(); + } + } + const soundPlayer = new SoundPlayer(audioPlayer); + + + + function loadAllBgm() { + const data = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d; + for (const bgm of data.main.bgms) { + bgmController.addBgm(bgm); + } + } loadAllBgm(); - AudioStreamSource.registerDecoder(AudioType.Ogg, VorbisDecoder); - AudioStreamSource.registerDecoder(AudioType.Opus, OpusDecoder); + AudioDecoder.registerDecoder(AudioType.Ogg, VorbisDecoder); + AudioDecoder.registerDecoder(AudioType.Opus, OpusDecoder); core.plugin.audioSystem = { AudioType, + AudioDecoder, + AudioStatus, + checkAudioType, isAudioSupport, + audioPlayer, + soundPlayer, + bgmController, guessTypeByExt, + BgmController, + SoundPlayer, EchoEffect, DelayEffect, ChannelVolumeEffect, @@ -17046,7 +17569,102 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = loadAllBgm, StreamLoader, }; + //bgm相关复写 + control.prototype.playBgm = (bgm, when) => { + bgmController.play(bgm, when); + core.setMusicBtn(); + }; + control.prototype.pauseBgm = () => { + bgmController.pause(); + core.setMusicBtn(); + }; + + control.prototype.resumeBgm = function () { + bgmController.resume(); + core.setMusicBtn(); + }; + control.prototype.checkBgm = function () { + if (bgmController.playing) return; + if (core.musicStatus.bgmStatus) { + if (bgmController.playingBgm) { + bgmController.play(bgmController.playingBgm); + } else { + play(main.startBgm, 0); + } + } else { + pause(); + } + }; + control.prototype.triggerBgm = function () { + core.musicStatus.bgmStatus = !core.musicStatus.bgmStatus; + if (bgmController.playing) bgmController.pause(); + else bgmController.resume(); + core.setMusicBtn(); + core.setLocalStorage('bgmStatus', core.musicStatus.bgmStatus); + }; + //sound相关复写 + control.prototype.playSound = function ( + sound, + _pitch, + callback, + position, + orientation + ) { + if (main.mode != 'play' || !core.musicStatus.soundStatus) return + const name = core.getMappedName(sound); + const num = soundPlayer.play(name, position, orientation); + const route = audioPlayer.getRoute(`sounds.${num}`); + if (!route) { + callback?.(); + return -1; + } else { + sleep(route.duration).then(() => callback?.()); + return num; + } + }; + control.prototype.stopSound = function (id) { + if (isNil(id)) { + soundPlayer.stopAllSounds(); + } else { + soundPlayer.stop(id); + } + }; + control.prototype.getPlayingSounds = function () { + return [...soundPlayer.playing]; + }; + //sound加载复写 + loader.prototype._loadOneSound_decodeData = function (name, data) { + if (data instanceof Blob) { + var blobReader = new zip.BlobReader(data); + blobReader.init(function () { + blobReader.readUint8Array(0, blobReader.size, function (uint8) { + //core.loader._loadOneSound_decodeData(name, uint8.buffer); + soundPlayer.add(name, uint8) + }) + }); + return; + } + if (data instanceof ArrayBuffer) { + const uint8 = new Uint8Array(data) + soundPlayer.add(name, uint8) + } + } + //音量控制复写 + soundPlayer.setVolume(core.musicStatus.userVolume * core.musicStatus.designVolume) + bgmController.setVolume(core.musicStatus.userVolume * core.musicStatus.designVolume) + actions.prototype._clickSwitchs_sounds_userVolume = function (delta) { + var value = Math.round(Math.sqrt(100 * core.musicStatus.userVolume)); + if (value == 0 && delta < 0) return; + core.musicStatus.userVolume = core.clamp(Math.pow(value + delta, 2) / 100, 0, 1); + //audioContext 音效 不受designVolume 影响 + if (core.musicStatus.gainNode != null) core.musicStatus.gainNode.gain.value = core.musicStatus.userVolume; + soundPlayer.setVolume(core.musicStatus.userVolume * core.musicStatus.designVolume) + bgmController.setVolume(core.musicStatus.userVolume * core.musicStatus.designVolume) + core.setLocalStorage('userVolume', core.musicStatus.userVolume); + core.playSound('确定'); + core.ui._drawSwitchs_sounds(); + } } } \ No newline at end of file diff --git a/project/sounds/attack.opus b/project/sounds/attack.opus new file mode 100644 index 0000000..acd40a4 Binary files /dev/null and b/project/sounds/attack.opus differ diff --git a/project/sounds/floor.mp3 b/project/sounds/floor.mp3 index 96dc4fa..2b24efb 100644 Binary files a/project/sounds/floor.mp3 and b/project/sounds/floor.mp3 differ