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 { GameUI, IUIMountable, SetupComponentOptions } from '@motajs/system-ui';
|
||||
import { useKey } from '../use';
|
||||
import { sleep } from 'mutate-animate';
|
||||
|
||||
export interface ConfirmBoxProps extends DefaultProps, TextContentProps {
|
||||
text: string;
|
||||
@ -192,7 +193,7 @@ export const ConfirmBox = defineComponent<
|
||||
);
|
||||
}, confirmBoxProps);
|
||||
|
||||
export type ChoiceKey = string | number | symbol;
|
||||
export type ChoiceKey = string | number;
|
||||
export type ChoiceItem = [key: ChoiceKey, text: string];
|
||||
|
||||
export interface ChoicesProps extends DefaultProps, TextContentProps {
|
||||
@ -211,6 +212,7 @@ export interface ChoicesProps extends DefaultProps, TextContentProps {
|
||||
titleFill?: CanvasStyle;
|
||||
pad?: number;
|
||||
interval?: number;
|
||||
selected?: number;
|
||||
}
|
||||
|
||||
export type ChoicesEmits = {
|
||||
@ -233,7 +235,8 @@ const choicesProps = {
|
||||
'titleFont',
|
||||
'titleFill',
|
||||
'pad',
|
||||
'interval'
|
||||
'interval',
|
||||
'selected'
|
||||
],
|
||||
emits: ['choose']
|
||||
} satisfies SetupComponentOptions<
|
||||
@ -283,7 +286,7 @@ export const Choices = defineComponent<
|
||||
>((props, { emit, attrs }) => {
|
||||
const titleHeight = ref(0);
|
||||
const contentHeight = ref(0);
|
||||
const selected = ref(0);
|
||||
const selected = ref(props.selected ?? 0);
|
||||
const pageCom = ref<PageExpose>();
|
||||
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} */
|
||||
export const ConfirmBoxUI = new GameUI('confirm-box', ConfirmBox);
|
||||
/** @see {@link Choices} */
|
||||
|
@ -1363,20 +1363,6 @@ export function calMapWalls(floor: FloorIds, nocache: boolean = false) {
|
||||
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 {
|
||||
static shadowList: Set<LayerShadowExtends> = new Set();
|
||||
id: string = 'shadow';
|
||||
|
@ -30,6 +30,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { isMobile } from '../use';
|
||||
import { detailInfo, getSpecialHint } from '../tools/book';
|
||||
import Scroll from '../components/scroll.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
fromBook?: boolean;
|
||||
|
@ -31,12 +31,7 @@
|
||||
class="detial-more"
|
||||
v-if="panel === 'special'"
|
||||
>
|
||||
<span
|
||||
id="enemy-target"
|
||||
class="button-text more"
|
||||
@click="changePanel($event, 'target')"
|
||||
><LeftOutlined />
|
||||
</span>
|
||||
<span id="enemy-target" class="button-text more"> </span>
|
||||
<span
|
||||
id="critical-more"
|
||||
class="button-text more"
|
||||
@ -81,7 +76,6 @@ import { useDrag } from '../use';
|
||||
import EnemySpecial from '../panel/enemySpecial.vue';
|
||||
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||
import EnemyCritical from '../panel/enemyCritical.vue';
|
||||
// import EnemyTarget from '../panel/enemyTarget.vue';
|
||||
import { detailInfo } from '../tools/book';
|
||||
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.steps = 0;
|
||||
core.status.replay.save = [];
|
||||
core.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199);
|
||||
core.setOpacity('replay', 0.6);
|
||||
this._replay_drawProgress();
|
||||
core.updateStatusBar(false, true);
|
||||
@ -1407,7 +1406,6 @@ control.prototype.rewindReplay = function () {
|
||||
steps: data.replay.steps,
|
||||
save: save
|
||||
};
|
||||
core.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199);
|
||||
core.setOpacity('replay', 0.6);
|
||||
core.control._replay_drawProgress();
|
||||
core.updateStatusBar(false, true);
|
||||
|
@ -2520,70 +2520,6 @@ events.prototype._precompile_switch = function (data) {
|
||||
};
|
||||
|
||||
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.replaceText(data.text, prefix),
|
||||
data.choices,
|
||||
@ -2646,41 +2582,17 @@ events.prototype._precompile_choices = function (data) {
|
||||
|
||||
events.prototype._action_confirm = function (data, x, y, prefix) {
|
||||
data.text = core.replaceText(data.text, prefix);
|
||||
core.status.event.ui = { text: data.text, yes: data.yes, no: data.no };
|
||||
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 (
|
||||
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);
|
||||
core.ui.drawConfirmBox(
|
||||
data.text,
|
||||
() => {
|
||||
core.insertAction(data.yes ?? []);
|
||||
core.doAction();
|
||||
},
|
||||
() => {
|
||||
core.insertAction(data.no ?? []);
|
||||
core.doAction();
|
||||
}
|
||||
} 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) {
|
||||
|
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;
|
||||
_setAutomaticRoute_drawRoute(step: any): void;
|
||||
_setAutomaticRoute_setAutoSteps(step: any): void;
|
||||
__replay_getTimeout(): number;
|
||||
}
|
||||
|
||||
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(
|
||||
content: string,
|
||||
choices: string[],
|
||||
choices: object[],
|
||||
width?: number,
|
||||
ctx?: CtxRefer
|
||||
): void;
|
||||
|
Loading…
Reference in New Issue
Block a user