fix: 更新策略 & 文本框显示问题

This commit is contained in:
unanmed 2025-02-25 21:33:10 +08:00
parent df993a7242
commit bca679d4b1
10 changed files with 290 additions and 186 deletions

View File

@ -1117,7 +1117,7 @@ actions.prototype._clickAction_text = function () {
// 正在淡入淡出的话不执行 // 正在淡入淡出的话不执行
if (core.status.event.animateUI) return; if (core.status.event.animateUI) return;
const Store = Mota.require('module', 'Render').TextboxStore; const Store = Mota.require('module', 'MainUI').TextboxStore;
const store = Store.get('main-textbox'); const store = Store.get('main-textbox');
// var data = core.clone(core.status.event.data.current); // var data = core.clone(core.status.event.data.current);

View File

@ -1553,7 +1553,7 @@ events.prototype.__action_doAsyncFunc = function (isAsync, func) {
events.prototype._action_text = function (data, x, y, prefix) { events.prototype._action_text = function (data, x, y, prefix) {
if (this.__action_checkReplaying()) return; if (this.__action_checkReplaying()) return;
const Store = Mota.require('module', 'Render').TextboxStore; const Store = Mota.require('module', 'MainUI').TextboxStore;
const store = Store.get('main-textbox'); const store = Store.get('main-textbox');
const { text } = data; const { text } = data;
let title = ''; let title = '';
@ -1594,10 +1594,10 @@ events.prototype._action_text = function (data, x, y, prefix) {
} }
} }
const showTitle = const showText = text.slice(0, titleStartIndex) + text.slice(titleEndIndex);
text.slice(0, titleStartIndex) + text.slice(titleEndIndex);
store.show(); store.show();
store.modify({ text: showTitle, title }); store.modify({ title });
store.setText(showText);
// data.text = core.replaceText(data.text, prefix); // data.text = core.replaceText(data.text, prefix);
// var ctx = data.code ? '__text__' + data.code : null; // var ctx = data.code ? '__text__' + data.code : null;

View File

@ -13,7 +13,7 @@ function checkSupport() {
sleep(3000).then(() => { sleep(3000).then(() => {
tip( tip(
'warning', 'warning',
`您的浏览器不支持WebGL大部分特效将会无法显示,建议使用新版浏览器` `您的浏览器不支持WebGL大部分效果将会无法显示,请更新你的浏览器`
); );
}); });
} }
@ -21,7 +21,7 @@ function checkSupport() {
sleep(3000).then(() => { sleep(3000).then(() => {
tip( tip(
'warning', 'warning',
`您的浏览器不支持WebGL2一部分特效将会无法显示,建议使用新版浏览器` `您的浏览器不支持WebGL2大部分效果将会无法显示,请更新你的浏览器`
); );
}); });
} }

View File

