diff --git a/idea.md b/idea.md index f6939f9..498d56d 100644 --- a/idea.md +++ b/idea.md @@ -90,6 +90,11 @@ dam4.png ---- 存档 59 [] 优化路径显示,瞬移可以闪一下再熄灭 [] 勇士身上显示攻防血 [] 优化地图拖动 -[] 楼层转换假如随机小贴士 +[] 楼层转换加入随机小贴士 [] ui 中如果元素发生改变,那么做出背景亮一下再熄灭的效果 [] 双击怪物手册拐点可以直接在拖动条上定位 +[] 重构技能树结构 +[] 技能树允许自动升级 +[] 重构装备系统 +[] 野外地图加入平行光 +[] 弹幕系统 diff --git a/src/core/main/custom/ui.ts b/src/core/main/custom/ui.ts new file mode 100644 index 0000000..9359219 --- /dev/null +++ b/src/core/main/custom/ui.ts @@ -0,0 +1,145 @@ +import { Component, reactive } from 'vue'; +import { EmitableEvent, EventEmitter } from '../../common/eventEmitter'; +import { KeyCode } from '../../../plugin/keyCodes'; +import { Hotkey } from './hotkey'; + +interface FocusEvent<T> extends EmitableEvent { + focus: (before: T | null, after: T) => void; + unfocus: (before: T | null) => void; + add: (item: T) => void; + pop: (item: T | null) => void; + register: (item: T[]) => void; + splice: (spliced: T[]) => void; +} + +export class Focus<T = any> extends EventEmitter<FocusEvent<T>> { + targets: Set<T> = new Set(); + /** 显示列表 */ + stack: T[]; + focused: T | null = null; + + constructor(react?: boolean) { + super(); + this.stack = react ? reactive([]) : []; + } + + /** + * 聚焦于一个目标 + * @param target 聚焦目标 + * @param add 如果聚焦目标不在显示列表里面,是否自动追加 + */ + focus(target: T, add: boolean = false) { + if (target === this.focused) return; + const before = this.focused; + if (!this.stack.includes(target)) { + if (add) { + this.add(target); + this.focused = target; + } else { + console.warn( + `聚焦于一个不存在的目标,同时没有传入自动追加的参数`, + `聚焦目标:${target}` + ); + return; + } + } else { + this.focused = target; + } + this.emit('focus', before, this.focused); + } + + /** + * 取消聚焦 + */ + unfocus() { + const before = this.focused; + this.focused = null; + this.emit('unfocus', before); + } + + /** + * 向显示列表中添加物品 + * @param item 添加的物品 + */ + add(item: T) { + if (!this.targets.has(item)) { + console.warn(`向显示列表里面添加了不在物品集合里面的物品`); + return; + } + this.stack.push(item); + this.emit('add', item); + } + + /** + * 弹出显示列表中的最后一个物品 + */ + pop() { + const item = this.stack.pop() ?? null; + this.emit('pop', item); + return item; + } + + /** + * 从一个位置开始删除显示列表 + * @param item 从哪开始删除,包括此项 + */ + splice(item: T) { + const index = this.stack.indexOf(item); + if (index === -1) { + this.emit('splice', []); + return; + } + this.emit('splice', this.stack.splice(index)); + } + + /** + * 注册一个物品 + * @param item 要注册的物品 + */ + register(...item: T[]) { + item.forEach(v => { + this.targets.add(v); + }); + this.emit('register', item); + } +} + +interface GameUiEvent extends EmitableEvent { + close: () => void; + open: () => void; +} + +export class GameUi extends EventEmitter<GameUiEvent> { + static uiList: GameUi[] = []; + + component: Component; + hotkey?: Hotkey; + + constructor(component: Component, hotkey?: Hotkey) { + super(); + this.component = component; + this.hotkey = hotkey; + GameUi.uiList.push(this); + } +} + +export class UiController extends Focus<GameUi> { + constructor() { + super(true); + this.on('splice', spliced => { + spliced.forEach(v => { + v.emit('close'); + }); + }); + this.on('add', item => item.emit('open')); + } + + /** + * 执行按键操作 + * @param key 按键的KeyCode + * @param e 按键操作事件 + */ + emitKey(key: KeyCode, e: KeyboardEvent) { + this.focused?.hotkey?.emitKey(key, e); + } +} diff --git a/src/core/main/setting.ts b/src/core/main/setting.ts index b5b752f..8a93a7d 100644 --- a/src/core/main/setting.ts +++ b/src/core/main/setting.ts @@ -3,7 +3,6 @@ import { EmitableEvent, EventEmitter } from '../common/eventEmitter'; import { transition } from '../../plugin/uiController'; import { loading } from '../loader/load'; import { hook } from './game'; -import { isMobile } from '../../plugin/use'; import { GameStorage } from './storage'; import { triggerFullscreen } from '../../plugin/utils'; @@ -352,7 +351,6 @@ mainSetting new MotaSetting() .register('fullscreen', '全屏游戏', false) .register('halo', '光环显示', true) - .register('frag', '打怪特效', true) .register('itemDetail', '宝石血瓶显伤', true) .register('transition', '界面动画', false) .register('antiAlias', '抗锯齿', false) @@ -376,10 +374,17 @@ mainSetting ) .register( 'utils', - '功能设置', + '系统设置', new MotaSetting() .register('betterLoad', '优化加载', true) .register('autoScale', '自动放缩', true) + ) + .register( + 'fx', + '特效设置', + new MotaSetting() + .register('paraLight', '野外阴影', true) + .register('frag', '打怪特效', true) ); interface SettingStorage { @@ -394,6 +399,7 @@ interface SettingStorage { fixed: boolean; betterLoad: boolean; autoScale: boolean; + paraLight: boolean; } const storage = new GameStorage<SettingStorage>( @@ -404,7 +410,6 @@ loading.once('coreInit', () => { mainSetting.reset({ 'screen.fullscreen': !!document.fullscreenElement, 'screen.halo': !!storage.getValue('showHalo', true), - 'screen.frag': !!storage.getValue('frag', true), 'screen.itemDetail': !!storage.getValue('itemDetail', true), 'screen.transition': !!storage.getValue('transition', false), 'screen.antiAlias': !!storage.getValue('antiAlias', false), @@ -413,7 +418,9 @@ loading.once('coreInit', () => { 'screen.criticalGem': !!storage.getValue('criticalGem', false), 'action.fixed': !!storage.getValue('fixed', true), 'utils.betterLoad': !!storage.getValue('betterLoad', true), - 'utils.autoScale': !!storage.getValue('autoScale', true) + 'utils.autoScale': !!storage.getValue('autoScale', true), + 'fx.paraLight': !!storage.getValue('paraLight', true), + 'fx.frag': !!storage.getValue('frag', true) }); }); diff --git a/src/data/settings.json b/src/data/settings.json index 144ba27..ccf6533 100644 --- a/src/data/settings.json +++ b/src/data/settings.json @@ -5,7 +5,6 @@ "请按下方的按钮打开。进入或退出全屏后请存读档一下,以解决一部分绘制问题。" ], "halo": ["开启后,会在地图上显示范围光环。"], - "frag": ["开启后,在打败怪物后会触发怪物碎裂特效。"], "itemDetail": ["是否在地图上显示宝石血瓶装备等增加的属性值"], "transition": [ "是否展示当一个ui界面,如怪物手册等的打开与关闭时的动画。当此项开启时,", @@ -14,7 +13,6 @@ "antiAlias": [ "是否开启抗锯齿。开启后,画面会变得不那么锐利,观感更加舒适;关闭后,可以更好地展现出像素感,同时部分像素错误也不会出现。" ], - "fontSize": [ "在各种 ui 界面中显示的文字大小,范围为 8 - 28。注意,字体过大可能会引起 ui 布局发生错误" ], @@ -57,5 +55,11 @@ "<br>", "2. 如果缩放后游戏画面高度高于页面高度的95%,那么缩小一个缩放比例,否则保持最大比例" ] + }, + "fx": { + "paraLight": [ + "是否开启野外的平行光阴影,在野外将会显示平行光阴影,模拟太阳光,拥有不错的视觉效果" + ], + "frag": ["开启后,在打败怪物后会触发怪物碎裂特效。"] } }