mirror of
https://github.com/motajs/template.git
synced 2026-10-16 10:30:18 +08:00
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:
parent
3a49b37c25
commit
8cfbc7333e
@ -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';
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user