@ -80,9 +80,9 @@ export class Container<E extends EContainerEvent = EContainerEvent>
append(parent: RenderItem): void { append(parent: RenderItem): void {
super.append(parent); super.append(parent);
if (this.root) { if (this.root) {
const root = this.root;
this.forEachChild(ele => { this.forEachChild(ele => {
ele.checkRoot(); ele.setRoot(root);
this.root?.connect(ele);
}); });
} }
} }
@ -104,6 +104,7 @@ export class Container<E extends EContainerEvent = EContainerEvent>
this.sortedChildren = [...this.children].sort( this.sortedChildren = [...this.children].sort(
(a, b) => a.zIndex - b.zIndex (a, b) => a.zIndex - b.zIndex
); );
this.update();
} }
protected propagateEvent<T extends ActionType>( protected propagateEvent<T extends ActionType>(

View File

@ -437,6 +437,15 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
return canvas; return canvas;
} }
/**
* `requireCanvas` 使
* @param canvas
*/
protected deleteCanvas(canvas: MotaOffscreenCanvas2D) {
if (!this.canvases.delete(canvas)) return;
canvas.delete();
}
//#region 修改元素属性 //#region 修改元素属性
/** /**
@ -457,8 +466,8 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
* @param y * @param y
*/ */
pos(x: number, y: number) { pos(x: number, y: number) {
// 这个函数会调用 update因此不再手动调用 update
this._transform.setTranslate(x, y); this._transform.setTranslate(x, y);
this.update();
} }
/** /**
@ -588,10 +597,15 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
} }
update(item: RenderItem<any> = this): void { update(item: RenderItem<any> = this): void {
if (this.cacheDirty) return; if (this._parent) {
if (this.cacheDirty && this._parent.cacheDirty) return;
this.cacheDirty = true; this.cacheDirty = true;
if (this.hidden) return; if (this.hidden) return;
this.parent?.update(item); this._parent.update(item);
} else {
if (this.cacheDirty) return;
this.cacheDirty = true;
}
} }
updateTransform() { updateTransform() {
@ -650,6 +664,12 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
//#region 父子关系 //#region 父子关系
setRoot(item: RenderItem & IRenderTreeRoot) {
this._root?.disconnect(this);
this._root = item;
item.connect(item);
}
checkRoot(): RenderItem | null { checkRoot(): RenderItem | null {
if (this._root) return this._root; if (this._root) return this._root;
if (this.isRoot) return this; if (this.isRoot) return this;

View File

@ -30,7 +30,10 @@ export class Text extends RenderItem<ETextEvent> {
super(type, false); super(type, false);
this.text = text; this.text = text;
if (text.length > 0) this.calBox(); if (text.length > 0) {
this.calBox();
this.emit('setText', text);
}
} }
protected render( protected render(
@ -70,7 +73,7 @@ export class Text extends RenderItem<ETextEvent> {
setText(text: string) { setText(text: string) {
this.text = text; this.text = text;
this.calBox(); this.calBox();
if (this.parent) this.update(this); this.update(this);
this.emit('setText', text); this.emit('setText', text);
} }
@ -81,7 +84,7 @@ export class Text extends RenderItem<ETextEvent> {
setFont(font: string) { setFont(font: string) {
this.font = font; this.font = font;
this.calBox(); this.calBox();
if (this.parent) this.update(this); this.update(this);
} }
/** /**
@ -410,8 +413,7 @@ export class Winskin extends RenderItem<EWinskinEvent> {
Winskin.patternMap.set(this.imageName, winskinPattern); Winskin.patternMap.set(this.imageName, winskinPattern);
} }
this.patternCache = winskinPattern; this.patternCache = winskinPattern;
pattern.delete(); this.deleteCanvas(pattern);
this.canvases.delete(pattern);
return winskinPattern; return winskinPattern;
} }

View File

@ -2,8 +2,8 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
import { import {
computed, computed,
defineComponent, defineComponent,
nextTick,
onUnmounted, onUnmounted,
onUpdated,
ref, ref,
shallowReactive, shallowReactive,
shallowRef, shallowRef,
@ -13,7 +13,7 @@ import {
} from 'vue'; } from 'vue';
import { logger } from '@/core/common/logger'; import { logger } from '@/core/common/logger';
import { Sprite } from '@/core/render/sprite'; import { Sprite } from '@/core/render/sprite';
import { ContainerProps, DefaultProps } from '@/core/render/renderer'; import { DefaultProps } from '@/core/render/renderer';
import { isNil } from 'lodash-es'; import { isNil } from 'lodash-es';
import { SetupComponentOptions } from './types'; import { SetupComponentOptions } from './types';
import EventEmitter from 'eventemitter3'; import EventEmitter from 'eventemitter3';
@ -22,7 +22,9 @@ import {
ITextContentConfig, ITextContentConfig,
TextContentTyper, TextContentTyper,
TyperRenderable, TyperRenderable,
TextContentType TextContentType,
WordBreak,
TextAlign
} from './textboxTyper'; } from './textboxTyper';
export interface TextContentProps export interface TextContentProps
@ -34,8 +36,6 @@ export interface TextContentProps
fill?: boolean; fill?: boolean;
/** 是否描边 */ /** 是否描边 */
stroke?: boolean; stroke?: boolean;
/** 是否忽略打字机,直接显伤全部 */
showAll?: boolean;
} }
export type TextContentEmits = { export type TextContentEmits = {
@ -43,6 +43,18 @@ export type TextContentEmits = {
typeStart: () => void; typeStart: () => void;
}; };
export interface TextContentExpose {
/**
*
*/
retype(): void;
/**
*
*/
showAll(): void;
}
const textContentOptions = { const textContentOptions = {
props: [ props: [
'breakChars', 'breakChars',
@ -50,7 +62,6 @@ const textContentOptions = {
'fontSize', 'fontSize',
'fontWeight', 'fontWeight',
'fontItalic', 'fontItalic',
'height',
'ignoreLineEnd', 'ignoreLineEnd',
'ignoreLineStart', 'ignoreLineStart',
'interval', 'interval',
@ -58,17 +69,14 @@ const textContentOptions = {
'lineHeight', 'lineHeight',
'text', 'text',
'textAlign', 'textAlign',
'width',
'wordBreak', 'wordBreak',
'x',
'y',
'fill', 'fill',
'fillStyle', 'fillStyle',
'strokeStyle', 'strokeStyle',
'strokeWidth', 'strokeWidth',
'stroke', 'stroke',
'showAll', 'loc',
'loc' 'width'
], ],
emits: ['typeEnd', 'typeStart'] emits: ['typeEnd', 'typeStart']
} satisfies SetupComponentOptions< } satisfies SetupComponentOptions<
@ -81,45 +89,42 @@ export const TextContent = defineComponent<
TextContentProps, TextContentProps,
TextContentEmits, TextContentEmits,
keyof TextContentEmits keyof TextContentEmits
>((props, { emit }) => { >((props, { emit, expose }) => {
if (props.width && props.width <= 0) { const width = computed(() => props.width ?? props.loc?.[2] ?? 200);
if (width.value < 0) {
logger.warn(41, String(props.width)); logger.warn(41, String(props.width));
} }
const typer = new TextContentTyper(props); const typer = new TextContentTyper(props);
let renderable: TyperRenderable[] = []; let renderable: TyperRenderable[] = [];
let needUpdate = false; let needUpdate = false;
let nowText = '';
watch(props, value => {
typer.setConfig(value);
});
const retype = () => { const retype = () => {
if (props.showAll) {
typer.typeAll();
}
if (props.text === nowText) return;
if (needUpdate) return; if (needUpdate) return;
needUpdate = true; needUpdate = true;
if (!spriteElement.value) { if (!spriteElement.value) {
needUpdate = false; needUpdate = false;
} }
nowText = props.text ?? '';
renderable = []; renderable = [];
spriteElement.value?.requestBeforeFrame(() => { spriteElement.value?.requestBeforeFrame(() => {
typer.setConfig(props); typer.setConfig(props);
typer.setText(props.text ?? ''); typer.setText(props.text ?? '');
typer.type(); typer.type();
if (props.showAll) {
typer.typeAll();
}
needUpdate = false; needUpdate = false;
}); });
}; };
onUpdated(retype); const showAll = () => {
typer.typeAll();
};
watch(props, value => {
typer.setConfig(value);
retype();
});
expose({ retype, showAll });
const spriteElement = shallowRef<Sprite>(); const spriteElement = shallowRef<Sprite>();
const renderContent = (canvas: MotaOffscreenCanvas2D) => { const renderContent = (canvas: MotaOffscreenCanvas2D) => {
@ -164,19 +169,15 @@ export const TextContent = defineComponent<
return () => { return () => {
return ( return (
<sprite <sprite
{...props} loc={props.loc}
ref={spriteElement} ref={spriteElement}
x={props.x}
y={props.y}
width={props.width}
height={props.height}
render={renderContent} render={renderContent}
></sprite> ></sprite>
); );
}; };
}, textContentOptions); }, textContentOptions);
export interface TextboxProps extends TextContentProps, ContainerProps { export interface TextboxProps extends TextContentProps, DefaultProps {
/** 背景颜色 */ /** 背景颜色 */
backColor?: CanvasStyle; backColor?: CanvasStyle;
/** 背景 winskin */ /** 背景 winskin */
@ -195,6 +196,28 @@ export interface TextboxProps extends TextContentProps, ContainerProps {
titlePadding?: number; titlePadding?: number;
} }
export interface TextboxExpose {
/**
*
*/
show(): void;
/**
*
*/
hide(): void;
/**
*
*/
retype(): void;
/**
*
*/
showAll(): void;
}
type TextboxEmits = TextContentEmits; type TextboxEmits = TextContentEmits;
type TextboxSlots = SlotsType<{ type TextboxSlots = SlotsType<{
default: (data: TextboxProps) => VNode[]; default: (data: TextboxProps) => VNode[];
@ -205,23 +228,14 @@ const textboxOptions = {
props: (textContentOptions.props as (keyof TextboxProps)[]).concat([ props: (textContentOptions.props as (keyof TextboxProps)[]).concat([
'backColor', 'backColor',
'winskin', 'winskin',
'id',
'padding', 'padding',
'alpha',
'hidden',
'anchorX',
'anchorY',
'anti',
'cache',
'composite',
'fall',
'hd',
'transform',
'type',
'zIndex',
'titleFill', 'titleFill',
'titleStroke', 'titleStroke',
'titleFont' 'titleFont',
'titlePadding',
'id',
'hidden',
'title'
]), ]),
emits: textContentOptions.emits emits: textContentOptions.emits
} satisfies SetupComponentOptions<TextboxProps, {}, string, TextboxSlots>; } satisfies SetupComponentOptions<TextboxProps, {}, string, TextboxSlots>;
@ -236,153 +250,206 @@ export const Textbox = defineComponent<
TextboxEmits, TextboxEmits,
keyof TextboxEmits, keyof TextboxEmits,
TextboxSlots TextboxSlots
>((props, { slots }) => { >((props, { slots, expose }) => {
const data = shallowReactive({ ...props }); const contentData = shallowReactive<TextContentProps>({});
data.padding ??= 8; const data = shallowReactive<TextboxProps>({});
data.width ??= 200;
data.height ??= 200; const setContentData = () => {
data.id ??= ''; contentData.breakChars = props.breakChars ?? '';
data.alpha ??= 1; contentData.fontFamily = props.fontFamily ?? 'Verdana';
data.titleFill ??= '#000'; contentData.fontSize = props.fontSize ?? 16;
data.titleStroke ??= 'transparent'; contentData.fontWeight = props.fontWeight ?? 500;
data.titleFont ??= '16px Verdana'; contentData.fontItalic = props.fontItalic ?? false;
data.titlePadding ??= 4; contentData.ignoreLineEnd = props.ignoreLineEnd ?? '';
contentData.ignoreLineStart = props.ignoreLineStart ?? '';
contentData.interval = props.interval ?? 0;
contentData.keepLast = props.keepLast ?? false;
contentData.lineHeight = props.lineHeight ?? 0;
contentData.text = props.text ?? '';
contentData.textAlign = props.textAlign ?? TextAlign.Left;
contentData.wordBreak = props.wordBreak ?? WordBreak.Space;
contentData.fill = props.fill ?? true;
contentData.stroke = props.stroke ?? false;
contentData.fillStyle = props.fillStyle ?? '#fff';
contentData.strokeStyle = props.strokeStyle ?? '#000';
contentData.strokeWidth = props.strokeWidth ?? 2;
contentData.loc = props.loc;
contentData.width = props.width;
};
const setTextboxData = () => {
data.backColor = props.backColor ?? '#222';
data.winskin = props.winskin;
data.padding = props.padding ?? 8;
data.titleFill = props.titleFill ?? 'gold';
data.titleStroke = props.titleStroke ?? 'transparent';
data.titleFont = props.titleFont ?? '18px Verdana';
data.titlePadding = props.titlePadding ?? 8;
data.width = props.width ?? props.loc?.[2] ?? 200;
data.height = props.height ?? props.loc?.[3] ?? 200;
data.title = props.title ?? '';
};
setContentData();
setTextboxData();
watch(props, () => {
const needUpdateTitle = data.title !== props.title;
setTextboxData();
if (needUpdateTitle) {
onSetText();
}
});
const titleElement = ref<Text>(); const titleElement = ref<Text>();
const titleWidth = ref(data.titlePadding * 2); const content = ref<TextContentExpose>();
const titleHeight = ref(data.titlePadding * 2); const hidden = ref(props.hidden);
/** 标题宽度 */
const tw = ref(data.titlePadding! * 2);
/** 标题高度 */
const th = ref(data.titlePadding! * 2);
const contentY = computed(() => { const contentY = computed(() => {
const height = titleHeight.value; const height = th.value;
return data.title ? height : 0; return data.title ? height : 0;
}); });
const backHeight = computed(() => data.height! - contentY.value);
const contentWidth = computed(() => data.width! - data.padding! * 2); const contentWidth = computed(() => data.width! - data.padding! * 2);
const contentHeight = computed( const contentHeight = computed(
() => data.height! - data.padding! * 2 - contentY.value () => data.height! - data.padding! * 2 - contentY.value
); );
const calTitleSize = (text: string) => { const onSetText = () => {
if (!titleElement.value) return; nextTick(() => {
titleElement.value?.requestBeforeFrame(() => {
if (titleElement.value) {
const { width, height } = titleElement.value; const { width, height } = titleElement.value;
titleWidth.value = width + data.titlePadding! * 2; tw.value = width + data.padding! * 2;
titleHeight.value = height + data.titlePadding! * 2; th.value = height + data.padding! * 2;
data.title = text; }
});
});
}; };
watch(titleElement, (value, old) => {
old?.off('setText', calTitleSize);
value?.on('setText', calTitleSize);
if (value) calTitleSize(value?.text);
});
onUnmounted(() => {
titleElement.value?.off('setText', calTitleSize);
});
// ----- store // ----- store
/** 结束打字机 */ /** 结束打字机 */
const storeEmits: TextboxStoreEmits = { const storeEmits: TextboxStoreEmits = {
endType() { endType() {
data.showAll = true; content.value?.showAll();
},
hide() {
hidden.value = true;
},
show() {
hidden.value = false;
},
update(value) {
if (data.title !== value.title) {
data.title = value.title;
onSetText();
}
},
setText(text) {
if (contentData.text === text) {
content.value?.retype();
} else {
contentData.text = text;
}
} }
}; };
const store = TextboxStore.use( const store = TextboxStore.use(
props.id ?? getNextTextboxId(), props.id ?? getNextTextboxId(),
data, contentData,
storeEmits storeEmits
); );
const hidden = ref(data.hidden);
store.on('hide', () => (hidden.value = true));
store.on('show', () => (hidden.value = false));
store.on('update', value => {
if (value.title) {
titleElement.value?.requestBeforeFrame(() => {
const { width, height } = titleElement.value!;
titleWidth.value = width + data.padding! * 2;
titleHeight.value = height + data.padding! * 2;
});
}
});
const onTypeStart = () => { const onTypeStart = () => {
store.emitTypeStart(); store.emitTypeStart();
}; };
const onTypeEnd = () => { const onTypeEnd = () => {
data.showAll = false;
store.emitTypeEnd(); store.emitTypeEnd();
}; };
return () => { expose<TextboxExpose>({
return ( show() {
<container {...data} hidden={hidden.value} alpha={data.alpha}> hidden.value = false;
{data.title ? ( },
hide() {
hidden.value = true;
},
retype() {
content.value?.retype();
},
showAll() {
content.value?.showAll();
}
});
return () => (
<container <container
zIndex={10} id={props.id}
width={titleWidth.value} hidden={hidden.value}
height={titleHeight.value} alpha={data.alpha}
loc={props.loc}
> >
{data.title && (
<container zIndex={10} loc={[0, 0, tw.value, th.value]}>
{slots.title ? ( {slots.title ? (
slots.title(data) slots.title(data)
) : props.winskin ? ( ) : props.winskin ? (
<winskin image={props.winskin}></winskin> <winskin
image={props.winskin}
loc={[0, 0, tw.value, th.value]}
></winskin>
) : ( ) : (
<g-rect <g-rect loc={[0, 0, tw.value, th.value]}></g-rect>
x={0}
y={0}
width={titleWidth.value}
height={titleHeight.value}
fillStyle={data.backColor}
></g-rect>
)} )}
<text <text
ref={titleElement} ref={titleElement}
text={data.title} text={data.title}
x={data.titlePadding} loc={[data.titlePadding, data.titlePadding]}
y={data.titlePadding}
fillStyle={data.titleFill} fillStyle={data.titleFill}
strokeStyle={data.titleStroke} strokeStyle={data.titleStroke}
font={data.titleFont} font={data.titleFont}
></text> ></text>
</container> </container>
) : (
''
)} )}
{slots.default ? ( {slots.default ? (
slots.default(data) slots.default(data)
) : props.winskin ? ( ) : props.winskin ? (
<winskin image={props.winskin}></winskin> <winskin
image={props.winskin}
loc={[0, contentY.value, data.width!, backHeight.value]}
></winskin>
) : ( ) : (
<g-rect <g-rect
x={0} loc={[0, contentY.value, data.width!, backHeight.value]}
y={contentY.value}
width={data.width ?? 200}
height={(data.height ?? 200) - contentY.value}
fill fill
fillStyle={data.backColor} fillStyle={data.backColor}
></g-rect> ></g-rect>
)} )}
<TextContent <TextContent
{...data} {...contentData}
id="" ref={content}
hidden={false}
x={data.padding!} x={data.padding!}
y={contentY.value + data.padding!} y={contentY.value + data.padding!}
width={contentWidth.value} width={contentWidth.value}
height={contentHeight.value} height={contentHeight.value}
onTypeEnd={onTypeEnd} onTypeEnd={onTypeEnd}
onTypeStart={onTypeStart} onTypeStart={onTypeStart}
zIndex={0}
showAll={data.showAll}
></TextContent> ></TextContent>
</container> </container>
); );
};
}, textboxOptions); }, textboxOptions);
interface TextboxStoreEmits { interface TextboxStoreEmits {
endType: () => void; endType: () => void;
hide: () => void;
show: () => void;
update: (value: TextboxProps) => void;
setText: (text: string) => void;
} }
interface TextboxStoreEvent { interface TextboxStoreEvent {
@ -436,21 +503,30 @@ export class TextboxStore extends EventEmitter<TextboxStoreEvent> {
// @ts-expect-error 无法推导 // @ts-expect-error 无法推导
if (!isNil(value)) this.data[key] = value; if (!isNil(value)) this.data[key] = value;
} }
this.emits.update(this.data);
this.emit('update', this.data); this.emit('update', this.data);
} }
/**
*
* @param text
*/
setText(text: string) {
this.emits.setText(text);
}
/** /**
* *
*/ */
show() { show() {
this.emit('show'); this.emits.show();
} }
/** /**
* *
*/ */
hide() { hide() {
this.emit('hide'); this.emits.hide();
} }
/** /**

View File

@ -422,6 +422,7 @@ export class TextContentTyper extends EventEmitter<TextContentTyperEvent> {
* *
*/ */
type() { type() {
if (this.typing) return;
if (this.config.interval === 0) { if (this.config.interval === 0) {
this.emit('typeStart'); this.emit('typeStart');
this.typeChars(Infinity); this.typeChars(Infinity);
@ -438,6 +439,7 @@ export class TextContentTyper extends EventEmitter<TextContentTyperEvent> {
* *
*/ */
typeAll() { typeAll() {
if (!this.typing) return;
this.typeChars(Infinity); this.typeChars(Infinity);
this.render?.(this.renderData, false); this.render?.(this.renderData, false);
} }

View File

@ -4,6 +4,7 @@ import { defineComponent } from 'vue';
import { UIController } from '@/core/system'; import { UIController } from '@/core/system';
import { mainSceneUI } from './ui/main'; import { mainSceneUI } from './ui/main';
import { MAIN_HEIGHT, MAIN_WIDTH } from './shared'; import { MAIN_HEIGHT, MAIN_WIDTH } from './shared';
import { TextboxStore } from './components';
export function create() { export function create() {
const main = new MotaRenderer(); const main = new MotaRenderer();
@ -34,6 +35,10 @@ export function create() {
console.log(main); console.log(main);
} }
Mota.register('module', 'MainUI', {
TextboxStore
});
export * from './components'; export * from './components';
export * from './ui'; export * from './ui';
export * from './use'; export * from './use';

View File

@ -57,9 +57,7 @@ const MainScene = defineComponent(() => {
const mainTextboxProps: Props<typeof Textbox> = { const mainTextboxProps: Props<typeof Textbox> = {
text: '', text: '',
hidden: true, hidden: true,
width: 480, loc: [0, 330, 480, 150],
height: 150,
y: 330,
zIndex: 30, zIndex: 30,
fillStyle: '#fff', fillStyle: '#fff',
titleFill: 'gold', titleFill: 'gold',
@ -67,7 +65,7 @@ const MainScene = defineComponent(() => {
titleFont: '700 20px normal', titleFont: '700 20px normal',
winskin: 'winskin2.png', winskin: 'winskin2.png',
interval: 100, interval: 100,
lineHeight: 6 lineHeight: 4
}; };
const map = ref<LayerGroup>(); const map = ref<LayerGroup>();