mirror of
				https://github.com/unanmed/HumanBreak.git
				synced 2025-11-04 07:02:58 +08:00 
			
		
		
		
	refactor: drawTip
This commit is contained in:
		
							parent
							
								
									d0dae40a5a
								
							
						
					
					
						commit
						d2b7a5d430
					
				@ -944,60 +944,11 @@ ui.prototype.clearUI = function () {
 | 
			
		||||
 | 
			
		||||
////// 左上角绘制一段提示 //////
 | 
			
		||||
ui.prototype.drawTip = function (text, id, frame) {
 | 
			
		||||
    text = core.replaceText(text) || '';
 | 
			
		||||
    var realText = this._getRealContent(text);
 | 
			
		||||
    var one = {
 | 
			
		||||
        text: text,
 | 
			
		||||
        textX: 21,
 | 
			
		||||
        width: 26 + core.calWidth('data', realText, '16px Arial'),
 | 
			
		||||
        opacity: 0.1,
 | 
			
		||||
        stage: 1,
 | 
			
		||||
        frame: frame || 0,
 | 
			
		||||
        time: 0
 | 
			
		||||
    };
 | 
			
		||||
    if (id != null) {
 | 
			
		||||
        var info = core.getBlockInfo(id);
 | 
			
		||||
        if (info == null || !info.image || info.bigImage) {
 | 
			
		||||
            // 检查状态栏图标
 | 
			
		||||
            if (core.statusBar.icons[id] instanceof Image) {
 | 
			
		||||
                info = {
 | 
			
		||||
                    image: core.statusBar.icons[id],
 | 
			
		||||
                    posX: 0,
 | 
			
		||||
                    posY: 0,
 | 
			
		||||
                    height: 32
 | 
			
		||||
                };
 | 
			
		||||
            } else info = null;
 | 
			
		||||
        }
 | 
			
		||||
        if (info != null) {
 | 
			
		||||
            one.image = info.image;
 | 
			
		||||
            one.posX = info.posX;
 | 
			
		||||
            one.posY = info.posY;
 | 
			
		||||
            one.height = info.height;
 | 
			
		||||
            one.textX += 24;
 | 
			
		||||
            one.width += 24;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    core.animateFrame.tip = one;
 | 
			
		||||
    // Deprecated. Fallback in modules/fallback/ui.ts
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ui.prototype._drawTip_drawOne = function (tip) {
 | 
			
		||||
    core.setAlpha('data', tip.opacity);
 | 
			
		||||
    core.fillRect('data', 5, 5, tip.width, 42, '#000000');
 | 
			
		||||
    if (tip.image)
 | 
			
		||||
        core.drawImage(
 | 
			
		||||
            'data',
 | 
			
		||||
            tip.image,
 | 
			
		||||
            (tip.posX + tip.frame) * 32,
 | 
			
		||||
            tip.posY * tip.height,
 | 
			
		||||
            32,
 | 
			
		||||
            32,
 | 
			
		||||
            10,
 | 
			
		||||
            10,
 | 
			
		||||
            32,
 | 
			
		||||
            32
 | 
			
		||||
        );
 | 
			
		||||
    core.fillText('data', tip.text, tip.textX, 33, '#FFF', '16px normal');
 | 
			
		||||
    core.setAlpha('data', 1);
 | 
			
		||||
    // Deprecated. Fallback in modules/fallback/ui.ts
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
////// 地图中间绘制一段文字 //////
 | 
			
		||||
@ -2274,7 +2225,8 @@ ui.prototype._drawTextBox_getHorizontalPosition = function (
 | 
			
		||||
        paddingRight = 12;
 | 
			
		||||
    if ((posInfo.px != null && posInfo.py != null) || posInfo.pos)
 | 
			
		||||
        paddingLeft = 20;
 | 
			
		||||
    if (titleInfo.icon != null) paddingLeft = 62; // 15 + 32 + 15
 | 
			
		||||
    if (titleInfo.icon != null)
 | 
			
		||||
        paddingLeft = 62; // 15 + 32 + 15
 | 
			
		||||
    else if (titleInfo.image) paddingLeft = 90; // 10 + 70 + 10
 | 
			
		||||
    var left = 7 + 3 * (core._HALF_WIDTH_ - 6),
 | 
			
		||||
        right = core._PX_ - left,
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ import { IAnimateFrame, renderEmits } from '../frame';
 | 
			
		||||
type CanvasStyle = string | CanvasGradient | CanvasPattern;
 | 
			
		||||
 | 
			
		||||
export interface ETextEvent extends ERenderItemEvent {
 | 
			
		||||
    setText: [text: string];
 | 
			
		||||
    setText: [text: string, width: number, height: number];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class Text extends RenderItem<ETextEvent> {
 | 
			
		||||
@ -32,7 +32,7 @@ export class Text extends RenderItem<ETextEvent> {
 | 
			
		||||
        this.text = text;
 | 
			
		||||
        if (text.length > 0) {
 | 
			
		||||
            this.calBox();
 | 
			
		||||
            this.emit('setText', text);
 | 
			
		||||
            this.emit('setText', text, this.width, this.height);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -74,7 +74,7 @@ export class Text extends RenderItem<ETextEvent> {
 | 
			
		||||
        this.text = text;
 | 
			
		||||
        this.calBox();
 | 
			
		||||
        this.update(this);
 | 
			
		||||
        this.emit('setText', text);
 | 
			
		||||
        this.emit('setText', text, this.width, this.height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -113,11 +113,7 @@ export class Text extends RenderItem<ETextEvent> {
 | 
			
		||||
            this.measure();
 | 
			
		||||
        this.length = width;
 | 
			
		||||
        this.descent = actualBoundingBoxAscent;
 | 
			
		||||
        this.size(
 | 
			
		||||
            width,
 | 
			
		||||
            Math.abs(actualBoundingBoxAscent) +
 | 
			
		||||
                Math.abs(actualBoundingBoxDescent)
 | 
			
		||||
        );
 | 
			
		||||
        this.size(width, actualBoundingBoxAscent + actualBoundingBoxDescent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected handleProps(
 | 
			
		||||
@ -277,6 +273,10 @@ export class Icon extends RenderItem<EIconEvent> implements IAnimateFrame {
 | 
			
		||||
     * @param id 图标id
 | 
			
		||||
     */
 | 
			
		||||
    setIcon(id: AllIds | AllNumbers) {
 | 
			
		||||
        if (id === 0) {
 | 
			
		||||
            this.renderable = void 0;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        const num = typeof id === 'number' ? id : texture.idNumberMap[id];
 | 
			
		||||
 | 
			
		||||
        const loading = Mota.require('var', 'loading');
 | 
			
		||||
 | 
			
		||||
@ -91,6 +91,7 @@
 | 
			
		||||
        "57": "Repeated UI controller on item '$1', new controller will not work.",
 | 
			
		||||
        "58": "Fail to set ellipse round rect, since length of 'ellipse' property should only be 2, 4, 6 or 8. delivered: $1",
 | 
			
		||||
        "59": "Unknown icon '$1' in parsing text content.",
 | 
			
		||||
        "60": "Repeated Tip id: '$1'.",
 | 
			
		||||
        "1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency.",
 | 
			
		||||
        "1101": "Cannot add new effect to point effect instance, for there's no more reserve space for it. Please increase the max count of the instance."
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,12 @@
 | 
			
		||||
import { Patch } from '@/common/patch';
 | 
			
		||||
import { patchAudio } from './audio';
 | 
			
		||||
import { patchWeather } from './weather';
 | 
			
		||||
import { patchUI } from './ui';
 | 
			
		||||
 | 
			
		||||
export function patchAll() {
 | 
			
		||||
    patchAudio();
 | 
			
		||||
    patchWeather();
 | 
			
		||||
    patchUI();
 | 
			
		||||
    const loading = Mota.require('var', 'loading');
 | 
			
		||||
    loading.once('coreInit', () => {
 | 
			
		||||
        Patch.patchAll();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								src/module/fallback/ui.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/module/fallback/ui.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
import { Patch, PatchClass } from '@/common/patch';
 | 
			
		||||
import { TipStore } from '../render/components/tip';
 | 
			
		||||
 | 
			
		||||
export function patchUI() {
 | 
			
		||||
    const patch = new Patch(PatchClass.UI);
 | 
			
		||||
 | 
			
		||||
    patch.add('drawTip', function (text, id) {
 | 
			
		||||
        const tip = TipStore.get('main-tip');
 | 
			
		||||
        tip?.drawTip(text, id);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
@ -909,8 +909,7 @@ export class TextContentParser {
 | 
			
		||||
 | 
			
		||||
    private getHeight(metrics: TextMetrics) {
 | 
			
		||||
        return (
 | 
			
		||||
            Math.abs(metrics.actualBoundingBoxAscent) +
 | 
			
		||||
            Math.abs(metrics.actualBoundingBoxDescent)
 | 
			
		||||
            metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										169
									
								
								src/module/render/components/tip.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								src/module/render/components/tip.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,169 @@
 | 
			
		||||
import { DefaultProps, ElementLocator, texture } from '@/core/render';
 | 
			
		||||
import { computed, defineComponent, onUnmounted, ref } from 'vue';
 | 
			
		||||
import { SetupComponentOptions } from './types';
 | 
			
		||||
import { transitioned } from '../use';
 | 
			
		||||
import { hyper } from 'mutate-animate';
 | 
			
		||||
import { debounce } from 'lodash-es';
 | 
			
		||||
import { logger } from '@/core/common/logger';
 | 
			
		||||
 | 
			
		||||
export interface TipProps extends DefaultProps {
 | 
			
		||||
    loc: ElementLocator;
 | 
			
		||||
    pad?: [number, number];
 | 
			
		||||
    corner?: number;
 | 
			
		||||
    id?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TipExpose {
 | 
			
		||||
    /**
 | 
			
		||||
     * 显示提示文本
 | 
			
		||||
     * @param text 提示文字
 | 
			
		||||
     * @param icon 显示的图标,不填则不显示
 | 
			
		||||
     */
 | 
			
		||||
    drawTip(text: string, icon?: AllIds | AllNumbers): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const tipProps = {
 | 
			
		||||
    props: ['loc', 'pad', 'corner', 'id']
 | 
			
		||||
} satisfies SetupComponentOptions<TipProps>;
 | 
			
		||||
 | 
			
		||||
let id = 0;
 | 
			
		||||
function getNextTipId() {
 | 
			
		||||
    return `@default-tip-${id++}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const Tip = defineComponent<TipProps>((props, { expose }) => {
 | 
			
		||||
    const iconNum = ref<AllNumbers>(0);
 | 
			
		||||
    const text = ref<string>('');
 | 
			
		||||
    const textWidth = ref(0);
 | 
			
		||||
 | 
			
		||||
    const font = '16px normal';
 | 
			
		||||
 | 
			
		||||
    const alpha = transitioned(0, 500, hyper('sin', 'in-out'))!;
 | 
			
		||||
    const pad = computed(() => props.pad ?? [4, 4]);
 | 
			
		||||
    const locHeight = computed(() => props.loc[3] ?? 200);
 | 
			
		||||
    const hidden = computed(() => alpha.ref.value === 0);
 | 
			
		||||
    const showIcon = computed(() => iconNum.value !== 0);
 | 
			
		||||
    const iconSize = computed<[number, number]>(() => {
 | 
			
		||||
        const renderable = texture.getRenderable(iconNum.value);
 | 
			
		||||
        if (!renderable) return [1, 1];
 | 
			
		||||
        const [, , width, height] = renderable.render[0];
 | 
			
		||||
        return [width, height];
 | 
			
		||||
    });
 | 
			
		||||
    const iconLoc = computed<ElementLocator>(() => {
 | 
			
		||||
        const [width, height] = iconSize.value;
 | 
			
		||||
        const aspect = width / height;
 | 
			
		||||
        const realHeight = locHeight.value - pad.value[1] * 2;
 | 
			
		||||
        const realWidth = realHeight * aspect;
 | 
			
		||||
        return [pad.value[0], pad.value[1], realWidth, realHeight];
 | 
			
		||||
    });
 | 
			
		||||
    const textLoc = computed<ElementLocator>(() => {
 | 
			
		||||
        if (showIcon.value) {
 | 
			
		||||
            const [, , width] = iconLoc.value;
 | 
			
		||||
            const x = width! + pad.value[0] + pad.value[1];
 | 
			
		||||
            return [x, locHeight.value / 2, void 0, void 0, 0, 0.5];
 | 
			
		||||
        } else {
 | 
			
		||||
            return [pad.value[0], locHeight.value / 2, void 0, void 0, 0, 0.5];
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    const containerLoc = computed<ElementLocator>(() => {
 | 
			
		||||
        const [x = 0, y = 0, , height = 200] = props.loc;
 | 
			
		||||
        const iconWidth = iconLoc.value[2] ?? 32;
 | 
			
		||||
        if (showIcon.value) {
 | 
			
		||||
            const width =
 | 
			
		||||
                textWidth.value + iconWidth + pad.value[0] * 2 + pad.value[1];
 | 
			
		||||
            return [x, y, width, height];
 | 
			
		||||
        } else {
 | 
			
		||||
            const width = textWidth.value + pad.value[0] * 2;
 | 
			
		||||
            return [x, y, width, height];
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    const rectLoc = computed<ElementLocator>(() => {
 | 
			
		||||
        const [, , width = 200, height = 200] = containerLoc.value;
 | 
			
		||||
        return [1, 1, width - 2, height - 2];
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const hide = debounce(() => {
 | 
			
		||||
        alpha.set(0);
 | 
			
		||||
    }, 3000);
 | 
			
		||||
 | 
			
		||||
    const drawTip = (tipText: string, iconId: AllIds | AllNumbers = 0) => {
 | 
			
		||||
        if (typeof iconId === 'string') {
 | 
			
		||||
            const num = texture.idNumberMap[iconId];
 | 
			
		||||
            iconNum.value = num;
 | 
			
		||||
        } else {
 | 
			
		||||
            iconNum.value = iconId;
 | 
			
		||||
        }
 | 
			
		||||
        text.value = core.replaceText(tipText);
 | 
			
		||||
        alpha.set(0, 0);
 | 
			
		||||
        alpha.set(1);
 | 
			
		||||
        hide();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const onSetText = (_: string, width: number) => {
 | 
			
		||||
        textWidth.value = width;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const ex: TipExpose = { drawTip };
 | 
			
		||||
 | 
			
		||||
    TipStore.use(props.id ?? getNextTipId(), ex);
 | 
			
		||||
 | 
			
		||||
    expose<TipExpose>(ex);
 | 
			
		||||
 | 
			
		||||
    return () => (
 | 
			
		||||
        <container
 | 
			
		||||
            loc={containerLoc.value}
 | 
			
		||||
            alpha={alpha.ref.value}
 | 
			
		||||
            hidden={hidden.value}
 | 
			
		||||
            noevent
 | 
			
		||||
        >
 | 
			
		||||
            <g-rectr
 | 
			
		||||
                loc={rectLoc.value}
 | 
			
		||||
                circle={[props.corner ?? 4]}
 | 
			
		||||
                fill
 | 
			
		||||
                fillStyle="rgba(40,40,40,0.8)"
 | 
			
		||||
            />
 | 
			
		||||
            <icon
 | 
			
		||||
                hidden={!showIcon.value}
 | 
			
		||||
                icon={iconNum.value}
 | 
			
		||||
                loc={iconLoc.value}
 | 
			
		||||
            />
 | 
			
		||||
            <text
 | 
			
		||||
                loc={textLoc.value}
 | 
			
		||||
                text={text.value}
 | 
			
		||||
                onSetText={onSetText}
 | 
			
		||||
                font={font}
 | 
			
		||||
            />
 | 
			
		||||
        </container>
 | 
			
		||||
    );
 | 
			
		||||
}, tipProps);
 | 
			
		||||
 | 
			
		||||
export class TipStore {
 | 
			
		||||
    static list: Map<string, TipStore> = new Map();
 | 
			
		||||
 | 
			
		||||
    private constructor(private readonly data: TipExpose) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 显示提示文本
 | 
			
		||||
     * @param text 提示文字
 | 
			
		||||
     * @param icon 显示的图标,不填则不显示
 | 
			
		||||
     */
 | 
			
		||||
    drawTip(text: string, icon: AllIds | AllNumbers = 0) {
 | 
			
		||||
        this.data.drawTip(text, icon);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static get(id: string) {
 | 
			
		||||
        return TipStore.list.get(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static use(id: string, data: TipExpose) {
 | 
			
		||||
        const store = new TipStore(data);
 | 
			
		||||
        if (this.list.has(id)) {
 | 
			
		||||
            logger.warn(60, id);
 | 
			
		||||
        }
 | 
			
		||||
        this.list.set(id, store);
 | 
			
		||||
        onUnmounted(() => {
 | 
			
		||||
            this.list.delete(id);
 | 
			
		||||
        });
 | 
			
		||||
        return store;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -34,6 +34,7 @@ import {
 | 
			
		||||
} from './statusBar';
 | 
			
		||||
import { onLoaded } from '../use';
 | 
			
		||||
import { ReplayingStatus } from './toolbar';
 | 
			
		||||
import { Tip } from '../components/tip';
 | 
			
		||||
 | 
			
		||||
const MainScene = defineComponent(() => {
 | 
			
		||||
    const layerGroupExtends: ILayerGroupRenderExtends[] = [
 | 
			
		||||
@ -187,6 +188,13 @@ const MainScene = defineComponent(() => {
 | 
			
		||||
                </layer-group>
 | 
			
		||||
                <Textbox id="main-textbox" {...mainTextboxProps}></Textbox>
 | 
			
		||||
                <FloorChange id="floor-change" zIndex={50}></FloorChange>
 | 
			
		||||
                <Tip
 | 
			
		||||
                    id="main-tip"
 | 
			
		||||
                    zIndex={80}
 | 
			
		||||
                    loc={[8, 8, 200, 32]}
 | 
			
		||||
                    pad={[12, 6]}
 | 
			
		||||
                    corner={16}
 | 
			
		||||
                />
 | 
			
		||||
            </container>
 | 
			
		||||
            <g-line line={[180 + 480, 0, 180 + 480, 480]} lineWidth={1} />
 | 
			
		||||
            {loaded.value && (
 | 
			
		||||
 | 
			
		||||
@ -70,7 +70,7 @@ export function onLoaded(hook: () => void) {
 | 
			
		||||
export interface ITransitionedController<T> {
 | 
			
		||||
    readonly ref: Ref<T>;
 | 
			
		||||
    readonly value: T;
 | 
			
		||||
    set(value: T): void;
 | 
			
		||||
    set(value: T, time?: number): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class RenderTransition implements ITransitionedController<number> {
 | 
			
		||||
@ -100,11 +100,8 @@ class RenderTransition implements ITransitionedController<number> {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set(value: number): void {
 | 
			
		||||
        this.transition
 | 
			
		||||
            .time(this.time)
 | 
			
		||||
            .mode(this.curve)
 | 
			
		||||
            .transition(this.key, value);
 | 
			
		||||
    set(value: number, time: number = this.time): void {
 | 
			
		||||
        this.transition.time(time).mode(this.curve).transition(this.key, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -144,14 +141,14 @@ class RenderColorTransition implements ITransitionedController<string> {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set(value: string): void {
 | 
			
		||||
        this.transitionColor(this.decodeColor(value));
 | 
			
		||||
    set(value: string, time: number = this.time): void {
 | 
			
		||||
        this.transitionColor(this.decodeColor(value), time);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private transitionColor([r, g, b, a]: ColorRGBA) {
 | 
			
		||||
    private transitionColor([r, g, b, a]: ColorRGBA, time: number) {
 | 
			
		||||
        this.transition
 | 
			
		||||
            .mode(this.curve)
 | 
			
		||||
            .time(this.time)
 | 
			
		||||
            .time(time)
 | 
			
		||||
            .transition(this.keyR, r)
 | 
			
		||||
            .transition(this.keyG, g)
 | 
			
		||||
            .transition(this.keyB, b)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user