fix(09-05): repair src/ui migration type errors and prettier ui files

- main.tsx: p.state -> props.state (09-04 leftover typo)
This commit is contained in:
unanmed 2026-10-10 14:17:41 +08:00
parent 3a49b37c25
commit 8cfbc7333e
5 changed files with 428 additions and 430 deletions

View File

@ -1,4 +1,8 @@
import { GameUI, SetupComponentOptions, IUIDefaultPropsBase } from '@motajs/system';
import {
GameUI,
SetupComponentOptions,
IUIDefaultPropsBase
} from '@motajs/system';
import { DefaultProps } from '@motajs/render-vue';
import { defineComponent } from 'vue';
import { MAIN_WIDTH, MAIN_HEIGHT } from '../shared';

View File

@ -53,7 +53,7 @@ const MainScene = defineComponent<MainSceneProps>(props => {
};
const hideStatus = ref(
p.state.flags.getFieldValueDefaults('hideStatusBar', false)
props.state.flags.getFieldValueDefaults('hideStatusBar', false)
);
// TODO: flags 更新未接(当前无监听系统)
// const weather = new WeatherController();

View File

@ -57,6 +57,7 @@ export const MainSettings = defineComponent<MainSettingsProps>(props => {
[MainChoice.Back, '返回游戏']
];
const controller: IUIController<IGameUIPropsBase> = props.controller;
const [key, scope] = useKey();
key.realize('exit', () => props.controller.close(props.instance));
@ -78,21 +79,21 @@ export const MainSettings = defineComponent<MainSettingsProps>(props => {
break;
}
case MainChoice.ViewMap: {
props.controller.open(ViewMapUI, {
controller.open(ViewMapUI, {
loc: FULL_LOC
});
break;
}
case MainChoice.Replay: {
props.controller.open(ReplaySettingsUI, { loc: props.loc });
controller.open(ReplaySettingsUI, { loc: props.loc });
break;
}
case MainChoice.SyncSave: {
props.controller.open(SyncSaveUI, { loc: props.loc });
controller.open(SyncSaveUI, { loc: props.loc });
break;
}
case MainChoice.GameInfo: {
props.controller.open(GameInfoUI, { loc: props.loc });
controller.open(GameInfoUI, { loc: props.loc });
break;
}
case MainChoice.Restart: {
@ -363,13 +364,14 @@ export const SyncSave = defineComponent<MainSettingsProps>(props => {
[SyncSaveChoice.Back, '返回上一级']
];
const controller: IUIController<IGameUIPropsBase> = props.controller;
const [key, scope] = useKey();
key.realize('exit', () => props.controller.close(props.instance));
const choose = async (key: ChoiceKey) => {
switch (key) {
case SyncSaveChoice.ToServer: {
props.controller.open(SyncSaveSelectUI, { loc: props.loc });
controller.open(SyncSaveSelectUI, { loc: props.loc });
break;
}
case SyncSaveChoice.FromServer: {
@ -383,7 +385,7 @@ export const SyncSave = defineComponent<MainSettingsProps>(props => {
break;
}
case SyncSaveChoice.ToLocal: {
props.controller.open(DownloadSaveSelectUI, { loc: props.loc });
controller.open(DownloadSaveSelectUI, { loc: props.loc });
break;
}
case SyncSaveChoice.FromLocal: {
@ -391,7 +393,7 @@ export const SyncSave = defineComponent<MainSettingsProps>(props => {
break;
}
case SyncSaveChoice.ClearLocal: {
props.controller.open(ClearSaveSelectUI, { loc: props.loc });
controller.open(ClearSaveSelectUI, { loc: props.loc });
break;
}
case SyncSaveChoice.Back: {

View File

@ -7,7 +7,7 @@ import {
reactive,
shallowReactive
} from 'vue';
import { TextContent } from '@user/client-base';
import { TextContent, IClientBaseExtended } from '@user/client-base';
import { ElementLocator, Font, ITexture } from '@motajs/render';
import { MixedToolbar, ReplayingStatus } from './toolbar';
import { openViewMap } from './viewmap';
@ -19,7 +19,6 @@ import {
STATUS_BAR_WIDTH
} from '../shared';
import { DefaultProps } from '@motajs/render-vue';
import { IUIPropsBase } from './types';
export interface ILeftHeroStatus {
/** 楼层 id */
@ -100,7 +99,7 @@ interface KeyLikeInfo {
readonly items: KeyLikeItem[];
}
interface StatusBarProps extends DefaultProps, IUIPropsBase {
interface StatusBarProps extends DefaultProps, IClientBaseExtended {
loc: ElementLocator;
hidden: boolean;
}
@ -109,456 +108,450 @@ const statusBarProps = {
props: ['loc', 'hidden', 'state']
} satisfies SetupComponentOptions<StatusBarProps>;
export const LeftStatusBar = defineComponent<StatusBarProps>(
p => {
//#region 参数定义
export const LeftStatusBar = defineComponent<StatusBarProps>(p => {
//#region 参数定义
/** 属性文字的横坐标 */
const TEXT_X = 54;
/** 图标的横坐标 */
const STATUS_PAD = 8;
/** 楼层名称的高度 */
const TITLE_HEIGHT = 36;
/** 状态属性的开始纵坐标 */
const STATUS_Y = TITLE_HEIGHT + STATUS_PAD;
/** 属性文字的横坐标 */
const TEXT_X = 54;
/** 图标的横坐标 */
const STATUS_PAD = 8;
/** 楼层名称的高度 */
const TITLE_HEIGHT = 36;
/** 状态属性的开始纵坐标 */
const STATUS_Y = TITLE_HEIGHT + STATUS_PAD;
const materials = p.state.materials;
const materials = p.state.materials;
// 可以换成 materials.getImageByAlias('xxx.png') 来使用全塔属性注册的图片
const hpIcon = materials.getImageByAlias('icon-hp');
const atkIcon = materials.getImageByAlias('icon-atk');
const defIcon = materials.getImageByAlias('icon-def');
const mdefIcon = materials.getImageByAlias('icon-mdef');
const moneyIcon = materials.getImageByAlias('icon-money');
const expIcon = materials.getImageByAlias('icon-exp');
const manaIcon = materials.getImageByAlias('icon-mana');
const lvIcon = materials.getImageByAlias('icon-lv');
// 可以换成 materials.getImageByAlias('xxx.png') 来使用全塔属性注册的图片
const hpIcon = materials.getImageByAlias('icon-hp');
const atkIcon = materials.getImageByAlias('icon-atk');
const defIcon = materials.getImageByAlias('icon-def');
const mdefIcon = materials.getImageByAlias('icon-mdef');
const moneyIcon = materials.getImageByAlias('icon-money');
const expIcon = materials.getImageByAlias('icon-exp');
const manaIcon = materials.getImageByAlias('icon-mana');
const lvIcon = materials.getImageByAlias('icon-lv');
const leftStatus: ILeftHeroStatus = reactive({
hp: 0,
hpmax: 0,
mana: 0,
manamax: 0,
atk: 0,
def: 0,
mdef: 0,
money: 0,
exp: 0,
// TODO: 缺少「距升级所需经验」钩子(legacy core.getNextLvUpNeed 无新对应)
up: 0,
// TODO: 缺少道具数量变更钩子(IHeroItems 未实现 IHookable)
yellowKey: 0,
blueKey: 0,
redKey: 0,
greenKey: 0,
pickaxe: 0,
bomb: 0,
centerFly: 0,
// TODO: flags 更新未接(当前无监听系统)
poison: false,
weak: false,
curse: false,
floor: 'MT0',
lv: '',
// TODO: 缺少聚合录像状态钩子(replaySystem 仅提供沙箱级钩子 onCreateSandbox/onStartReplay 等);原值来源 legacy core.status.replay
replay: reactive<ReplayingStatus>({
replaying: false,
playing: false,
speed: 1,
played: 0,
total: 0
})
});
const leftStatus: ILeftHeroStatus = reactive({
hp: 0,
hpmax: 0,
mana: 0,
manamax: 0,
atk: 0,
def: 0,
mdef: 0,
money: 0,
exp: 0,
// TODO: 缺少「距升级所需经验」钩子(legacy core.getNextLvUpNeed 无新对应)
up: 0,
// TODO: 缺少道具数量变更钩子(IHeroItems 未实现 IHookable)
yellowKey: 0,
blueKey: 0,
redKey: 0,
greenKey: 0,
pickaxe: 0,
bomb: 0,
centerFly: 0,
// TODO: flags 更新未接(当前无监听系统)
poison: false,
weak: false,
curse: false,
floor: 'MT0',
lv: '',
// TODO: 缺少聚合录像状态钩子(replaySystem 仅提供沙箱级钩子 onCreateSandbox/onStartReplay 等);原值来源 legacy core.status.replay
replay: reactive<ReplayingStatus>({
replaying: false,
playing: false,
speed: 1,
played: 0,
total: 0
})
});
const s = leftStatus;
const s = leftStatus;
const refreshAttribute = () => {
s.atk = p.state.hero.attribute.getFinalAttribute('atk');
s.hp = p.state.hero.attribute.getFinalAttribute('hp');
s.hpmax = p.state.hero.attribute.getFinalAttribute('hpmax');
s.mana = p.state.hero.attribute.getFinalAttribute('mana');
s.manamax = p.state.hero.attribute.getFinalAttribute('manamax');
s.def = p.state.hero.attribute.getFinalAttribute('def');
s.mdef = p.state.hero.attribute.getFinalAttribute('mdef');
s.money = p.state.hero.attribute.getFinalAttribute('money');
s.exp = p.state.hero.attribute.getFinalAttribute('exp');
s.lv = core.getLvName(
p.state.hero.attribute.getFinalAttribute('level')
);
};
const refreshAttribute = () => {
s.atk = p.state.hero.attribute.getFinalAttribute('atk');
s.hp = p.state.hero.attribute.getFinalAttribute('hp');
s.hpmax = p.state.hero.attribute.getFinalAttribute('hpmax');
s.mana = p.state.hero.attribute.getFinalAttribute('mana');
s.manamax = p.state.hero.attribute.getFinalAttribute('manamax');
s.def = p.state.hero.attribute.getFinalAttribute('def');
s.mdef = p.state.hero.attribute.getFinalAttribute('mdef');
s.money = p.state.hero.attribute.getFinalAttribute('money');
s.exp = p.state.hero.attribute.getFinalAttribute('exp');
s.lv = core.getLvName(
p.state.hero.attribute.getFinalAttribute('level')
);
};
const attributeHook = p.state.hero.attribute.addHook({
onUpdateAttribute: () => refreshAttribute()
});
const locationHook = p.state.hero.location.addHook({
onSetFloor: map => {
if (map) s.floor = core.status.floorId;
}
});
onUnmounted(() => {
attributeHook.unload();
locationHook.unload();
});
/** 常规字体 */
const font1 = Font.defaults({ size: 18 });
/** 加粗字体 */
const font2 = Font.defaults({ size: 18, weight: 700 });
/** 楼层名 */
const floorName = computed(() => core.floors[s.floor]?.title ?? '');
/** 钥匙显示文字 */
const key = (num: number) => {
return num.toString().padStart(2, '0');
};
//#region 属性显示
/** 一般属性 */
const statusInfo: StatusInfo[] = shallowReactive([]);
/** 钥匙属性 */
const keyLike: KeyLikeInfo[] = shallowReactive([]);
// 根据全塔属性配置显示属性
// 如果你想修改状态栏显示,不建议修改这里的内容,而建议直接新增标签
// 这里的内容是为使用样板默认状态栏的人准备的,对于新增属性来说过于复杂,而且功能有限,对于新手来说也难以理解
// 可以参考说明文档中的常见需求指南中的新增状态教程
const list = core.flags.statusBarItems;
// 等级
if (list.includes('enableLv')) {
statusInfo.push({
icon: lvIcon,
value: computed(() => s.lv),
font: font1,
color: '#fff'
});
const attributeHook = p.state.hero.attribute.addHook({
onUpdateAttribute: () => refreshAttribute()
});
const locationHook = p.state.hero.location.addHook({
onSetFloor: map => {
if (map) s.floor = core.status.floorId;
}
});
// 生命值
if (list.includes('enableHP')) {
if (list.includes('enableHPMax')) {
// 如果启用血限
statusInfo.push({
icon: hpIcon,
value: computed(() => {
const hp = core.formatBigNumber(s.hp);
const hpmax = core.formatBigNumber(s.hpmax);
return `${hp} / ${hpmax}`;
}),
font: font1,
color: '#fff'
});
} else {
// 如果禁用血限
statusInfo.push({
icon: hpIcon,
value: computed(() => core.formatBigNumber(s.hp)),
font: font1,
color: '#fff'
});
}
}
onUnmounted(() => {
attributeHook.unload();
locationHook.unload();
});
// 魔力
if (list.includes('enableMana')) {
/** 常规字体 */
const font1 = Font.defaults({ size: 18 });
/** 加粗字体 */
const font2 = Font.defaults({ size: 18, weight: 700 });
/** 楼层名 */
const floorName = computed(() => core.floors[s.floor]?.title ?? '');
/** 钥匙显示文字 */
const key = (num: number) => {
return num.toString().padStart(2, '0');
};
//#region 属性显示
/** 一般属性 */
const statusInfo: StatusInfo[] = shallowReactive([]);
/** 钥匙属性 */
const keyLike: KeyLikeInfo[] = shallowReactive([]);
// 根据全塔属性配置显示属性
// 如果你想修改状态栏显示,不建议修改这里的内容,而建议直接新增标签
// 这里的内容是为使用样板默认状态栏的人准备的,对于新增属性来说过于复杂,而且功能有限,对于新手来说也难以理解
// 可以参考说明文档中的常见需求指南中的新增状态教程
const list = core.flags.statusBarItems;
// 等级
if (list.includes('enableLv')) {
statusInfo.push({
icon: lvIcon,
value: computed(() => s.lv),
font: font1,
color: '#fff'
});
}
// 生命值
if (list.includes('enableHP')) {
if (list.includes('enableHPMax')) {
// 如果启用血限
statusInfo.push({
icon: manaIcon,
icon: hpIcon,
value: computed(() => {
const mana = core.formatBigNumber(s.mana);
const manamax = core.formatBigNumber(s.manamax);
if (s.manamax > 0) {
// 如果启用魔力上限
return `${mana} / ${manamax}`;
} else {
// 如果禁用魔力上限
return mana;
}
const hp = core.formatBigNumber(s.hp);
const hpmax = core.formatBigNumber(s.hpmax);
return `${hp} / ${hpmax}`;
}),
font: font1,
color: '#fff'
});
}
// 攻击力
if (list.includes('enableAtk')) {
} else {
// 如果禁用血限
statusInfo.push({
icon: atkIcon,
value: computed(() => core.formatBigNumber(s.atk)),
icon: hpIcon,
value: computed(() => core.formatBigNumber(s.hp)),
font: font1,
color: '#fff'
});
}
}
// 防御力
if (list.includes('enableDef')) {
statusInfo.push({
icon: defIcon,
value: computed(() => core.formatBigNumber(s.def)),
font: font1,
color: '#fff'
});
}
// 魔防(护盾)
if (list.includes('enableMdef')) {
statusInfo.push({
icon: mdefIcon,
value: computed(() => core.formatBigNumber(s.mdef)),
font: font1,
color: '#fff'
});
}
// 金币
if (list.includes('enableMoney')) {
statusInfo.push({
icon: moneyIcon,
value: computed(() => core.formatBigNumber(s.money)),
font: font1,
color: '#fff'
});
}
// 经验值
if (list.includes('enableExp')) {
if (list.includes('enableLevelUp')) {
// 升级模式
statusInfo.push({
icon: expIcon,
value: computed(() => core.formatBigNumber(s.up)),
font: font1,
color: '#fff'
});
} else {
// 非升级模式
statusInfo.push({
icon: expIcon,
value: computed(() => core.formatBigNumber(s.exp)),
font: font1,
color: '#fff'
});
}
}
// 钥匙
if (list.includes('enableKeys')) {
const keys: KeyLikeItem[] = [];
keyLike.push({ items: keys });
// 黄钥匙
keys.push({
value: computed(() => key(s.yellowKey)),
font: font2,
color: '#fca'
});
// 蓝钥匙
keys.push({
value: computed(() => key(s.blueKey)),
font: font2,
color: '#aad'
});
// 红钥匙
keys.push({
value: computed(() => key(s.redKey)),
font: font2,
color: '#f88'
});
// 绿钥匙
if (list.includes('enableGreenKey')) {
keys.push({
value: computed(() => key(s.greenKey)),
font: font2,
color: '#8f8'
});
}
}
// 破炸飞
if (list.includes('enablePZF')) {
const items: KeyLikeItem[] = [];
keyLike.push({ items });
items.push({
value: computed(() => `破 ${s.pickaxe}`),
font: font1,
color: '#bc6e27'
});
items.push({
value: computed(() => `炸 ${s.bomb}`),
font: font1,
color: '#fa14b9'
});
items.push({
value: computed(() => `飞 ${s.centerFly}`),
font: font1,
color: '#8db600'
});
}
// 毒衰咒
if (list.includes('enableDebuff')) {
const debuffs: KeyLikeItem[] = [];
keyLike.push({ items: debuffs });
debuffs.push({
value: computed(() => (s.poison ? '毒' : '')),
font: font1,
color: '#affca8'
});
debuffs.push({
value: computed(() => (s.weak ? '衰' : '')),
font: font1,
color: '#feccd0'
});
debuffs.push({
value: computed(() => (s.curse ? '咒' : '')),
font: font1,
color: '#c2f4e7'
});
}
//#region 布局控制
/** 用于显示状态的高度,高度=状态栏高度-工具栏高度-楼层名高度-填充高度 */
const statusHeight =
STATUS_BAR_HEIGHT - 113 - TITLE_HEIGHT - STATUS_PAD * 2;
/** 每一行的高度 */
const rowHeight = computed(() => {
const length = statusInfo.length + keyLike.length;
return statusHeight / length;
// 魔力
if (list.includes('enableMana')) {
statusInfo.push({
icon: manaIcon,
value: computed(() => {
const mana = core.formatBigNumber(s.mana);
const manamax = core.formatBigNumber(s.manamax);
if (s.manamax > 0) {
// 如果启用魔力上限
return `${mana} / ${manamax}`;
} else {
// 如果禁用魔力上限
return mana;
}
}),
font: font1,
color: '#fff'
});
/** 钥匙、破炸飞、毒衰咒开始显示的纵坐标 */
const keyStart = computed(() => {
const statusHeight = statusInfo.length * rowHeight.value;
return STATUS_Y + statusHeight;
}
// 攻击力
if (list.includes('enableAtk')) {
statusInfo.push({
icon: atkIcon,
value: computed(() => core.formatBigNumber(s.atk)),
font: font1,
color: '#fff'
});
}
/**
* 左右居中布局
* @param y 纵坐标
*/
const central = (y: number): ElementLocator => {
const width = p.loc[2] ?? 200;
return [width / 2, y, void 0, void 0, 0.5, 0.5];
};
// 防御力
if (list.includes('enableDef')) {
statusInfo.push({
icon: defIcon,
value: computed(() => core.formatBigNumber(s.def)),
font: font1,
color: '#fff'
});
}
/**
* 点击楼层名打开浏览地图
*/
const viewMap = () => {
openViewMap(mainUIController, [0, 0, MAIN_WIDTH, MAIN_HEIGHT]);
};
// 魔防(护盾)
if (list.includes('enableMdef')) {
statusInfo.push({
icon: mdefIcon,
value: computed(() => core.formatBigNumber(s.mdef)),
font: font1,
color: '#fff'
});
}
return () => (
<container loc={p.loc} hidden={p.hidden}>
<text
text={floorName.value}
loc={central(18)}
font={font1}
cursor="pointer"
onClick={viewMap}
></text>
<g-line
lineWidth={1}
strokeStyle="#888"
line={[0, TITLE_HEIGHT, STATUS_BAR_WIDTH, TITLE_HEIGHT]}
/>
{statusInfo
.map((v, i) => {
const h = rowHeight.value;
const y = STATUS_Y + i * h;
const cy = y + h / 2;
const iconSize = Math.min(32, h * 0.8);
const pad = (h - iconSize) / 2;
return [
<image
loc={[STATUS_PAD, y + pad, iconSize, iconSize]}
image={v.icon}
noanti // 取消抗锯齿
/>,
// 金币
if (list.includes('enableMoney')) {
statusInfo.push({
icon: moneyIcon,
value: computed(() => core.formatBigNumber(s.money)),
font: font1,
color: '#fff'
});
}
// 经验值
if (list.includes('enableExp')) {
if (list.includes('enableLevelUp')) {
// 升级模式
statusInfo.push({
icon: expIcon,
value: computed(() => core.formatBigNumber(s.up)),
font: font1,
color: '#fff'
});
} else {
// 非升级模式
statusInfo.push({
icon: expIcon,
value: computed(() => core.formatBigNumber(s.exp)),
font: font1,
color: '#fff'
});
}
}
// 钥匙
if (list.includes('enableKeys')) {
const keys: KeyLikeItem[] = [];
keyLike.push({ items: keys });
// 黄钥匙
keys.push({
value: computed(() => key(s.yellowKey)),
font: font2,
color: '#fca'
});
// 蓝钥匙
keys.push({
value: computed(() => key(s.blueKey)),
font: font2,
color: '#aad'
});
// 红钥匙
keys.push({
value: computed(() => key(s.redKey)),
font: font2,
color: '#f88'
});
// 绿钥匙
if (list.includes('enableGreenKey')) {
keys.push({
value: computed(() => key(s.greenKey)),
font: font2,
color: '#8f8'
});
}
}
// 破炸飞
if (list.includes('enablePZF')) {
const items: KeyLikeItem[] = [];
keyLike.push({ items });
items.push({
value: computed(() => `破 ${s.pickaxe}`),
font: font1,
color: '#bc6e27'
});
items.push({
value: computed(() => `炸 ${s.bomb}`),
font: font1,
color: '#fa14b9'
});
items.push({
value: computed(() => `飞 ${s.centerFly}`),
font: font1,
color: '#8db600'
});
}
// 毒衰咒
if (list.includes('enableDebuff')) {
const debuffs: KeyLikeItem[] = [];
keyLike.push({ items: debuffs });
debuffs.push({
value: computed(() => (s.poison ? '毒' : '')),
font: font1,
color: '#affca8'
});
debuffs.push({
value: computed(() => (s.weak ? '衰' : '')),
font: font1,
color: '#feccd0'
});
debuffs.push({
value: computed(() => (s.curse ? '咒' : '')),
font: font1,
color: '#c2f4e7'
});
}
//#region 布局控制
/** 用于显示状态的高度,高度=状态栏高度-工具栏高度-楼层名高度-填充高度 */
const statusHeight =
STATUS_BAR_HEIGHT - 113 - TITLE_HEIGHT - STATUS_PAD * 2;
/** 每一行的高度 */
const rowHeight = computed(() => {
const length = statusInfo.length + keyLike.length;
return statusHeight / length;
});
/** 钥匙、破炸飞、毒衰咒开始显示的纵坐标 */
const keyStart = computed(() => {
const statusHeight = statusInfo.length * rowHeight.value;
return STATUS_Y + statusHeight;
});
/**
* 左右居中布局
* @param y 纵坐标
*/
const central = (y: number): ElementLocator => {
const width = p.loc[2] ?? 200;
return [width / 2, y, void 0, void 0, 0.5, 0.5];
};
/**
* 点击楼层名打开浏览地图
*/
const viewMap = () => {
openViewMap(mainUIController, [0, 0, MAIN_WIDTH, MAIN_HEIGHT]);
};
return () => (
<container loc={p.loc} hidden={p.hidden}>
<text
text={floorName.value}
loc={central(18)}
font={font1}
cursor="pointer"
onClick={viewMap}
></text>
<g-line
lineWidth={1}
strokeStyle="#888"
line={[0, TITLE_HEIGHT, STATUS_BAR_WIDTH, TITLE_HEIGHT]}
/>
{statusInfo
.map((v, i) => {
const h = rowHeight.value;
const y = STATUS_Y + i * h;
const cy = y + h / 2;
const iconSize = Math.min(32, h * 0.8);
const pad = (h - iconSize) / 2;
return [
<image
loc={[STATUS_PAD, y + pad, iconSize, iconSize]}
image={v.icon}
noanti // 取消抗锯齿
/>,
<text
loc={[TEXT_X, cy]}
anc={[0, 0.5]}
text={v.value.value}
fillStyle={v.color}
font={v.font}
/>
];
})
.flat()}
{keyLike
.map(({ items }, i) => {
const h = rowHeight.value;
const y = keyStart.value + i * h;
const cy = y + h / 2;
const rw = STATUS_BAR_WIDTH / (items.length + 1);
return items.map((v, i) => {
const x = rw * (i + 1);
return (
<text
loc={[TEXT_X, cy]}
anc={[0, 0.5]}
loc={[x, cy]}
anc={[0.5, 0.5]}
text={v.value.value}
fillStyle={v.color}
font={v.font}
fillStyle={v.color}
/>
];
})
.flat()}
{keyLike
.map(({ items }, i) => {
const h = rowHeight.value;
const y = keyStart.value + i * h;
const cy = y + h / 2;
const rw = STATUS_BAR_WIDTH / (items.length + 1);
return items.map((v, i) => {
const x = rw * (i + 1);
return (
<text
loc={[x, cy]}
anc={[0.5, 0.5]}
text={v.value.value}
font={v.font}
fillStyle={v.color}
/>
);
});
})
.flat()}
<g-line
lineWidth={1}
strokeStyle="#888"
line={[
0,
MAIN_HEIGHT - 113,
STATUS_BAR_WIDTH,
MAIN_HEIGHT - 113
]}
);
});
})
.flat()}
<g-line
lineWidth={1}
strokeStyle="#888"
line={[
0,
MAIN_HEIGHT - 113,
STATUS_BAR_WIDTH,
MAIN_HEIGHT - 113
]}
/>
<MixedToolbar
loc={[0, MAIN_HEIGHT - 113, STATUS_BAR_WIDTH, 113]}
status={s.replay}
state={p.state}
/>
</container>
);
}, statusBarProps);
export const RightStatusBar = defineComponent<StatusBarProps>(p => {
// p.status 就是你在 main.tsx 中传入的属性内容,用法与左侧状态栏完全一致
// TODO: flags 更新未接(当前无监听系统)
const rightStatus: IRightHeroStatus = reactive({ exampleHard: 0 });
const text = `这里是右侧状态栏,如果左侧状态栏不够用可以在 \\r[gold]statusBar.tsx\\r 中编写内容,如果不需要此状态栏,可以在 \\r[gold]shared.ts\\r 中关闭此状态栏。`;
return () => {
return (
<container loc={p.loc} hidden={p.hidden}>
<TextContent
loc={[8, 8]}
text={text}
width={STATUS_BAR_WIDTH - 16}
autoHeight
lineHeight={8}
/>
<MixedToolbar
loc={[0, MAIN_HEIGHT - 113, STATUS_BAR_WIDTH, 113]}
status={s.replay}
state={p.state}
<text loc={[8, 270]} text="示例内容" />
<text
loc={[8, 300]}
text={`游戏难度:${rightStatus.exampleHard}`}
/>
</container>
);
},
statusBarProps
);
export const RightStatusBar = defineComponent<StatusBarProps>(
p => {
// p.status 就是你在 main.tsx 中传入的属性内容,用法与左侧状态栏完全一致
// TODO: flags 更新未接(当前无监听系统)
const rightStatus: IRightHeroStatus = reactive({ exampleHard: 0 });
const text = `这里是右侧状态栏,如果左侧状态栏不够用可以在 \\r[gold]statusBar.tsx\\r 中编写内容,如果不需要此状态栏,可以在 \\r[gold]shared.ts\\r 中关闭此状态栏。`;
return () => {
return (
<container loc={p.loc} hidden={p.hidden}>
<TextContent
loc={[8, 8]}
text={text}
width={STATUS_BAR_WIDTH - 16}
autoHeight
lineHeight={8}
/>
<text loc={[8, 270]} text="示例内容" />
<text
loc={[8, 300]}
text={`游戏难度:${rightStatus.exampleHard}`}
/>
</container>
);
};
},
statusBarProps
);
};
}, statusBarProps);
export const leftStatusBarUI = new GameUI('left-status-bar', LeftStatusBar);
export const rightStatusBarUI = new GameUI('right-status-bar', RightStatusBar);

View File

@ -16,7 +16,7 @@ import { gameKey, generateKeyboardEvent } from '@motajs/system';
import { transitioned } from '../render/use';
import { linear } from 'mutate-animate';
import { KeyCode } from '@motajs/client-base';
import { Progress } from '@user/client-base';
import { IClientBaseExtended, Progress } from '@user/client-base';
import { generateBinary } from '@motajs/legacy-common';
import { SetupComponentOptions } from '@motajs/system';
import { saveSave, saveLoad } from './save';
@ -25,9 +25,8 @@ import { MAIN_HEIGHT, FULL_LOC, POP_BOX_WIDTH, CENTER_LOC } from '../shared';
import { openReplay, openSettings } from './settings';
import { openViewMap } from './viewmap';
import { DefaultProps } from '@motajs/render-vue';
import { IUIPropsBase } from './types';
interface ToolbarProps extends DefaultProps, IUIPropsBase {
interface ToolbarProps extends DefaultProps, IClientBaseExtended {
loc?: ElementLocator;
}