mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-06-28 05:07:59 +08:00
refactor: 部分 UI 换成新 UI
This commit is contained in:
parent
010383a914
commit
45c1d8c952
@ -6,6 +6,7 @@ import { TextAlign } from './textboxTyper';
|
|||||||
import { Page, PageExpose } from './page';
|
import { Page, PageExpose } from './page';
|
||||||
import { GameUI, IUIMountable, SetupComponentOptions } from '@motajs/system-ui';
|
import { GameUI, IUIMountable, SetupComponentOptions } from '@motajs/system-ui';
|
||||||
import { useKey } from '../use';
|
import { useKey } from '../use';
|
||||||
|
import { sleep } from 'mutate-animate';
|
||||||
|
|
||||||
export interface ConfirmBoxProps extends DefaultProps, TextContentProps {
|
export interface ConfirmBoxProps extends DefaultProps, TextContentProps {
|
||||||
text: string;
|
text: string;
|
||||||
@ -192,7 +193,7 @@ export const ConfirmBox = defineComponent<
|
|||||||
);
|
);
|
||||||
}, confirmBoxProps);
|
}, confirmBoxProps);
|
||||||
|
|
||||||
export type ChoiceKey = string | number | symbol;
|
export type ChoiceKey = string | number;
|
||||||
export type ChoiceItem = [key: ChoiceKey, text: string];
|
export type ChoiceItem = [key: ChoiceKey, text: string];
|
||||||
|
|
||||||
export interface ChoicesProps extends DefaultProps, TextContentProps {
|
export interface ChoicesProps extends DefaultProps, TextContentProps {
|
||||||
@ -211,6 +212,7 @@ export interface ChoicesProps extends DefaultProps, TextContentProps {
|
|||||||
titleFill?: CanvasStyle;
|
titleFill?: CanvasStyle;
|
||||||
pad?: number;
|
pad?: number;
|
||||||
interval?: number;
|
interval?: number;
|
||||||
|
selected?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ChoicesEmits = {
|
export type ChoicesEmits = {
|
||||||
@ -233,7 +235,8 @@ const choicesProps = {
|
|||||||
'titleFont',
|
'titleFont',
|
||||||
'titleFill',
|
'titleFill',
|
||||||
'pad',
|
'pad',
|
||||||
'interval'
|
'interval',
|
||||||
|
'selected'
|
||||||
],
|
],
|
||||||
emits: ['choose']
|
emits: ['choose']
|
||||||
} satisfies SetupComponentOptions<
|
} satisfies SetupComponentOptions<
|
||||||
@ -283,7 +286,7 @@ export const Choices = defineComponent<
|
|||||||
>((props, { emit, attrs }) => {
|
>((props, { emit, attrs }) => {
|
||||||
const titleHeight = ref(0);
|
const titleHeight = ref(0);
|
||||||
const contentHeight = ref(0);
|
const contentHeight = ref(0);
|
||||||
const selected = ref(0);
|
const selected = ref(props.selected ?? 0);
|
||||||
const pageCom = ref<PageExpose>();
|
const pageCom = ref<PageExpose>();
|
||||||
const choiceSize = reactive<[number, number][]>([]);
|
const choiceSize = reactive<[number, number][]>([]);
|
||||||
|
|
||||||
@ -634,6 +637,122 @@ export function getChoice<T extends ChoiceKey = ChoiceKey>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getChoiceRoute() {
|
||||||
|
const route = core.status.replay.toReplay[0];
|
||||||
|
if (!route.startsWith('choices:')) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return Number(route.slice(8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹出一个确认框,然后将确认结果返回,与 getConfirm 不同的是内置录像支持,如果这个选择框需要进录像,
|
||||||
|
* 需要使用此方法。例如给玩家弹出一个确认框,并获取玩家是否确认:
|
||||||
|
* ```ts
|
||||||
|
* const confirm = await routedConfirm(
|
||||||
|
* // 在哪个 UI 控制器上打开,对于一般 UI 组件来说,直接填写 props.controller 即可
|
||||||
|
* props.controller,
|
||||||
|
* // 确认内容
|
||||||
|
* '确认要 xxx 吗?',
|
||||||
|
* // 确认框的位置,宽度由下一个参数指定,高度参数由组件内部计算得出,指定无效
|
||||||
|
* [240, 240, void 0, void 0, 0.5, 0.5],
|
||||||
|
* // 宽度设为 240
|
||||||
|
* 240,
|
||||||
|
* // 可以给选择框传入其他的 props,例如指定字体,此项可选
|
||||||
|
* { font: new Font('Verdana', 20) }
|
||||||
|
* );
|
||||||
|
* // 之后,就可以直接判断 confirm 来执行不同的操作了
|
||||||
|
* if (confirm) { ... }
|
||||||
|
* ```
|
||||||
|
* @param controller UI 控制器
|
||||||
|
* @param text 确认文本内容
|
||||||
|
* @param loc 确认框的位置
|
||||||
|
* @param width 确认框的宽度
|
||||||
|
* @param props 额外的 props,参考 {@link ConfirmBoxProps}
|
||||||
|
*/
|
||||||
|
export async function routedConfirm(
|
||||||
|
controller: IUIMountable,
|
||||||
|
text: string,
|
||||||
|
loc: ElementLocator,
|
||||||
|
width: number,
|
||||||
|
props?: Partial<ConfirmBoxProps>
|
||||||
|
) {
|
||||||
|
if (core.isReplaying()) {
|
||||||
|
const confirm = getChoiceRoute() === 1;
|
||||||
|
const timeout = core.control.__replay_getTimeout();
|
||||||
|
if (timeout === 0) return confirm;
|
||||||
|
const instance = controller.open(ConfirmBoxUI, {
|
||||||
|
...(props ?? {}),
|
||||||
|
text,
|
||||||
|
loc,
|
||||||
|
width,
|
||||||
|
defaultYes: confirm
|
||||||
|
});
|
||||||
|
await sleep(core.control.__replay_getTimeout());
|
||||||
|
controller.close(instance);
|
||||||
|
return confirm;
|
||||||
|
} else {
|
||||||
|
const confirm = await getConfirm(controller, text, loc, width, props);
|
||||||
|
core.status.route.push(`choices:${confirm ? 1 : 0}`);
|
||||||
|
return confirm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹出一个选择框,然后将选择结果返回,与 getChoice 不同的是内置录像支持,如果这个选择框需要进录像,
|
||||||
|
* 需要使用此方法。例如给玩家弹出一个选择框,并获取玩家选择了哪个:
|
||||||
|
* ```ts
|
||||||
|
* const choice = await routedChoice(
|
||||||
|
* // 在哪个 UI 控制器上打开,对于一般 UI 组件来说,直接填写 props.controller 即可
|
||||||
|
* props.controller,
|
||||||
|
* // 选项内容,参考 Choices 的注释
|
||||||
|
* [[0, '选项1'], [1, '选项2'], [2, '选项3']],
|
||||||
|
* // 选择框的位置,宽度由下一个参数指定,高度参数由组件内部计算得出,指定无效
|
||||||
|
* [240, 240, void 0, void 0, 0.5, 0.5],
|
||||||
|
* // 宽度设为 240
|
||||||
|
* 240,
|
||||||
|
* // 可以给选择框传入其他的 props,例如指定标题,此项可选
|
||||||
|
* { title: '选项标题' }
|
||||||
|
* );
|
||||||
|
* // 之后,就可以直接判断 choice 来执行不同的操作了
|
||||||
|
* if (choice === 0) { ... }
|
||||||
|
* ```
|
||||||
|
* @param controller UI 控制器
|
||||||
|
* @param choices 选择框的选项
|
||||||
|
* @param loc 选择框的位置
|
||||||
|
* @param width 选择框的宽度
|
||||||
|
* @param props 额外的 props,参考 {@link ChoicesProps}
|
||||||
|
*/
|
||||||
|
export async function routedChoices(
|
||||||
|
controller: IUIMountable,
|
||||||
|
choices: ChoiceItem[],
|
||||||
|
loc: ElementLocator,
|
||||||
|
width: number,
|
||||||
|
props?: Partial<ChoicesProps>
|
||||||
|
) {
|
||||||
|
if (core.isReplaying()) {
|
||||||
|
const selected = getChoiceRoute();
|
||||||
|
const timeout = core.control.__replay_getTimeout();
|
||||||
|
if (timeout === 0) return selected;
|
||||||
|
const instance = controller.open(ChoicesUI, {
|
||||||
|
...(props ?? {}),
|
||||||
|
choices,
|
||||||
|
loc,
|
||||||
|
width,
|
||||||
|
selected
|
||||||
|
});
|
||||||
|
await sleep(core.control.__replay_getTimeout());
|
||||||
|
controller.close(instance);
|
||||||
|
return selected;
|
||||||
|
} else {
|
||||||
|
const choice = await getChoice(controller, choices, loc, width, props);
|
||||||
|
const index = choices.findIndex(v => v[1] === choice);
|
||||||
|
core.status.route.push(`choices:${index}`);
|
||||||
|
return choice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @see {@link ConfirmBox} */
|
/** @see {@link ConfirmBox} */
|
||||||
export const ConfirmBoxUI = new GameUI('confirm-box', ConfirmBox);
|
export const ConfirmBoxUI = new GameUI('confirm-box', ConfirmBox);
|
||||||
/** @see {@link Choices} */
|
/** @see {@link Choices} */
|
||||||
|
@ -1363,20 +1363,6 @@ export function calMapWalls(floor: FloorIds, nocache: boolean = false) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @__PURE__ */ export function drawPolygons(floor: FloorIds) {
|
|
||||||
const polygons = calMapPolygons(floor);
|
|
||||||
const ctx = core.createCanvas('polygons', 0, 0, 480, 480, 130);
|
|
||||||
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.lineJoin = 'round';
|
|
||||||
ctx.strokeStyle = 'white';
|
|
||||||
for (const p of polygons) {
|
|
||||||
for (const [x, y, w, h] of p) {
|
|
||||||
ctx.strokeRect(x, y, w, h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LayerShadowExtends implements ILayerRenderExtends {
|
export class LayerShadowExtends implements ILayerRenderExtends {
|
||||||
static shadowList: Set<LayerShadowExtends> = new Set();
|
static shadowList: Set<LayerShadowExtends> = new Set();
|
||||||
id: string = 'shadow';
|
id: string = 'shadow';
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { isMobile } from '../use';
|
import { isMobile } from '../use';
|
||||||
import { detailInfo, getSpecialHint } from '../tools/book';
|
import { detailInfo, getSpecialHint } from '../tools/book';
|
||||||
|
import Scroll from '../components/scroll.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
fromBook?: boolean;
|
fromBook?: boolean;
|
||||||
|
@ -31,12 +31,7 @@
|
|||||||
class="detial-more"
|
class="detial-more"
|
||||||
v-if="panel === 'special'"
|
v-if="panel === 'special'"
|
||||||
>
|
>
|
||||||
<span
|
<span id="enemy-target" class="button-text more"> </span>
|
||||||
id="enemy-target"
|
|
||||||
class="button-text more"
|
|
||||||
@click="changePanel($event, 'target')"
|
|
||||||
><LeftOutlined />
|
|
||||||
</span>
|
|
||||||
<span
|
<span
|
||||||
id="critical-more"
|
id="critical-more"
|
||||||
class="button-text more"
|
class="button-text more"
|
||||||
@ -81,7 +76,6 @@ import { useDrag } from '../use';
|
|||||||
import EnemySpecial from '../panel/enemySpecial.vue';
|
import EnemySpecial from '../panel/enemySpecial.vue';
|
||||||
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||||
import EnemyCritical from '../panel/enemyCritical.vue';
|
import EnemyCritical from '../panel/enemyCritical.vue';
|
||||||
// import EnemyTarget from '../panel/enemyTarget.vue';
|
|
||||||
import { detailInfo } from '../tools/book';
|
import { detailInfo } from '../tools/book';
|
||||||
import { gameKey } from '@motajs/system-action';
|
import { gameKey } from '@motajs/system-action';
|
||||||
|
|
||||||
|
@ -1272,7 +1272,6 @@ control.prototype.startReplay = function (list) {
|
|||||||
core.status.replay.totalList = core.status.route.concat(list);
|
core.status.replay.totalList = core.status.route.concat(list);
|
||||||
core.status.replay.steps = 0;
|
core.status.replay.steps = 0;
|
||||||
core.status.replay.save = [];
|
core.status.replay.save = [];
|
||||||
core.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199);
|
|
||||||
core.setOpacity('replay', 0.6);
|
core.setOpacity('replay', 0.6);
|
||||||
this._replay_drawProgress();
|
this._replay_drawProgress();
|
||||||
core.updateStatusBar(false, true);
|
core.updateStatusBar(false, true);
|
||||||
@ -1407,7 +1406,6 @@ control.prototype.rewindReplay = function () {
|
|||||||
steps: data.replay.steps,
|
steps: data.replay.steps,
|
||||||
save: save
|
save: save
|
||||||
};
|
};
|
||||||
core.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199);
|
|
||||||
core.setOpacity('replay', 0.6);
|
core.setOpacity('replay', 0.6);
|
||||||
core.control._replay_drawProgress();
|
core.control._replay_drawProgress();
|
||||||
core.updateStatusBar(false, true);
|
core.updateStatusBar(false, true);
|
||||||
|
@ -2520,70 +2520,6 @@ events.prototype._precompile_switch = function (data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
events.prototype._action_choices = function (data, x, y, prefix) {
|
events.prototype._action_choices = function (data, x, y, prefix) {
|
||||||
data.choices = data.choices.filter(function (x) {
|
|
||||||
if (x._disabled) return false;
|
|
||||||
if (x.condition == null || x.condition == '') return true;
|
|
||||||
try {
|
|
||||||
return core.calValue(x.condition, prefix);
|
|
||||||
} catch (e) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (data.choices.length == 0) return this.doAction();
|
|
||||||
if (core.isReplaying()) {
|
|
||||||
var action = core.status.replay.toReplay.shift();
|
|
||||||
if (
|
|
||||||
action.indexOf('choices:') == 0 &&
|
|
||||||
!(action == 'choices:none' && !data.timeout)
|
|
||||||
) {
|
|
||||||
var index = action.substring(8);
|
|
||||||
if (!this.__action_choices_replaying(data, index)) {
|
|
||||||
core.control._replay_error(action);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 容错录像
|
|
||||||
if (main.replayChecking) {
|
|
||||||
// 录像验证系统中选最后一项
|
|
||||||
if (action != 'choices:none')
|
|
||||||
core.status.replay.toReplay.unshift(action); // 首先归还刚才读出的下一步操作
|
|
||||||
core.events.__action_choices_replaying(data, -1);
|
|
||||||
} else {
|
|
||||||
// 正常游戏中弹窗选择
|
|
||||||
core.myprompt(
|
|
||||||
'录像回放出错!当前需要执行选择项但录像中未记录。\n如需修复请输入您要选的项(从0起),点击取消将不会修复。',
|
|
||||||
0,
|
|
||||||
function (value) {
|
|
||||||
if (value == null) {
|
|
||||||
core.control._replay_error(action);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action != 'choices:none')
|
|
||||||
core.status.replay.toReplay.unshift(action); // 首先归还刚才读出的下一步操作
|
|
||||||
core.events.__action_choices_replaying(
|
|
||||||
data,
|
|
||||||
((parseInt(value) || 0) + data.choices.length) %
|
|
||||||
data.choices.length
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (data.timeout) {
|
|
||||||
core.status.event.interval = setTimeout(function () {
|
|
||||||
core.status.route.push('choices:none');
|
|
||||||
core.setFlag('timeout', 0);
|
|
||||||
core.doAction();
|
|
||||||
}, data.timeout);
|
|
||||||
}
|
|
||||||
core.status.event.timeout = new Date().getTime() + (data.timeout || 0);
|
|
||||||
}
|
|
||||||
for (var i = 0; i < data.choices.length; i++) {
|
|
||||||
if (typeof data.choices[i] === 'string')
|
|
||||||
data.choices[i] = { text: data.choices[i] };
|
|
||||||
data.choices[i].text = core.replaceText(data.choices[i].text, prefix);
|
|
||||||
}
|
|
||||||
core.ui.drawChoices(
|
core.ui.drawChoices(
|
||||||
core.replaceText(data.text, prefix),
|
core.replaceText(data.text, prefix),
|
||||||
data.choices,
|
data.choices,
|
||||||
@ -2646,41 +2582,17 @@ events.prototype._precompile_choices = function (data) {
|
|||||||
|
|
||||||
events.prototype._action_confirm = function (data, x, y, prefix) {
|
events.prototype._action_confirm = function (data, x, y, prefix) {
|
||||||
data.text = core.replaceText(data.text, prefix);
|
data.text = core.replaceText(data.text, prefix);
|
||||||
core.status.event.ui = { text: data.text, yes: data.yes, no: data.no };
|
core.ui.drawConfirmBox(
|
||||||
if (core.isReplaying()) {
|
data.text,
|
||||||
var action = core.status.replay.toReplay.shift();
|
() => {
|
||||||
if (
|
core.insertAction(data.yes ?? []);
|
||||||
action.indexOf('choices:') == 0 &&
|
core.doAction();
|
||||||
!(action == 'choices:none' && !data.timeout)
|
},
|
||||||
) {
|
() => {
|
||||||
var index = action.substring(8);
|
core.insertAction(data.no ?? []);
|
||||||
if (
|
core.doAction();
|
||||||
index == 'none' ||
|
|
||||||
((index = parseInt(index)) >= 0 && index % 100 < 2)
|
|
||||||
) {
|
|
||||||
this.__action_confirm_replaying(data, index);
|
|
||||||
} else {
|
|
||||||
core.control._replay_error(action);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 录像中未记录选了哪个,则选默认值,而不是直接报错
|
|
||||||
if (action != 'choices:none')
|
|
||||||
core.status.replay.toReplay.unshift(action);
|
|
||||||
this.__action_confirm_replaying(data, data['default'] ? 0 : 1);
|
|
||||||
}
|
}
|
||||||
} else {
|
);
|
||||||
core.status.event.selection = data['default'] ? 0 : 1;
|
|
||||||
if (data.timeout) {
|
|
||||||
core.status.event.interval = setTimeout(function () {
|
|
||||||
core.status.route.push('choices:none');
|
|
||||||
core.setFlag('timeout', 0);
|
|
||||||
core.doAction();
|
|
||||||
}, data.timeout);
|
|
||||||
}
|
|
||||||
core.status.event.timeout = new Date().getTime() + (data.timeout || 0);
|
|
||||||
}
|
|
||||||
core.ui.drawConfirmBox(data.text);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
events.prototype.__action_confirm_replaying = function (data, index) {
|
events.prototype.__action_confirm_replaying = function (data, index) {
|
||||||
|
1738
public/libs/ui.js
1738
public/libs/ui.js
File diff suppressed because it is too large
Load Diff
1
src/types/declaration/control.d.ts
vendored
1
src/types/declaration/control.d.ts
vendored
@ -1179,6 +1179,7 @@ interface Control {
|
|||||||
): boolean;
|
): boolean;
|
||||||
_setAutomaticRoute_drawRoute(step: any): void;
|
_setAutomaticRoute_drawRoute(step: any): void;
|
||||||
_setAutomaticRoute_setAutoSteps(step: any): void;
|
_setAutomaticRoute_setAutoSteps(step: any): void;
|
||||||
|
__replay_getTimeout(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const control: new () => Control;
|
declare const control: new () => Control;
|
||||||
|
2
src/types/declaration/ui.d.ts
vendored
2
src/types/declaration/ui.d.ts
vendored
@ -764,7 +764,7 @@ interface Ui {
|
|||||||
*/
|
*/
|
||||||
drawChoices(
|
drawChoices(
|
||||||
content: string,
|
content: string,
|
||||||
choices: string[],
|
choices: object[],
|
||||||
width?: number,
|
width?: number,
|
||||||
ctx?: CtxRefer
|
ctx?: CtxRefer
|
||||||
): void;
|
): void;
|
||||||
|
Loading…
Reference in New Issue
Block a user