mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-19 12:49:25 +08:00
feat: keyboard类 & todo
This commit is contained in:
parent
60d708e5e3
commit
e77ca3e376
13
idea.md
13
idea.md
@ -100,9 +100,18 @@ dam4.png ---- 存档 59
|
||||
[] 优化各种 ui
|
||||
[] 怪物脚下加入阴影
|
||||
[x] 着色器特效
|
||||
[] 完全删除 core.plugin?(待定)
|
||||
[] 完全删除 core.plugin,采用 Plugin.register 的形式进行插件编写
|
||||
[] 通用 Addon 接口
|
||||
[] 完善加载系统
|
||||
[] 不同怪物可以在怪物手册中添加一些不同的边框
|
||||
[] 按住一个按键时显示怪物的攻防血
|
||||
[] 新的事件系统?
|
||||
[] 新的事件系统,并丰富自定义事件
|
||||
[] 事件、eval 内容预编译
|
||||
[] 新的存档系统,可以注册存档项
|
||||
[] 渐变切 bgm
|
||||
[] 新的 Flag 系统,使用 for 申请变量,dispose 释放变量,可设为渲染进程与游戏进程共通变量
|
||||
[] 注册可录像操作,比如可以在点击的时候执行,自动计入录像
|
||||
[] 机关门显示绑定怪物
|
||||
[] 自定义状态栏,通过申请空间进行布局
|
||||
[] 复写 api,rewrite()
|
||||
[] 对 vnode 进行简单的包装,提供出显示文字、显示图片等 api 以及修改 css 的 api
|
||||
|
@ -3,6 +3,8 @@ import { AudioParamOf, AudioPlayer } from './audio';
|
||||
import resource from '@/data/resource.json';
|
||||
import { ResourceController } from '../loader/controller';
|
||||
|
||||
// todo: 立体声,可设置音源位置
|
||||
|
||||
type Panner = AudioParamOf<PannerNode>;
|
||||
|
||||
export class SoundEffect extends AudioPlayer {
|
||||
|
@ -1,3 +1,4 @@
|
||||
// todo: 更改utils.ts的形式,使common文件夹可以同时在渲染进程和游戏进程使用
|
||||
import { has } from '@/plugin/utils';
|
||||
|
||||
export interface EmitableEvent {
|
||||
|
@ -6,6 +6,8 @@ import JSZip from 'jszip';
|
||||
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
|
||||
import { loading } from './load';
|
||||
|
||||
// todo: 应当用register去注册资源类型,然后进行分块处理
|
||||
|
||||
interface ResourceData {
|
||||
image: HTMLImageElement;
|
||||
arraybuffer: ArrayBuffer;
|
||||
|
@ -2,6 +2,8 @@ import { KeyCode } from '@/plugin/keyCodes';
|
||||
import { deleteWith, generateBinary, spliceBy } from '@/plugin/utils';
|
||||
import { EmitableEvent, EventEmitter } from '../../common/eventEmitter';
|
||||
|
||||
// todo: 按下时触发,长按(单次/连续)触发,按下连续触发,按下节流触发,按下加速节流触发
|
||||
|
||||
interface HotkeyEvent extends EmitableEvent {
|
||||
set: (id: string, key: KeyCode, assist: number) => void;
|
||||
emit: (key: KeyCode, assist: number, type: KeyEmitType) => void;
|
||||
|
122
src/core/main/custom/keyboard.ts
Normal file
122
src/core/main/custom/keyboard.ts
Normal 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;
|
||||
}
|
@ -9,6 +9,7 @@ import { GameStorage } from '../storage';
|
||||
export const mainScope = Symbol.for('@key_main');
|
||||
export const gameKey = new Hotkey('gameKey', '游戏按键');
|
||||
|
||||
// todo: 读取上一个手动存档,存档至下一个存档栏
|
||||
// ----- Register
|
||||
gameKey
|
||||
// --------------------
|
||||
|
@ -3,19 +3,21 @@ import { Button, InputNumber } from 'ant-design-vue';
|
||||
import { mainUi } from './ui';
|
||||
import { gameKey } from './hotkey';
|
||||
|
||||
// todo: 数字类型改为一个输入框,一个加按钮一个减按钮;新增单选框
|
||||
|
||||
interface Components {
|
||||
DefaultSetting: SettingComponent;
|
||||
BooleanSetting: SettingComponent;
|
||||
NumberSetting: SettingComponent;
|
||||
Default: SettingComponent;
|
||||
Boolean: SettingComponent;
|
||||
Number: SettingComponent;
|
||||
HotkeySetting: SettingComponent;
|
||||
ToolbarEditor: SettingComponent;
|
||||
}
|
||||
|
||||
export function createSettingComponents() {
|
||||
const com: Components = {
|
||||
DefaultSetting,
|
||||
BooleanSetting,
|
||||
NumberSetting,
|
||||
Default: DefaultSetting,
|
||||
Boolean: BooleanSetting,
|
||||
Number: NumberSetting,
|
||||
HotkeySetting,
|
||||
ToolbarEditor
|
||||
};
|
||||
|
@ -6,6 +6,8 @@ import type {
|
||||
import BoxAnimate from '@/components/boxAnimate.vue';
|
||||
import { checkAssist } from '../custom/hotkey';
|
||||
|
||||
// todo: 新增更改设置的ToolItem
|
||||
|
||||
interface Components {
|
||||
DefaultTool: CustomToolbarComponent;
|
||||
KeyTool: CustomToolbarComponent<'hotkey'>;
|
||||
|
@ -85,7 +85,7 @@ export class MotaSetting extends EventEmitter<SettingEvent> {
|
||||
key: string,
|
||||
name: string,
|
||||
value: MotaSettingType,
|
||||
com: SettingComponent = COM.DefaultSetting,
|
||||
com: SettingComponent = COM.Default,
|
||||
step: [number, number, number] = [0, 100, 1]
|
||||
) {
|
||||
const setting: MotaSettingItem = {
|
||||
@ -274,11 +274,34 @@ export class SettingDisplayer extends EventEmitter<SettingDisplayerEvent> {
|
||||
}
|
||||
}
|
||||
|
||||
// todo: 优化存储方式
|
||||
|
||||
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) => {
|
||||
const [root, setting] = key.split('.');
|
||||
|
||||
if (root === 'screen') {
|
||||
handleScreenSetting(setting, n, o);
|
||||
} else if (root === 'action') {
|
||||
@ -367,28 +390,30 @@ function handleUtilsSetting<T extends number | boolean>(
|
||||
}
|
||||
|
||||
// ----- 游戏的所有设置项
|
||||
// todo: 虚拟键盘缩放,小地图楼传缩放
|
||||
mainSetting
|
||||
.register(
|
||||
'screen',
|
||||
'显示设置',
|
||||
new MotaSetting()
|
||||
.register('fullscreen', '全屏游戏', false, COM.BooleanSetting)
|
||||
.register('halo', '光环显示', true, COM.BooleanSetting)
|
||||
.register('itemDetail', '宝石血瓶显伤', true, COM.BooleanSetting)
|
||||
.register('heroDetail', '勇士显伤', false, COM.BooleanSetting)
|
||||
.register('transition', '界面动画', false, COM.BooleanSetting)
|
||||
.register('antiAlias', '抗锯齿', false, COM.BooleanSetting)
|
||||
.register('fontSize', '字体大小', 16, COM.NumberSetting, [8, 28, 1])
|
||||
.register('smoothView', '平滑镜头', true, COM.BooleanSetting)
|
||||
.register('criticalGem', '临界显示方式', false, COM.BooleanSetting)
|
||||
.register('fullscreen', '全屏游戏', false, COM.Boolean)
|
||||
.register('halo', '光环显示', true, COM.Boolean)
|
||||
.register('itemDetail', '宝石血瓶显伤', true, COM.Boolean)
|
||||
.register('heroDetail', '勇士显伤', false, COM.Boolean)
|
||||
.register('transition', '界面动画', false, COM.Boolean)
|
||||
.register('antiAlias', '抗锯齿', false, COM.Boolean)
|
||||
.register('fontSize', '字体大小', 16, COM.Number, [8, 28, 1])
|
||||
.register('smoothView', '平滑镜头', true, COM.Boolean)
|
||||
.register('criticalGem', '临界显示方式', false, COM.Boolean)
|
||||
.setDisplayFunc('criticalGem', value => (value ? '宝石数' : '攻击'))
|
||||
.register('keyScale', '虚拟键盘缩放', 100, COM.Number, [25, 5, 500])
|
||||
)
|
||||
.register(
|
||||
'action',
|
||||
'操作设置',
|
||||
new MotaSetting()
|
||||
.register('autoSkill', '自动切换技能', true, COM.BooleanSetting)
|
||||
.register('fixed', '定点查看', true, COM.BooleanSetting)
|
||||
.register('autoSkill', '自动切换技能', true, COM.Boolean)
|
||||
.register('fixed', '定点查看', true, COM.Boolean)
|
||||
.register('hotkey', '快捷键', false, COM.HotkeySetting)
|
||||
.setDisplayFunc('hotkey', () => '')
|
||||
.register('toolbar', '自定义工具栏', false, COM.ToolbarEditor)
|
||||
@ -398,37 +423,28 @@ mainSetting
|
||||
'utils',
|
||||
'系统设置',
|
||||
new MotaSetting()
|
||||
.register('betterLoad', '优化加载', true, COM.BooleanSetting)
|
||||
.register('autoScale', '自动放缩', true, COM.BooleanSetting)
|
||||
.register('betterLoad', '优化加载', true, COM.Boolean)
|
||||
.register('autoScale', '自动放缩', true, COM.Boolean)
|
||||
)
|
||||
.register(
|
||||
'fx',
|
||||
'特效设置',
|
||||
new MotaSetting()
|
||||
.register('paraLight', '野外阴影', true, COM.BooleanSetting)
|
||||
.register('frag', '打怪特效', true, COM.BooleanSetting)
|
||||
.register('paraLight', '野外阴影', true, COM.Boolean)
|
||||
.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', () => {
|
||||
mainSetting.reset({
|
||||
'screen.fullscreen': !!document.fullscreenElement,
|
||||
|
@ -30,12 +30,15 @@ export class GameStorage<T> {
|
||||
* @param key 存储的名称
|
||||
* @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]) {
|
||||
this.data[key] = value;
|
||||
}
|
||||
|
||||
getValue<K extends keyof T>(key: K): T[K] | null;
|
||||
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]) {
|
||||
if (this.data[key]) return this.data[key];
|
||||
else {
|
||||
|
@ -18,6 +18,8 @@ import smooth from '@/plugin/fx/smoothView';
|
||||
import frag from '@/plugin/fx/frag';
|
||||
import { Mota } from '.';
|
||||
|
||||
// todo: 将插件更改为注册形式,分为渲染进程和游戏进程两部分,同时分配优先级
|
||||
|
||||
export function resolvePlugin() {
|
||||
const toForward: [keyof Mota['plugin'], any][] = [
|
||||
['pop', pop()],
|
||||
|
32
src/panel/keyboard.vue
Normal file
32
src/panel/keyboard.vue
Normal 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>
|
@ -3,10 +3,11 @@ import { MessageApi } from 'ant-design-vue/lib/message';
|
||||
import { isNil } from 'lodash-es';
|
||||
import { Animation, sleep, TimingFn } from 'mutate-animate';
|
||||
import { ref } from 'vue';
|
||||
import { EVENT_KEY_CODE_MAP } from './keyCodes';
|
||||
import { EVENT_KEY_CODE_MAP, KeyCode } from './keyCodes';
|
||||
import axios from 'axios';
|
||||
import { decompressFromBase64 } from 'lz-string';
|
||||
import { parseColor } from './webgl/utils';
|
||||
import { KeyboardEmits } from '@/core/main/custom/keyboard';
|
||||
|
||||
type CanParseCss = keyof {
|
||||
[P in keyof CSSStyleDeclaration as CSSStyleDeclaration[P] extends string
|
||||
@ -264,6 +265,11 @@ export function pColor(color: string) {
|
||||
return `rgba(${arr.join(',')})` as Color;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数组内的某个项,返回删除后的数组
|
||||
* @param arr 要操作的数组
|
||||
* @param ele 要删除的项
|
||||
*/
|
||||
export function deleteWith<T>(arr: T[], ele: T): T[] {
|
||||
const index = arr.indexOf(ele);
|
||||
if (index === -1) return arr;
|
||||
@ -339,3 +345,18 @@ export function flipBinary(num: number, col: number) {
|
||||
if (num & n) 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 });
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user