feat: keyboard类 & todo

This commit is contained in:
unanmed 2024-01-18 15:25:33 +08:00
parent 60d708e5e3
commit e77ca3e376
14 changed files with 262 additions and 45 deletions

13
idea.md
View File

@ -100,9 +100,18 @@ dam4.png ---- 存档 59
[] 优化各种 ui [] 优化各种 ui
[] 怪物脚下加入阴影 [] 怪物脚下加入阴影
[x] 着色器特效 [x] 着色器特效
[] 完全删除 core.plugin?(待定) [] 完全删除 core.plugin,采用 Plugin.register 的形式进行插件编写
[] 通用 Addon 接口 [] 通用 Addon 接口
[] 完善加载系统 [] 完善加载系统
[] 不同怪物可以在怪物手册中添加一些不同的边框 [] 不同怪物可以在怪物手册中添加一些不同的边框
[] 按住一个按键时显示怪物的攻防血 [] 按住一个按键时显示怪物的攻防血
[] 新的事件系统? [] 新的事件系统,并丰富自定义事件
[] 事件、eval 内容预编译
[] 新的存档系统,可以注册存档项
[] 渐变切 bgm
[] 新的 Flag 系统,使用 for 申请变量dispose 释放变量,可设为渲染进程与游戏进程共通变量
[] 注册可录像操作,比如可以在点击的时候执行,自动计入录像
[] 机关门显示绑定怪物
[] 自定义状态栏,通过申请空间进行布局
[] 复写 apirewrite()
[] 对 vnode 进行简单的包装,提供出显示文字、显示图片等 api 以及修改 css 的 api

View File

