diff --git a/idea.md b/idea.md index 498d56d..df517a9 100644 --- a/idea.md +++ b/idea.md @@ -21,7 +21,7 @@ ### 机制 -[] 苍蓝之殿 1: 利用点光源,照到的位置与没照到的位置内容不同,玩家可以选择是否装备手电筒 +[] 苍蓝之殿 1: [] 苍蓝之殿 2: [] 苍蓝之殿 3: [] 苍蓝之殿 4: @@ -72,7 +72,7 @@ dam4.png ---- 存档 59 [] 区域名称显示特效,3D 粒子特效 [] 单独的工具栏,可以自定义按键 [] 完全 ts 化 -[] 平行光 +[] 平行光(待定) [] 视角控制系统 [x] 重构设置界面 [] 优化开头动画 @@ -96,5 +96,7 @@ dam4.png ---- 存档 59 [] 重构技能树结构 [] 技能树允许自动升级 [] 重构装备系统 -[] 野外地图加入平行光 [] 弹幕系统 +[] 优化各种 ui +[] 怪物脚下加入阴影 +[] 着色器特效 diff --git a/src/core/main/custom/hotkey.ts b/src/core/main/custom/hotkey.ts index 3f0f92e..12ccdd5 100644 --- a/src/core/main/custom/hotkey.ts +++ b/src/core/main/custom/hotkey.ts @@ -135,11 +135,12 @@ export class Hotkey extends EventEmitter { * @param hotkey 被继承的按键 * @param cover 继承时是否覆盖同id的按键 */ - extend(hotkey: Hotkey, cover: boolean) { + extend(hotkey: Hotkey, cover: boolean = false) { Object.values(hotkey.list).forEach(v => { if (v.id in this.list && !cover) return; this.register(v.id, v.name, v); }); + return this; } private ensureKey(key: KeyCode) { @@ -177,7 +178,7 @@ hotkey core.doSL('autoSave', 'load'); } }) - .register('redo', '撤销回退', { + .register('redo', '恢复', { defaults: KeyCode.KeyW, func: () => { core.doSL('autoSave', 'reload'); diff --git a/src/core/main/custom/ui.ts b/src/core/main/custom/ui.ts index 55e7c99..02ee36b 100644 --- a/src/core/main/custom/ui.ts +++ b/src/core/main/custom/ui.ts @@ -1,4 +1,4 @@ -import { Component, shallowReactive } from 'vue'; +import { Component, h, shallowReactive } from 'vue'; import { EmitableEvent, EventEmitter } from '../../common/eventEmitter'; import { KeyCode } from '../../../plugin/keyCodes'; import { Hotkey } from './hotkey'; @@ -19,9 +19,13 @@ export class Focus extends EventEmitter> { stack: T[]; focused: T | null = null; - constructor(react?: boolean) { + /** ui是否平等,在平等时,关闭ui不再会将其之后的ui全部删除,而是保留 */ + readonly equal: boolean; + + constructor(react: boolean = false, equal: boolean = false) { super(); this.stack = react ? shallowReactive([]) : []; + this.equal = equal; } /** @@ -79,12 +83,15 @@ export class Focus extends EventEmitter> { */ pop() { const item = this.stack.pop() ?? null; + const last = this.stack.at(-1) ?? null; + if (!last) this.unfocus(); + else this.focus(last); this.emit('pop', item); return item; } /** - * 从一个位置开始删除显示列表 + * 从一个位置开始删除显示列表,如果ui平等,则只会删除一个,否则会将其之后的所有ui全部删除 * @param item 从哪开始删除,包括此项 */ splice(item: T) { @@ -93,7 +100,13 @@ export class Focus extends EventEmitter> { this.emit('splice', []); return; } - this.emit('splice', this.stack.splice(index)); + const last = this.stack.at(-1) ?? null; + if (!last) this.unfocus(); + else this.focus(last); + this.emit( + 'splice', + this.stack.splice(index, this.equal ? 1 : Infinity) + ); } /** @@ -133,6 +146,9 @@ export class GameUi extends EventEmitter { hotkey?: Hotkey; id: string; + vBind: any = {}; + vOn: Record any> = {}; + constructor(id: string, component: Component, hotkey?: Hotkey) { super(); this.component = component; @@ -140,17 +156,53 @@ export class GameUi extends EventEmitter { this.id = id; GameUi.uiList.push(this); } + + /** + * 双向数据绑定,即 vue 内的 v-bind + * @param data 要绑定的数据 + */ + vbind(data: any) { + this.vBind = data; + } + + /** + * 监听这个ui组件所触发的某种事件 + * @param event 要监听的事件 + * @param fn 事件触发时执行的函数 + */ + von(event: string, fn: (...params: any[]) => any) { + this.vOn[event] = fn; + } + + /** + * 取消监听这个ui组件所触发的某种事件 + * @param event 要取消监听的事件 + */ + voff(event: string) { + delete this.vOn[event]; + } } export class UiController extends Focus { - constructor() { - super(true); + static list: UiController[] = []; + + constructor(equal?: boolean) { + super(true, equal); + UiController.list.push(this); this.on('splice', spliced => { spliced.forEach(v => { v.emit('close'); + if (this.stack.length === 0) { + this.emit('end'); + } }); }); - this.on('add', item => item.emit('open')); + this.on('add', item => { + if (this.stack.length === 1) { + this.emit('start'); + } + item.emit('open'); + }); } /** @@ -171,7 +223,7 @@ export class UiController extends Focus { } /** - * 关闭一个ui,注意在其之后的ui都会同时关闭掉 + * 关闭一个ui,注意如果不是平等模式,在其之后的ui都会同时关闭掉 * @param id 要关闭的ui的id */ close(id: string) { diff --git a/src/core/main/init/ui.ts b/src/core/main/init/ui.ts index 3076455..3df84d7 100644 --- a/src/core/main/init/ui.ts +++ b/src/core/main/init/ui.ts @@ -10,26 +10,16 @@ import FixedDetail from '../../../ui/fixedDetail.vue'; import Shop from '../../../ui/shop.vue'; import Achievement from '../../../ui/achievement.vue'; import Bgm from '../../../ui/bgmList.vue'; +import StatusBar from '../../../ui/statusBar.vue'; +import Mark from '../../../ui/markedEnemy.vue'; +import Fixed from '../../../ui/fixed.vue'; +import Chapter from '../../../ui/chapter.vue'; +import CompleteAchi from '../../../ui/completeAchievement.vue'; +import Start from '../../../ui/start.vue'; import { GameUi, UiController } from '../custom/ui'; import { Hotkey } from '../custom/hotkey'; import { KeyCode } from '../../../plugin/keyCodes'; -export const mainUi = new UiController(); -mainUi.register( - new GameUi('book', Book), - new GameUi('toolbox', Toolbox), - new GameUi('equipbox', Equipbox), - new GameUi('settings', Settings), - new GameUi('desc', Desc), - new GameUi('skill', Skill), - new GameUi('skillTree', SkillTree), - new GameUi('fly', Fly), - new GameUi('fixedDetail', FixedDetail), - new GameUi('shop', Shop), - new GameUi('achievement', Achievement), - new GameUi('bgm', Bgm) -); - export const exitKey = new Hotkey('exitKey'); exitKey .register('exit1', '退出', { @@ -44,3 +34,30 @@ exitKey if (mainUi.focused) mainUi.splice(mainUi.focused); } }); + +export const mainUi = new UiController(); +mainUi.register( + new GameUi('book', Book, exitKey), + new GameUi('toolbox', Toolbox, exitKey), + new GameUi('equipbox', Equipbox, exitKey), + new GameUi('settings', Settings, exitKey), + new GameUi('desc', Desc, exitKey), + new GameUi('skill', Skill, exitKey), + new GameUi('skillTree', SkillTree, exitKey), + new GameUi('fly', Fly, exitKey), + new GameUi('fixedDetail', FixedDetail, exitKey), + new GameUi('shop', Shop, exitKey), + new GameUi('achievement', Achievement, exitKey), + new GameUi('bgm', Bgm, exitKey), + new GameUi('start', Start) + // todo: 把游戏主 div 加入到 mainUi 里面 +); + +export const fixedUi = new UiController(true); +fixedUi.register( + new GameUi('statusBar', StatusBar), + new GameUi('markedEnemy', Mark), + new GameUi('fixed', Fixed), + new GameUi('chapter', Chapter), + new GameUi('completeAchi', CompleteAchi) +);