diff --git a/src/core/render/index.ts b/src/core/render/index.ts index 4f5a574..f889456 100644 --- a/src/core/render/index.ts +++ b/src/core/render/index.ts @@ -11,6 +11,7 @@ import { LayerGroupPortal } from '@/plugin/fx/portal'; import { LayerGroupHalo } from '@/plugin/fx/halo'; import { FloorViewport } from './preset/viewport'; import { Container } from './container'; +import { PopText } from '@/plugin/fx/pop'; let main: MotaRenderer; @@ -22,13 +23,16 @@ Mota.require('var', 'loading').once('coreInit', () => { const mapDraw = new Container(); const layer = new LayerGroup(); + const pop = new PopText('static'); mapDraw.id = 'map-draw'; layer.id = 'layer-main'; + pop.id = 'pop-main'; mapDraw.setHD(true); mapDraw.setAntiAliasing(false); mapDraw.size(core._PX_, core._PY_); + pop.setZIndex(80); ['bg', 'bg2', 'event', 'fg', 'fg2'].forEach(v => { layer.addLayer(v as FloorLayer); }); @@ -56,6 +60,7 @@ Mota.require('var', 'loading').once('coreInit', () => { render.appendChild(mapDraw); mapDraw.appendChild(layer); + layer.appendChild(pop); console.log(render); }); diff --git a/src/plugin/fx/pop.ts b/src/plugin/fx/pop.ts new file mode 100644 index 0000000..e1948bd --- /dev/null +++ b/src/plugin/fx/pop.ts @@ -0,0 +1,96 @@ +import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d'; +import { RenderItem, RenderItemPosition } from '@/core/render/item'; +import { Transform } from '@/core/render/transform'; +import { TimingFn } from 'mutate-animate'; + +interface PopData { + cx: number; + cy: number; + path: TimingFn<2>; + text: string; + time: number; + start: number; + color: CanvasStyle; +} + +function parabola(input: number): [number, number] { + const x = input * 100; + return [x, x ** 2 / 20 - 3 * x]; +} + +export class PopText extends RenderItem { + private popList: Set = new Set(); + + private delegation: number = 0; + + constructor(type: RenderItemPosition) { + super(type, false); + this.delegation = this.delegateTicker(() => { + if (this.popList.size > 0) this.update(); + }); + } + + /** + * 添加一个弹出文字 + * @param text 要显示的文字 + * @param time 持续时长 + * @param cx 中心点,也就是从哪弹出的 + * @param cy 中心点,也就是从哪弹出的 + * @param path 自定义路径,不填表示默认的抛物线路径 + */ + addPop( + text: string, + time: number, + cx: number, + cy: number, + color: CanvasStyle, + path?: TimingFn<2> + ) { + this.popList.add({ + text, + time, + cx, + cy, + color, + path: path ?? parabola, + start: Date.now() + }); + this.update(); + } + + protected render( + canvas: MotaOffscreenCanvas2D, + transform: Transform + ): void { + const ctx = canvas.ctx; + const toDelete = new Set(); + const now = Date.now(); + ctx.strokeStyle = '#000'; + ctx.font = '22px Verdana'; + ctx.lineWidth = 3; + this.popList.forEach(v => { + const { cx, cy, path, text, color, time, start } = v; + const dt = now - start; + const progress = dt / time; + if (progress >= 1) { + toDelete.add(v); + return; + } + const [x, y] = path(progress); + const dx = cx + x; + const dy = cy + y; + ctx.globalAlpha = Math.min(1, 2 - progress * 2); + ctx.fillStyle = color; + ctx.strokeText(text, dx, dy); + ctx.fillText(text, dx, dy); + }); + toDelete.forEach(v => { + this.popList.delete(v); + }); + } + + destroy(): void { + super.destroy(); + this.removeTicker(this.delegation); + } +}