@ -3,6 +3,8 @@ import { AudioParamOf, AudioPlayer } from './audio';
import resource from '@/data/resource.json'; import resource from '@/data/resource.json';
import { ResourceController } from '../loader/controller'; import { ResourceController } from '../loader/controller';
// todo: 立体声,可设置音源位置
type Panner = AudioParamOf<PannerNode>; type Panner = AudioParamOf<PannerNode>;
export class SoundEffect extends AudioPlayer { export class SoundEffect extends AudioPlayer {

View File

@ -1,3 +1,4 @@
// todo: 更改utils.ts的形式使common文件夹可以同时在渲染进程和游戏进程使用
import { has } from '@/plugin/utils'; import { has } from '@/plugin/utils';
export interface EmitableEvent { export interface EmitableEvent {

View File

@ -6,6 +6,8 @@ import JSZip from 'jszip';
import { EmitableEvent, EventEmitter } from '../common/eventEmitter'; import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
import { loading } from './load'; import { loading } from './load';
// todo: 应当用register去注册资源类型然后进行分块处理
interface ResourceData { interface ResourceData {
image: HTMLImageElement; image: HTMLImageElement;
arraybuffer: ArrayBuffer; arraybuffer: ArrayBuffer;

View File

@ -2,6 +2,8 @@ import { KeyCode } from '@/plugin/keyCodes';
import { deleteWith, generateBinary, spliceBy } from '@/plugin/utils'; import { deleteWith, generateBinary, spliceBy } from '@/plugin/utils';
import { EmitableEvent, EventEmitter } from '../../common/eventEmitter'; import { EmitableEvent, EventEmitter } from '../../common/eventEmitter';
// todo: 按下时触发,长按(单次/连续)触发,按下连续触发,按下节流触发,按下加速节流触发
interface HotkeyEvent extends EmitableEvent { interface HotkeyEvent extends EmitableEvent {
set: (id: string, key: KeyCode, assist: number) => void; set: (id: string, key: KeyCode, assist: number) => void;
emit: (key: KeyCode, assist: number, type: KeyEmitType) => void; emit: (key: KeyCode, assist: number, type: KeyEmitType) => void;

View File

@ -0,0 +1,122 @@
import { EmitableEvent, EventEmitter } from '@/core/common/eventEmitter';
import { KeyCode } from '@/plugin/keyCodes';
import { gameKey } from '../init/hotkey';
import { unwarpBinary } from './hotkey';
import { deleteWith } from '@/plugin/utils';
import { cloneDeep } from 'lodash-es';
export interface KeyboardEmits {
key: KeyCode;
assist: number;
}
interface KeyboardItem {
key: KeyCode;
text?: string;
x: number;
y: number;
width: number;
height: number;
}
interface AssistManager {
end(): void;
}
interface VirtualKeyboardEvent extends EmitableEvent {
add: (item: KeyboardItem) => void;
remove: (item: KeyboardItem) => void;
emit: (item: KeyboardItem, assist: number, index: number) => void;
}
/**
*
*/
export class Keyboard extends EventEmitter<VirtualKeyboardEvent> {
static list: Keyboard[] = [];
id: string;
keys: KeyboardItem[] = [];
assist: number = 0;
constructor(id: string) {
super();
this.id = id;
Keyboard.list.push(this);
}
/**
*
* @param item
*/
add(item: KeyboardItem) {
this.keys.push(item);
this.emit('add', item);
}
/**
*
* @param item
*/
remove(item: KeyboardItem) {
deleteWith(this.keys, item);
this.emit('remove', item);
}
/**
*
* @param assist
* @returns
*/
withAssist(assist: number): AssistManager {
const thisAssist = this.assist;
this.assist = assist;
return {
end: () => {
this.assist = thisAssist;
}
};
}
/**
*
* @param keyboard
* @param offsetX
* @param offsetY
*/
extend(keyboard: Keyboard, offsetX: number = 0, offsetY: number = 0) {
const toClone = cloneDeep(keyboard.keys);
toClone.forEach(v => {
v.x += offsetX;
v.y += offsetY;
});
this.keys.push(...toClone);
}
/**
*
* @param key
*/
emitKey(key: KeyboardItem, index: number) {
const ev = generateKeyboardEvent(key.key, this.assist);
gameKey.emitKey(key.key, this.assist, 'up', ev);
this.emit('emit', key, this.assist, index);
}
static get(id: string) {
return this.list.find(v => v.id === id);
}
}
export function generateKeyboardEvent(key: KeyCode, assist: number) {
const { ctrl, alt, shift } = unwarpBinary(assist);
const ev = new KeyboardEvent('keyup', {
ctrlKey: ctrl,
shiftKey: shift,
altKey: alt
});
return ev;
}

View File

@ -9,6 +9,7 @@ import { GameStorage } from '../storage';
export const mainScope = Symbol.for('@key_main'); export const mainScope = Symbol.for('@key_main');
export const gameKey = new Hotkey('gameKey', '游戏按键'); export const gameKey = new Hotkey('gameKey', '游戏按键');
// todo: 读取上一个手动存档,存档至下一个存档栏
// ----- Register // ----- Register
gameKey gameKey
// -------------------- // --------------------

View File

@ -3,19 +3,21 @@ import { Button, InputNumber } from 'ant-design-vue';
import { mainUi } from './ui'; import { mainUi } from './ui';
import { gameKey } from './hotkey'; import { gameKey } from './hotkey';
// todo: 数字类型改为一个输入框,一个加按钮一个减按钮;新增单选框
interface Components { interface Components {
DefaultSetting: SettingComponent; Default: SettingComponent;
BooleanSetting: SettingComponent; Boolean: SettingComponent;
NumberSetting: SettingComponent; Number: SettingComponent;
HotkeySetting: SettingComponent; HotkeySetting: SettingComponent;
ToolbarEditor: SettingComponent; ToolbarEditor: SettingComponent;
} }
export function createSettingComponents() { export function createSettingComponents() {
const com: Components = { const com: Components = {
DefaultSetting, Default: DefaultSetting,
BooleanSetting, Boolean: BooleanSetting,
NumberSetting, Number: NumberSetting,
HotkeySetting, HotkeySetting,
ToolbarEditor ToolbarEditor
}; };

View File

@ -6,6 +6,8 @@ import type {
import BoxAnimate from '@/components/boxAnimate.vue'; import BoxAnimate from '@/components/boxAnimate.vue';
import { checkAssist } from '../custom/hotkey'; import { checkAssist } from '../custom/hotkey';
// todo: 新增更改设置的ToolItem
interface Components { interface Components {
DefaultTool: CustomToolbarComponent; DefaultTool: CustomToolbarComponent;
KeyTool: CustomToolbarComponent<'hotkey'>; KeyTool: CustomToolbarComponent<'hotkey'>;

View File

@ -85,7 +85,7 @@ export class MotaSetting extends EventEmitter<SettingEvent> {
key: string, key: string,
name: string, name: string,
value: MotaSettingType, value: MotaSettingType,
com: SettingComponent = COM.DefaultSetting, com: SettingComponent = COM.Default,
step: [number, number, number] = [0, 100, 1] step: [number, number, number] = [0, 100, 1]
) { ) {
const setting: MotaSettingItem = { const setting: MotaSettingItem = {
@ -274,11 +274,34 @@ export class SettingDisplayer extends EventEmitter<SettingDisplayerEvent> {
} }
} }
// todo: 优化存储方式
export const mainSetting = new MotaSetting(); export const mainSetting = new MotaSetting();
interface SettingStorage {
showHalo: boolean;
frag: boolean;
itemDetail: boolean;
transition: boolean;
antiAlias: boolean;
fontSize: number;
smoothView: boolean;
criticalGem: boolean;
fixed: boolean;
betterLoad: boolean;
autoScale: boolean;
paraLight: boolean;
heroDetail: boolean;
}
const storage = new GameStorage<SettingStorage>(
GameStorage.fromAuthor('AncTe', 'setting')
);
// ----- 监听设置修改 // ----- 监听设置修改
mainSetting.on('valueChange', (key, n, o) => { mainSetting.on('valueChange', (key, n, o) => {
const [root, setting] = key.split('.'); const [root, setting] = key.split('.');
if (root === 'screen') { if (root === 'screen') {
handleScreenSetting(setting, n, o); handleScreenSetting(setting, n, o);
} else if (root === 'action') { } else if (root === 'action') {
@ -367,28 +390,30 @@ function handleUtilsSetting<T extends number | boolean>(
} }
// ----- 游戏的所有设置项 // ----- 游戏的所有设置项
// todo: 虚拟键盘缩放,小地图楼传缩放
mainSetting mainSetting
.register( .register(
'screen', 'screen',
'显示设置', '显示设置',
new MotaSetting() new MotaSetting()
.register('fullscreen', '全屏游戏', false, COM.BooleanSetting) .register('fullscreen', '全屏游戏', false, COM.Boolean)
.register('halo', '光环显示', true, COM.BooleanSetting) .register('halo', '光环显示', true, COM.Boolean)
.register('itemDetail', '宝石血瓶显伤', true, COM.BooleanSetting) .register('itemDetail', '宝石血瓶显伤', true, COM.Boolean)
.register('heroDetail', '勇士显伤', false, COM.BooleanSetting) .register('heroDetail', '勇士显伤', false, COM.Boolean)
.register('transition', '界面动画', false, COM.BooleanSetting) .register('transition', '界面动画', false, COM.Boolean)
.register('antiAlias', '抗锯齿', false, COM.BooleanSetting) .register('antiAlias', '抗锯齿', false, COM.Boolean)
.register('fontSize', '字体大小', 16, COM.NumberSetting, [8, 28, 1]) .register('fontSize', '字体大小', 16, COM.Number, [8, 28, 1])
.register('smoothView', '平滑镜头', true, COM.BooleanSetting) .register('smoothView', '平滑镜头', true, COM.Boolean)
.register('criticalGem', '临界显示方式', false, COM.BooleanSetting) .register('criticalGem', '临界显示方式', false, COM.Boolean)
.setDisplayFunc('criticalGem', value => (value ? '宝石数' : '攻击')) .setDisplayFunc('criticalGem', value => (value ? '宝石数' : '攻击'))
.register('keyScale', '虚拟键盘缩放', 100, COM.Number, [25, 5, 500])
) )
.register( .register(
'action', 'action',
'操作设置', '操作设置',
new MotaSetting() new MotaSetting()
.register('autoSkill', '自动切换技能', true, COM.BooleanSetting) .register('autoSkill', '自动切换技能', true, COM.Boolean)
.register('fixed', '定点查看', true, COM.BooleanSetting) .register('fixed', '定点查看', true, COM.Boolean)
.register('hotkey', '快捷键', false, COM.HotkeySetting) .register('hotkey', '快捷键', false, COM.HotkeySetting)
.setDisplayFunc('hotkey', () => '') .setDisplayFunc('hotkey', () => '')
.register('toolbar', '自定义工具栏', false, COM.ToolbarEditor) .register('toolbar', '自定义工具栏', false, COM.ToolbarEditor)
@ -398,37 +423,28 @@ mainSetting
'utils', 'utils',
'系统设置', '系统设置',
new MotaSetting() new MotaSetting()
.register('betterLoad', '优化加载', true, COM.BooleanSetting) .register('betterLoad', '优化加载', true, COM.Boolean)
.register('autoScale', '自动放缩', true, COM.BooleanSetting) .register('autoScale', '自动放缩', true, COM.Boolean)
) )
.register( .register(
'fx', 'fx',
'特效设置', '特效设置',
new MotaSetting() new MotaSetting()
.register('paraLight', '野外阴影', true, COM.BooleanSetting) .register('paraLight', '野外阴影', true, COM.Boolean)
.register('frag', '打怪特效', true, COM.BooleanSetting) .register('frag', '打怪特效', true, COM.Boolean)
)
.register(
'ui',
'ui设置',
new MotaSetting().register(
'mapScale',
'小地图楼传缩放',
300,
COM.Number,
[50, 50, 1000]
)
); );
interface SettingStorage {
showHalo: boolean;
frag: boolean;
itemDetail: boolean;
transition: boolean;
antiAlias: boolean;
fontSize: number;
smoothView: boolean;
criticalGem: boolean;
fixed: boolean;
betterLoad: boolean;
autoScale: boolean;
paraLight: boolean;
heroDetail: boolean;
}
const storage = new GameStorage<SettingStorage>(
GameStorage.fromAuthor('AncTe', 'setting')
);
loading.once('coreInit', () => { loading.once('coreInit', () => {
mainSetting.reset({ mainSetting.reset({
'screen.fullscreen': !!document.fullscreenElement, 'screen.fullscreen': !!document.fullscreenElement,

View File

@ -30,12 +30,15 @@ export class GameStorage<T> {
* @param key * @param key
* @param value * @param value
*/ */
setValue<K extends keyof T>(key: K, value: T[K]): void;
setValue(key: string, value: any): void;
setValue<K extends keyof T>(key: K, value: T[K]) { setValue<K extends keyof T>(key: K, value: T[K]) {
this.data[key] = value; this.data[key] = value;
} }
getValue<K extends keyof T>(key: K): T[K] | null; getValue<K extends keyof T>(key: K): T[K] | null;
getValue<K extends keyof T>(key: K, defaults: T[K]): T[K]; getValue<K extends keyof T>(key: K, defaults: T[K]): T[K];
getValue<T>(key: string, defaults?: T): T;
getValue<K extends keyof T>(key: K, defaults?: T[K]) { getValue<K extends keyof T>(key: K, defaults?: T[K]) {
if (this.data[key]) return this.data[key]; if (this.data[key]) return this.data[key];
else { else {

View File

@ -18,6 +18,8 @@ import smooth from '@/plugin/fx/smoothView';
import frag from '@/plugin/fx/frag'; import frag from '@/plugin/fx/frag';
import { Mota } from '.'; import { Mota } from '.';
// todo: 将插件更改为注册形式,分为渲染进程和游戏进程两部分,同时分配优先级
export function resolvePlugin() { export function resolvePlugin() {
const toForward: [keyof Mota['plugin'], any][] = [ const toForward: [keyof Mota['plugin'], any][] = [
['pop', pop()], ['pop', pop()],

32
src/panel/keyboard.vue Normal file
View File

@ -0,0 +1,32 @@
<template>
<div class="keyboard-container"></div>
</template>
<script lang="ts" setup>
import { Keyboard } from '@/core/main/custom/keyboard';
import { KeyboardEmits } from '@/core/main/custom/keyboard';
import { ref } from 'vue';
const props = defineProps<{
keyboard: Keyboard;
}>();
const [width, height] = (() => {
const key = props.keyboard;
const mw = Math.max(...key.keys.map(v => v.x));
const mh = Math.max(...key.keys.map(v => v.y));
return [mw, mh];
})();
const emits = defineEmits<{
(e: 'keyup', data: KeyboardEmits): void;
}>();
</script>
<style lang="less" scoped>
.keyboard-container {
width: v-bind(width);
height: v-bind(height);
}
</style>

View File

@ -3,10 +3,11 @@ import { MessageApi } from 'ant-design-vue/lib/message';
import { isNil } from 'lodash-es'; import { isNil } from 'lodash-es';
import { Animation, sleep, TimingFn } from 'mutate-animate'; import { Animation, sleep, TimingFn } from 'mutate-animate';
import { ref } from 'vue'; import { ref } from 'vue';
import { EVENT_KEY_CODE_MAP } from './keyCodes'; import { EVENT_KEY_CODE_MAP, KeyCode } from './keyCodes';
import axios from 'axios'; import axios from 'axios';
import { decompressFromBase64 } from 'lz-string'; import { decompressFromBase64 } from 'lz-string';
import { parseColor } from './webgl/utils'; import { parseColor } from './webgl/utils';
import { KeyboardEmits } from '@/core/main/custom/keyboard';
type CanParseCss = keyof { type CanParseCss = keyof {
[P in keyof CSSStyleDeclaration as CSSStyleDeclaration[P] extends string [P in keyof CSSStyleDeclaration as CSSStyleDeclaration[P] extends string
@ -264,6 +265,11 @@ export function pColor(color: string) {
return `rgba(${arr.join(',')})` as Color; return `rgba(${arr.join(',')})` as Color;
} }
/**
*
* @param arr
* @param ele
*/
export function deleteWith<T>(arr: T[], ele: T): T[] { export function deleteWith<T>(arr: T[], ele: T): T[] {
const index = arr.indexOf(ele); const index = arr.indexOf(ele);
if (index === -1) return arr; if (index === -1) return arr;
@ -339,3 +345,18 @@ export function flipBinary(num: number, col: number) {
if (num & n) return num & ~n; if (num & n) return num & ~n;
else return num | n; else return num | n;
} }
/**
*
* @param emitAssist true时
*
* @param assist
*/
export function getVitualKeyOnce(
emitAssist: boolean = false,
assist: number = 0
): Promise<KeyboardEmits> {
return new Promise(res => {
res({ key: KeyCode.Unknown, assist: 0 });
});
}