mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-31 23:29:27 +08:00
feat: 显示自定义工具栏
This commit is contained in:
parent
9adcb5543f
commit
56ff2098f7
1
idea.md
1
idea.md
@ -105,3 +105,4 @@ dam4.png ---- 存档 59
|
||||
[] 完善加载系统
|
||||
[] 不同怪物可以在怪物手册中添加一些不同的边框
|
||||
[] 按住一个按键时显示怪物的攻防血
|
||||
[] 新的事件系统?
|
||||
|
@ -271,3 +271,10 @@ export function unwarpBinary(bin: number): AssistHoykey {
|
||||
alt: !!(bin & (1 << 2))
|
||||
};
|
||||
}
|
||||
|
||||
export function checkAssist(bin: number, key: KeyCode) {
|
||||
return !!(
|
||||
(1 << (key === KeyCode.Ctrl ? 0 : key === KeyCode.Shift ? 1 : 2)) &
|
||||
bin
|
||||
);
|
||||
}
|
||||
|
180
src/core/main/custom/toolbar.ts
Normal file
180
src/core/main/custom/toolbar.ts
Normal file
@ -0,0 +1,180 @@
|
||||
import { EmitableEvent, EventEmitter } from '@/core/common/eventEmitter';
|
||||
import { KeyCode } from '@/plugin/keyCodes';
|
||||
import { flipBinary, has } from '@/plugin/utils';
|
||||
import { FunctionalComponent, reactive } from 'vue';
|
||||
import { createToolbarComponents } from '../init/toolbar';
|
||||
import { gameKey } from '../init/hotkey';
|
||||
import { unwarpBinary } from './hotkey';
|
||||
|
||||
interface CustomToolbarEvent extends EmitableEvent {
|
||||
add: (item: ValueOf<ToolbarItemMap>) => void;
|
||||
delete: (item: ValueOf<ToolbarItemMap>) => void;
|
||||
set: (id: string, data: Partial<SettableItemData>) => void;
|
||||
emit: (id: string) => void;
|
||||
}
|
||||
|
||||
type ToolbarItemType = 'hotkey' | 'item' | 'assistKey';
|
||||
|
||||
interface ToolbarItemBase<T extends ToolbarItemType> {
|
||||
type: T;
|
||||
id: string;
|
||||
com: CustomToolbarComponent<T>;
|
||||
}
|
||||
|
||||
// 快捷键
|
||||
interface HotkeyToolbarItem extends ToolbarItemBase<'hotkey'> {
|
||||
key: KeyCode;
|
||||
assist: number;
|
||||
}
|
||||
|
||||
// 使用道具
|
||||
interface ItemToolbarItem extends ToolbarItemBase<'item'> {
|
||||
item: ItemIdOf<'tools' | 'constants'>;
|
||||
}
|
||||
|
||||
// 切换辅助按键 ctrl alt shift
|
||||
interface AssistKeyToolbarItem extends ToolbarItemBase<'assistKey'> {
|
||||
assist: KeyCode.Ctrl | KeyCode.Shift | KeyCode.Alt;
|
||||
}
|
||||
|
||||
interface ToolbarItemMap {
|
||||
hotkey: HotkeyToolbarItem;
|
||||
item: ItemToolbarItem;
|
||||
assistKey: AssistKeyToolbarItem;
|
||||
}
|
||||
|
||||
export type SettableItemData<T extends ToolbarItemType = ToolbarItemType> =
|
||||
Omit<ToolbarItemMap[T], 'id' | 'type'>;
|
||||
|
||||
export interface CustomToolbarProps<
|
||||
T extends ToolbarItemType = ToolbarItemType
|
||||
> {
|
||||
item: ToolbarItemMap[T];
|
||||
toolbar: CustomToolbar;
|
||||
}
|
||||
export type CustomToolbarComponent<
|
||||
T extends ToolbarItemType = ToolbarItemType
|
||||
> = FunctionalComponent<CustomToolbarProps<T>>;
|
||||
|
||||
const COM = createToolbarComponents();
|
||||
|
||||
const comMap: {
|
||||
[P in ToolbarItemType]: CustomToolbarComponent<P>;
|
||||
} = {
|
||||
hotkey: COM.KeyTool,
|
||||
item: COM.ItemTool,
|
||||
assistKey: COM.AssistKeyTool
|
||||
};
|
||||
|
||||
export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
||||
static num: number = 0;
|
||||
static list: CustomToolbar[] = [];
|
||||
|
||||
items: ValueOf<ToolbarItemMap>[] = reactive([]);
|
||||
num: number = CustomToolbar.num++;
|
||||
id: string;
|
||||
// ----- size
|
||||
x: number = 300;
|
||||
y: number = 300;
|
||||
width: number = 300;
|
||||
height: number = 100;
|
||||
// ----- other
|
||||
assistKey: number = 0;
|
||||
|
||||
constructor(id: string) {
|
||||
super();
|
||||
this.id = id;
|
||||
CustomToolbar.list.push(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个自定义项
|
||||
* @param item 要添加的自定义工具栏项
|
||||
*/
|
||||
add<K extends ToolbarItemType>(item: Omit<ToolbarItemMap[K], 'com'>) {
|
||||
// @ts-ignore
|
||||
const data: ToolbarItemMap[K] = {
|
||||
com: comMap[item.type],
|
||||
...item
|
||||
} as ToolbarItemMap[K];
|
||||
this.items.push(data);
|
||||
this.emit('add', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个自定义项
|
||||
* @param id 要删除的项的id
|
||||
*/
|
||||
delete(id: string) {
|
||||
const index = this.items.findIndex(v => v.id === id);
|
||||
if (index === -1) return;
|
||||
const item = this.items[index];
|
||||
this.items.splice(index, 1);
|
||||
this.emit('delete', item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个项
|
||||
* @param id 要设置的项的id
|
||||
* @param item 要设置的属性内容
|
||||
*/
|
||||
set<T extends ToolbarItemType>(
|
||||
id: string,
|
||||
item: Partial<SettableItemData<T>>
|
||||
) {
|
||||
const toSet = this.items.find(v => v.id === id);
|
||||
if (!toSet) return;
|
||||
Object.assign(toSet, item);
|
||||
this.emit('set', id, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发一个自定义工具
|
||||
* @param id 要触发的自定义工具的id
|
||||
*/
|
||||
emitTool(id: string) {
|
||||
const item = this.items.find(v => v.id === id);
|
||||
if (!item) return;
|
||||
this.emit(id);
|
||||
if (item.type === 'hotkey') {
|
||||
// 按键
|
||||
const { ctrl, shift, alt } = unwarpBinary(
|
||||
item.assist | this.assistKey
|
||||
);
|
||||
const ev = new KeyboardEvent('keyup', {
|
||||
ctrlKey: ctrl,
|
||||
shiftKey: shift,
|
||||
altKey: alt
|
||||
});
|
||||
|
||||
// todo: Advanced KeyboardEvent simulate
|
||||
gameKey.emitKey(item.key, item.assist, 'up', ev);
|
||||
} else if (item.type === 'item') {
|
||||
// 道具
|
||||
core.tryUseItem(item.item);
|
||||
} else if (item.type === 'assistKey') {
|
||||
// 辅助按键
|
||||
if (item.assist === KeyCode.Ctrl) {
|
||||
this.assistKey = flipBinary(this.assistKey, 0);
|
||||
} else if (item.assist === KeyCode.Shift) {
|
||||
this.assistKey = flipBinary(this.assistKey, 1);
|
||||
} else if (item.assist === KeyCode.Alt) {
|
||||
this.assistKey = flipBinary(this.assistKey, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setPos(x?: number, y?: number) {
|
||||
has(x) && (this.x = x);
|
||||
has(y) && (this.y = y);
|
||||
}
|
||||
|
||||
setSize(width?: number, height?: number) {
|
||||
has(width) && (this.width = width);
|
||||
has(height) && (this.height = height);
|
||||
}
|
||||
|
||||
static get(id: string) {
|
||||
return this.list.find(v => v.id === id);
|
||||
}
|
||||
}
|
71
src/core/main/init/toolbar.tsx
Normal file
71
src/core/main/init/toolbar.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import { KeyCodeUtils } from '@/plugin/keyCodes';
|
||||
import type {
|
||||
CustomToolbarComponent,
|
||||
CustomToolbarProps
|
||||
} from '../custom/toolbar';
|
||||
import BoxAnimate from '@/components/boxAnimate.vue';
|
||||
import { onUnmounted, ref } from 'vue';
|
||||
import { checkAssist } from '../custom/hotkey';
|
||||
|
||||
interface Components {
|
||||
DefaultTool: CustomToolbarComponent;
|
||||
KeyTool: CustomToolbarComponent<'hotkey'>;
|
||||
ItemTool: CustomToolbarComponent<'item'>;
|
||||
AssistKeyTool: CustomToolbarComponent<'assistKey'>;
|
||||
}
|
||||
|
||||
export function createToolbarComponents() {
|
||||
const com: Components = {
|
||||
DefaultTool,
|
||||
KeyTool,
|
||||
ItemTool,
|
||||
AssistKeyTool
|
||||
};
|
||||
return com;
|
||||
}
|
||||
|
||||
function DefaultTool(props: CustomToolbarProps) {
|
||||
return <span>未知工具</span>;
|
||||
}
|
||||
|
||||
function KeyTool(props: CustomToolbarProps<'hotkey'>) {
|
||||
const { item, toolbar } = props;
|
||||
return (
|
||||
<span onClick={() => toolbar.emitTool(item.id)}>
|
||||
{KeyCodeUtils.toString(item.key)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function ItemTool(props: CustomToolbarProps<'item'>) {
|
||||
const { item, toolbar } = props;
|
||||
return (
|
||||
<div onClick={() => toolbar.emitTool(item.id)}>
|
||||
<BoxAnimate id={item.item}></BoxAnimate>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AssistKeyTool(props: CustomToolbarProps<'assistKey'>) {
|
||||
const { item, toolbar } = props;
|
||||
const pressed = ref(checkAssist(toolbar.assistKey, item.assist));
|
||||
const listen = () => {
|
||||
pressed.value = checkAssist(toolbar.assistKey, item.assist);
|
||||
};
|
||||
toolbar.on('emit', listen);
|
||||
|
||||
onUnmounted(() => {
|
||||
toolbar.off('emit', listen);
|
||||
});
|
||||
|
||||
return (
|
||||
<span
|
||||
class="button-text"
|
||||
// @ts-ignore
|
||||
active={pressed.value}
|
||||
onClick={() => toolbar.emitTool(item.id)}
|
||||
>
|
||||
{KeyCodeUtils.toString(item.assist)}
|
||||
</span>
|
||||
);
|
||||
}
|
@ -28,7 +28,8 @@ fixedUi.register(
|
||||
new GameUi('fixed', UI.Fixed),
|
||||
new GameUi('chapter', UI.Chapter),
|
||||
new GameUi('completeAchi', UI.CompleteAchi),
|
||||
new GameUi('start', UI.Start)
|
||||
new GameUi('start', UI.Start),
|
||||
new GameUi('toolbar', UI.Toolbar)
|
||||
);
|
||||
fixedUi.showAll();
|
||||
|
||||
|
@ -333,3 +333,9 @@ export function getStatusLabel(name: string) {
|
||||
}[name] || name
|
||||
);
|
||||
}
|
||||
|
||||
export function flipBinary(num: number, col: number) {
|
||||
const n = 1 << col;
|
||||
if (num & col) return num & ~n;
|
||||
else return num | n;
|
||||
}
|
||||
|
@ -20,3 +20,4 @@ export { default as Studied } from './studied.vue';
|
||||
export { default as Study } from './study.vue';
|
||||
export { default as Toolbox } from './toolbox.vue';
|
||||
export { default as Hotkey } from './hotkey.vue';
|
||||
export { default as Toolbar } from './toolbar.vue';
|
||||
|
62
src/ui/toolbar.vue
Normal file
62
src/ui/toolbar.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<Box
|
||||
:dragable="true"
|
||||
:resizable="true"
|
||||
v-model:left="box.x"
|
||||
v-model:top="box.y"
|
||||
v-model:height="box.height"
|
||||
v-model:width="box.width"
|
||||
>
|
||||
<div class="toolbar">
|
||||
<div v-for="item of bar.items">
|
||||
<component
|
||||
:is="(item.com as any)"
|
||||
:item="item"
|
||||
:toolbar="bar"
|
||||
></component>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import Box from '@/components/box.vue';
|
||||
import { CustomToolbar } from '@/core/main/custom/toolbar';
|
||||
import { GameUi } from '@/core/main/custom/ui';
|
||||
import { reactive, watch } from 'vue';
|
||||
|
||||
interface BoxData {
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
num: number;
|
||||
ui: GameUi;
|
||||
bar: CustomToolbar;
|
||||
}>();
|
||||
|
||||
const bar = props.bar;
|
||||
const box = reactive<BoxData>({
|
||||
x: bar.x,
|
||||
y: bar.y,
|
||||
width: bar.width,
|
||||
height: bar.height
|
||||
});
|
||||
|
||||
watch(box, ({ x, y, width, height }) => {
|
||||
bar.x = x;
|
||||
bar.y = y;
|
||||
bar.width = width;
|
||||
bar.height = height;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.toolbar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user