mirror of
https://github.com/motajs/template.git
synced 2026-04-12 15:11:10 +08:00
Compare commits
No commits in common. "93fb788befe662fe8acc3d366266f4077ac9ad20" and "57108367b268f535a088005e70e3ecab81a0a781" have entirely different histories.
93fb788bef
...
57108367b2
@ -19,5 +19,4 @@ export async function createMainExtension() {
|
|||||||
mainMapExtension.addHero(state.hero, layer);
|
mainMapExtension.addHero(state.hero, layer);
|
||||||
mainMapExtension.addDoor(layer);
|
mainMapExtension.addDoor(layer);
|
||||||
}
|
}
|
||||||
mainMapExtension.addText();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { Icon, Winskin } from './misc';
|
|||||||
import { Animate } from './animate';
|
import { Animate } from './animate';
|
||||||
import { createItemDetail } from './itemDetail';
|
import { createItemDetail } from './itemDetail';
|
||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { MapExtensionManager, MapRender, MapRenderer } from '../map';
|
import { MapRender, MapRenderer } from '../map';
|
||||||
import { state } from '@user/data-state';
|
import { state } from '@user/data-state';
|
||||||
import { materials } from '@user/client-base';
|
import { materials } from '@user/client-base';
|
||||||
|
|
||||||
@ -72,31 +72,28 @@ export function createElements() {
|
|||||||
tagMap.register('icon', standardElementNoCache(Icon));
|
tagMap.register('icon', standardElementNoCache(Icon));
|
||||||
tagMap.register('map-render', (_0, _1, props) => {
|
tagMap.register('map-render', (_0, _1, props) => {
|
||||||
if (!props) {
|
if (!props) {
|
||||||
logger.error(42, 'layerState, renderer, extenstion');
|
logger.error(42);
|
||||||
const renderer = new MapRenderer(materials, state.layer);
|
return new MapRender(
|
||||||
const manager = new MapExtensionManager(renderer);
|
state.layer,
|
||||||
return new MapRender(state.layer, renderer, manager);
|
new MapRenderer(materials, state.layer)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const { layerState, renderer, extension } = props;
|
const { layerState, renderer } = props;
|
||||||
if (!layerState) {
|
if (!layerState) {
|
||||||
logger.error(42, 'layerState');
|
logger.error(42, 'layerState');
|
||||||
const renderer = new MapRenderer(materials, state.layer);
|
return new MapRender(
|
||||||
const manager = new MapExtensionManager(renderer);
|
state.layer,
|
||||||
return new MapRender(state.layer, renderer, manager);
|
new MapRenderer(materials, state.layer)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!renderer) {
|
if (!renderer) {
|
||||||
logger.error(42, 'renderer');
|
logger.error(42, 'renderer');
|
||||||
const renderer = new MapRenderer(materials, state.layer);
|
return new MapRender(
|
||||||
const manager = new MapExtensionManager(renderer);
|
state.layer,
|
||||||
return new MapRender(state.layer, renderer, manager);
|
new MapRenderer(materials, state.layer)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!extension) {
|
return new MapRender(layerState, renderer);
|
||||||
logger.error(42, 'extension');
|
|
||||||
const renderer = new MapRenderer(materials, state.layer);
|
|
||||||
const manager = new MapExtensionManager(renderer);
|
|
||||||
return new MapRender(state.layer, renderer, manager);
|
|
||||||
}
|
|
||||||
return new MapRender(layerState, renderer, extension);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { EAnimateEvent } from './animate';
|
|||||||
import { EIconEvent, EWinskinEvent } from './misc';
|
import { EIconEvent, EWinskinEvent } from './misc';
|
||||||
import { IEnemyCollection } from '@motajs/types';
|
import { IEnemyCollection } from '@motajs/types';
|
||||||
import { ILayerState } from '@user/data-state';
|
import { ILayerState } from '@user/data-state';
|
||||||
import { IMapExtensionManager, IMapRenderer, IOnMapTextRenderer } from '../map';
|
import { IMapRenderer } from '../map';
|
||||||
|
|
||||||
export interface AnimateProps extends BaseProps {}
|
export interface AnimateProps extends BaseProps {}
|
||||||
|
|
||||||
@ -65,8 +65,6 @@ export interface LayerProps extends BaseProps {
|
|||||||
export interface MapRenderProps extends BaseProps {
|
export interface MapRenderProps extends BaseProps {
|
||||||
layerState: ILayerState;
|
layerState: ILayerState;
|
||||||
renderer: IMapRenderer;
|
renderer: IMapRenderer;
|
||||||
extension: IMapExtensionManager;
|
|
||||||
textExtension?: IOnMapTextRenderer | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'vue/jsx-runtime' {
|
declare module 'vue/jsx-runtime' {
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { ILayerState } from '@user/data-state';
|
|||||||
import { IMapRenderer } from './types';
|
import { IMapRenderer } from './types';
|
||||||
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
||||||
import { CELL_HEIGHT, CELL_WIDTH, MAP_HEIGHT, MAP_WIDTH } from '../shared';
|
import { CELL_HEIGHT, CELL_WIDTH, MAP_HEIGHT, MAP_WIDTH } from '../shared';
|
||||||
import { IMapExtensionManager } from './extension';
|
|
||||||
|
|
||||||
export class MapRender extends RenderItem {
|
export class MapRender extends RenderItem {
|
||||||
/**
|
/**
|
||||||
@ -12,8 +11,7 @@ export class MapRender extends RenderItem {
|
|||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
readonly layerState: ILayerState,
|
readonly layerState: ILayerState,
|
||||||
readonly renderer: IMapRenderer,
|
readonly renderer: IMapRenderer
|
||||||
readonly exManager: IMapExtensionManager
|
|
||||||
) {
|
) {
|
||||||
super('static', false, false);
|
super('static', false, false);
|
||||||
|
|
||||||
@ -26,33 +24,9 @@ export class MapRender extends RenderItem {
|
|||||||
if (this.renderer.needUpdate()) {
|
if (this.renderer.needUpdate()) {
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
const text = exManager.textRenderer;
|
|
||||||
if (text) {
|
|
||||||
if (text.needResize) {
|
|
||||||
this.resizeTextRenderer(this.width, this.height);
|
|
||||||
}
|
|
||||||
if (text.needUpdate()) {
|
|
||||||
this.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private resizeTextRenderer(width: number, height: number) {
|
|
||||||
const ex = this.exManager.textRenderer;
|
|
||||||
if (!ex) return;
|
|
||||||
const ratio = this.highResolution ? devicePixelRatio : 1;
|
|
||||||
const scale = ratio * this.scale;
|
|
||||||
const w = width * scale;
|
|
||||||
const h = height * scale;
|
|
||||||
ex.resize(
|
|
||||||
w,
|
|
||||||
h,
|
|
||||||
w / this.renderer.renderWidth,
|
|
||||||
h / this.renderer.renderHeight
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private sizeGL(width: number, height: number) {
|
private sizeGL(width: number, height: number) {
|
||||||
const ratio = this.highResolution ? devicePixelRatio : 1;
|
const ratio = this.highResolution ? devicePixelRatio : 1;
|
||||||
const scale = ratio * this.scale;
|
const scale = ratio * this.scale;
|
||||||
@ -60,14 +34,6 @@ export class MapRender extends RenderItem {
|
|||||||
const h = height * scale;
|
const h = height * scale;
|
||||||
this.renderer.setCanvasSize(w, h);
|
this.renderer.setCanvasSize(w, h);
|
||||||
this.renderer.setViewport(0, 0, w, h);
|
this.renderer.setViewport(0, 0, w, h);
|
||||||
if (this.exManager.textRenderer) {
|
|
||||||
this.exManager.textRenderer.resize(
|
|
||||||
w,
|
|
||||||
h,
|
|
||||||
w / this.renderer.renderWidth,
|
|
||||||
h / this.renderer.renderHeight
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onResize(scale: number): void {
|
onResize(scale: number): void {
|
||||||
@ -83,11 +49,7 @@ export class MapRender extends RenderItem {
|
|||||||
protected render(canvas: MotaOffscreenCanvas2D): void {
|
protected render(canvas: MotaOffscreenCanvas2D): void {
|
||||||
this.renderer.clear(true, true);
|
this.renderer.clear(true, true);
|
||||||
const map = this.renderer.render();
|
const map = this.renderer.render();
|
||||||
canvas.ctx.drawImage(map.canvas, 0, 0, canvas.width, canvas.height);
|
canvas.ctx.drawImage(map, 0, 0, canvas.width, canvas.height);
|
||||||
if (this.exManager.textRenderer) {
|
|
||||||
const text = this.exManager.textRenderer.render(map);
|
|
||||||
canvas.ctx.drawImage(text, 0, 0, canvas.width, canvas.height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
patchProp(
|
patchProp(
|
||||||
|
|||||||
@ -8,16 +8,12 @@ import { IMapRenderer } from '../types';
|
|||||||
import { MapHeroRenderer } from './hero';
|
import { MapHeroRenderer } from './hero';
|
||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { MapDoorRenderer } from './door';
|
import { MapDoorRenderer } from './door';
|
||||||
import { OnMapTextRenderer } from './text';
|
|
||||||
import { IOnMapTextRenderer } from './types';
|
|
||||||
|
|
||||||
export class MapExtensionManager implements IMapExtensionManager {
|
export class MapExtensionManager implements IMapExtensionManager {
|
||||||
/** 勇士状态至勇士渲染器的映射 */
|
/** 勇士状态至勇士渲染器的映射 */
|
||||||
readonly heroMap: Map<IHeroState, IMapHeroRenderer> = new Map();
|
readonly heroMap: Map<IHeroState, IMapHeroRenderer> = new Map();
|
||||||
/** 地图图层到门渲染器的映射 */
|
/** 地图图层到门渲染器的映射 */
|
||||||
readonly doorMap: Map<IMapLayer, IMapDoorRenderer> = new Map();
|
readonly doorMap: Map<IMapLayer, IMapDoorRenderer> = new Map();
|
||||||
/** 单例的文字渲染拓展(独立图层) */
|
|
||||||
textRenderer: IOnMapTextRenderer | null = null;
|
|
||||||
|
|
||||||
constructor(readonly renderer: IMapRenderer) {}
|
constructor(readonly renderer: IMapRenderer) {}
|
||||||
|
|
||||||
@ -48,22 +44,6 @@ export class MapExtensionManager implements IMapExtensionManager {
|
|||||||
return doorRenderer;
|
return doorRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
addText(): IOnMapTextRenderer | null {
|
|
||||||
if (this.textRenderer) {
|
|
||||||
logger.error(45, 'on-map text renderer');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const r = new OnMapTextRenderer(this.renderer);
|
|
||||||
this.textRenderer = r;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeText(): void {
|
|
||||||
if (!this.textRenderer) return;
|
|
||||||
this.textRenderer.destroy();
|
|
||||||
this.textRenderer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeDoor(layer: IMapLayer): void {
|
removeDoor(layer: IMapLayer): void {
|
||||||
const renderer = this.doorMap.get(layer);
|
const renderer = this.doorMap.get(layer);
|
||||||
if (!renderer) return;
|
if (!renderer) return;
|
||||||
@ -76,7 +56,5 @@ export class MapExtensionManager implements IMapExtensionManager {
|
|||||||
this.doorMap.forEach(v => void v.destroy());
|
this.doorMap.forEach(v => void v.destroy());
|
||||||
this.heroMap.clear();
|
this.heroMap.clear();
|
||||||
this.doorMap.clear();
|
this.doorMap.clear();
|
||||||
this.textRenderer?.destroy();
|
|
||||||
this.textRenderer = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,279 +1,63 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { IMapRenderer } from '../types';
|
||||||
import {
|
|
||||||
IBlockData,
|
|
||||||
IBlockSplitter,
|
|
||||||
IMapRenderer,
|
|
||||||
IMapRenderResult,
|
|
||||||
IMapVertexBlock
|
|
||||||
} from '../types';
|
|
||||||
import { IMapTextArea, IMapTextRenderable, IOnMapTextRenderer } from './types';
|
import { IMapTextArea, IMapTextRenderable, IOnMapTextRenderer } from './types';
|
||||||
import { ITransformUpdatable, Transform } from '@motajs/render-core';
|
|
||||||
|
|
||||||
export class OnMapTextRenderer
|
export class OnMapTextRenderer implements IOnMapTextRenderer {
|
||||||
implements IOnMapTextRenderer, ITransformUpdatable<Transform>
|
|
||||||
{
|
|
||||||
/** 画布元素 */
|
/** 画布元素 */
|
||||||
readonly canvas: HTMLCanvasElement;
|
readonly canvas: HTMLCanvasElement;
|
||||||
/** 画布 Canvas2D 上下文 */
|
/** 画布 Canvas2D 上下文 */
|
||||||
readonly ctx: CanvasRenderingContext2D;
|
readonly ctx: CanvasRenderingContext2D;
|
||||||
|
|
||||||
needResize: boolean = true;
|
/** 图块索引到图块文本对象的映射 */
|
||||||
|
readonly areaMap: Map<number, MapTextArea> = new Map();
|
||||||
/** 分块上附着文本区域的标识符 */
|
|
||||||
private readonly attachSymbol: symbol = Symbol('onMapTextAreas');
|
|
||||||
|
|
||||||
/** 是否有内容发生变化,需要更新 */
|
|
||||||
private dirty: boolean = false;
|
private dirty: boolean = false;
|
||||||
|
|
||||||
/** 分块对象 */
|
|
||||||
private readonly block: IBlockSplitter<IMapVertexBlock>;
|
|
||||||
/** 变换矩阵 */
|
|
||||||
private readonly transform: Transform;
|
|
||||||
|
|
||||||
constructor(readonly renderer: IMapRenderer) {
|
constructor(readonly renderer: IMapRenderer) {
|
||||||
this.canvas = document.createElement('canvas');
|
this.canvas = document.createElement('canvas');
|
||||||
this.ctx = this.canvas.getContext('2d')!;
|
this.ctx = this.canvas.getContext('2d')!;
|
||||||
this.block = renderer.vertex.block;
|
|
||||||
this.transform = renderer.transform;
|
|
||||||
this.ctx.lineWidth = 2;
|
|
||||||
this.transform.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTransform() {
|
render(): HTMLCanvasElement {
|
||||||
this.dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标记为需要更新
|
|
||||||
*/
|
|
||||||
markDirty(): void {
|
|
||||||
this.dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
resize(
|
|
||||||
width: number,
|
|
||||||
height: number,
|
|
||||||
scaleX: number,
|
|
||||||
scaleY: number
|
|
||||||
): void {
|
|
||||||
this.canvas.width = width;
|
|
||||||
this.canvas.height = height;
|
|
||||||
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
||||||
this.ctx.translate(width / 2, height / 2);
|
|
||||||
this.ctx.scale(1, -1);
|
|
||||||
this.ctx.scale(scaleX, scaleY);
|
|
||||||
this.dirty = true;
|
|
||||||
this.needResize = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlockByLoc(x: number, y: number): Readonly<IMapTextArea> | null {
|
|
||||||
const index = y * this.renderer.mapWidth + x;
|
|
||||||
// 首先尝试使用分块系统获取对应分块并从分块附着数据读取
|
|
||||||
const blockData = this.block.getBlockByDataIndex(index);
|
|
||||||
if (blockData) {
|
|
||||||
const map = blockData.data.getAttachedData<
|
|
||||||
Map<number, MapTextArea>
|
|
||||||
>(this.attachSymbol);
|
|
||||||
if (map) return map.get(index) ?? null;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getBlockByIndex(index: number): Readonly<IMapTextArea> | null {
|
|
||||||
const blockData = this.block.getBlockByDataIndex(index);
|
|
||||||
if (blockData) {
|
|
||||||
const map = blockData.data.getAttachedData<
|
|
||||||
Map<number, MapTextArea>
|
|
||||||
>(this.attachSymbol);
|
|
||||||
if (map) return map.get(index) || null;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
render(data: IMapRenderResult): HTMLCanvasElement {
|
|
||||||
if (!this.dirty) return this.canvas;
|
|
||||||
|
|
||||||
const ctx = this.ctx;
|
|
||||||
const { renderWidth, renderHeight } = this.renderer;
|
|
||||||
|
|
||||||
// clear
|
|
||||||
ctx.clearRect(
|
|
||||||
-renderWidth / 2,
|
|
||||||
-renderHeight / 2,
|
|
||||||
renderWidth,
|
|
||||||
renderHeight
|
|
||||||
);
|
|
||||||
ctx.save();
|
|
||||||
|
|
||||||
// apply transform matrix
|
|
||||||
const [a, b, , c, d, , e, f] = this.transform.mat;
|
|
||||||
|
|
||||||
ctx.transform(
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
c,
|
|
||||||
d,
|
|
||||||
(e * renderWidth) / 2,
|
|
||||||
(f * renderHeight) / 2
|
|
||||||
);
|
|
||||||
ctx.scale(1, -1);
|
|
||||||
|
|
||||||
// draw text in each block
|
|
||||||
for (const blk of data.area.blockList) {
|
|
||||||
const map = blk.data.getAttachedData<Map<number, MapTextArea>>(
|
|
||||||
this.attachSymbol
|
|
||||||
);
|
|
||||||
if (!map) continue;
|
|
||||||
for (const area of map.values()) {
|
|
||||||
const baseX = area.mapX * this.renderer.cellWidth;
|
|
||||||
const baseY = area.mapY * this.renderer.cellHeight;
|
|
||||||
for (const renderable of area.getRenderables()) {
|
|
||||||
const x = baseX + (renderable.px ?? 0) - renderWidth / 2;
|
|
||||||
const y = renderHeight / 2 - (baseY + (renderable.py ?? 0));
|
|
||||||
ctx.font = renderable.font.string();
|
|
||||||
ctx.textAlign = renderable.textAlign ?? 'left';
|
|
||||||
ctx.textBaseline = renderable.textBaseline ?? 'top';
|
|
||||||
if (renderable.stroke) {
|
|
||||||
ctx.strokeStyle = renderable.strokeStyle ?? 'black';
|
|
||||||
ctx.strokeText(renderable.text, x, -y);
|
|
||||||
}
|
|
||||||
if (renderable.fill) {
|
|
||||||
ctx.fillStyle = renderable.fillStyle ?? 'white';
|
|
||||||
ctx.fillText(renderable.text, x, -y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dirty = false;
|
|
||||||
ctx.restore();
|
|
||||||
|
|
||||||
return this.canvas;
|
return this.canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
requireBlockArea(x: number, y: number): Readonly<IMapTextArea> {
|
||||||
* 获取分块所附着的文字数据
|
|
||||||
* @param blockData 分块数据
|
|
||||||
*/
|
|
||||||
private getAttachedMap(
|
|
||||||
blockData: IBlockData<IMapVertexBlock>
|
|
||||||
): Map<number, MapTextArea> {
|
|
||||||
const map = blockData.data.getAttachedData<Map<number, MapTextArea>>(
|
|
||||||
this.attachSymbol
|
|
||||||
);
|
|
||||||
if (map) return map;
|
|
||||||
else {
|
|
||||||
const map = new Map();
|
|
||||||
blockData.data.attach(this.attachSymbol, map);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
requireBlockArea(x: number, y: number): Readonly<IMapTextArea> | null {
|
|
||||||
const index = y * this.renderer.mapWidth + x;
|
const index = y * this.renderer.mapWidth + x;
|
||||||
// try to find corresponding block by data index
|
const exist = this.areaMap.get(index);
|
||||||
const blockData = this.block.getBlockByDataIndex(index);
|
if (exist) return exist;
|
||||||
if (blockData) {
|
const area = new MapTextArea(this, x, y);
|
||||||
const map = this.getAttachedMap(blockData);
|
this.areaMap.set(index, area);
|
||||||
const exist = map.get(index);
|
return area;
|
||||||
if (exist) return exist;
|
|
||||||
const area = new MapTextArea(this, x, y);
|
|
||||||
map.set(index, area);
|
|
||||||
this.markDirty();
|
|
||||||
return area;
|
|
||||||
} else {
|
|
||||||
logger.error(47);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
needUpdate(): boolean {
|
needUpdate(): boolean {
|
||||||
return this.dirty;
|
return this.dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear(): void {
|
clear(): void {}
|
||||||
// 清理所有附着在分块上的文本区域
|
|
||||||
for (const b of this.block.iterateBlocks()) {
|
|
||||||
const blk = b.data;
|
|
||||||
const map = blk.getAttachedData<Map<number, MapTextArea>>(
|
|
||||||
this.attachSymbol
|
|
||||||
);
|
|
||||||
if (map) {
|
|
||||||
for (const area of map.values()) area.clear();
|
|
||||||
blk.deleteAttachedData(this.attachSymbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dirty = true;
|
destroy(): void {}
|
||||||
}
|
|
||||||
|
|
||||||
destroy(): void {
|
|
||||||
this.transform.unbind(this);
|
|
||||||
this.clear();
|
|
||||||
// the canvas and context references are left intact; consumers may
|
|
||||||
// discard the renderer instance to allow GC. We don't detach the
|
|
||||||
// canvas from any DOM since ownership is external.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MapTextArea implements IMapTextArea {
|
class MapTextArea implements IMapTextArea {
|
||||||
readonly index: number;
|
index: number;
|
||||||
// maintain both a set for quick membership checks and a map for index lookup
|
|
||||||
private renderableSet: Set<IMapTextRenderable> = new Set();
|
|
||||||
private renderableMap: Map<number, IMapTextRenderable> = new Map();
|
|
||||||
private reverseMap: Map<IMapTextRenderable, number> = new Map();
|
|
||||||
private nextRenderableIndex: number = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取本区域的所有可渲染对象,用于绘制阶段
|
|
||||||
*/
|
|
||||||
getRenderables(): Iterable<IMapTextRenderable> {
|
|
||||||
return this.renderableSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly renderer: OnMapTextRenderer,
|
readonly renderer: OnMapTextRenderer,
|
||||||
public readonly mapX: number,
|
public mapX: number,
|
||||||
public readonly mapY: number
|
public mapY: number
|
||||||
) {
|
) {
|
||||||
this.index = mapY * renderer.renderer.mapWidth + mapX;
|
this.index = mapY * renderer.renderer.mapWidth + mapX;
|
||||||
}
|
}
|
||||||
|
|
||||||
addTextRenderable(renderable: IMapTextRenderable): number {
|
addTextRenderable(renderable: IMapTextRenderable): void {
|
||||||
const idx = this.nextRenderableIndex++;
|
throw new Error('Method not implemented.');
|
||||||
this.renderableSet.add(renderable);
|
|
||||||
this.renderableMap.set(idx, renderable);
|
|
||||||
this.reverseMap.set(renderable, idx);
|
|
||||||
this.renderer.markDirty();
|
|
||||||
return idx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTextRenderable(renderable: IMapTextRenderable): void {
|
removeTextRenderable(renderable: IMapTextRenderable): void {
|
||||||
const idx = this.reverseMap.get(renderable);
|
throw new Error('Method not implemented.');
|
||||||
if (idx !== void 0) {
|
|
||||||
this.renderableSet.delete(renderable);
|
|
||||||
this.renderableMap.delete(idx);
|
|
||||||
this.reverseMap.delete(renderable);
|
|
||||||
this.renderer.markDirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
removeTextRenderableByIndex(index: number): void {
|
|
||||||
const obj = this.renderableMap.get(index);
|
|
||||||
if (obj !== void 0) {
|
|
||||||
this.renderableMap.delete(index);
|
|
||||||
this.renderableSet.delete(obj);
|
|
||||||
this.reverseMap.delete(obj);
|
|
||||||
this.renderer.markDirty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clear(): void {
|
clear(): void {
|
||||||
if (this.renderableSet.size > 0) {
|
throw new Error('Method not implemented.');
|
||||||
this.renderableSet.clear();
|
|
||||||
this.renderableMap.clear();
|
|
||||||
this.reverseMap.clear();
|
|
||||||
this.renderer.markDirty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,16 +6,8 @@ import {
|
|||||||
IMapLayer
|
IMapLayer
|
||||||
} from '@user/data-state';
|
} from '@user/data-state';
|
||||||
import { Font } from '@motajs/render-style';
|
import { Font } from '@motajs/render-style';
|
||||||
import { IMapRenderResult } from '../types';
|
|
||||||
|
|
||||||
export interface IMapExtensionManager {
|
export interface IMapExtensionManager {
|
||||||
/** 勇士状态至勇士渲染器的映射 */
|
|
||||||
readonly heroMap: Map<IHeroState, IMapHeroRenderer>;
|
|
||||||
/** 地图图层到门渲染器的映射 */
|
|
||||||
readonly doorMap: Map<IMapLayer, IMapDoorRenderer>;
|
|
||||||
/** 单例的文字渲染拓展(独立图层) */
|
|
||||||
readonly textRenderer: IOnMapTextRenderer | null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加勇士渲染拓展
|
* 添加勇士渲染拓展
|
||||||
* @param state 勇士状态
|
* @param state 勇士状态
|
||||||
@ -39,16 +31,6 @@ export interface IMapExtensionManager {
|
|||||||
*/
|
*/
|
||||||
removeDoor(layer: IMapLayer): void;
|
removeDoor(layer: IMapLayer): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加文字渲染拓展
|
|
||||||
*/
|
|
||||||
addText(): IOnMapTextRenderer | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 移除文字渲染拓展
|
|
||||||
*/
|
|
||||||
removeText(): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 摧毁这个拓展管理对象,释放相关资源
|
* 摧毁这个拓展管理对象,释放相关资源
|
||||||
*/
|
*/
|
||||||
@ -186,22 +168,18 @@ export interface IMapTextRenderable {
|
|||||||
readonly text: string;
|
readonly text: string;
|
||||||
/** 文本字体 */
|
/** 文本字体 */
|
||||||
readonly font: Font;
|
readonly font: Font;
|
||||||
/** 是否填充 */
|
|
||||||
readonly fill?: boolean;
|
|
||||||
/** 是否描边 */
|
|
||||||
readonly stroke?: boolean;
|
|
||||||
/** 文本填充样式 */
|
/** 文本填充样式 */
|
||||||
readonly fillStyle?: CanvasStyle;
|
readonly fillStyle: CanvasStyle;
|
||||||
/** 文本描边样式 */
|
/** 文本描边样式 */
|
||||||
readonly strokeStyle?: CanvasStyle;
|
readonly strokeStyle: CanvasStyle;
|
||||||
/** 文本横坐标,注意 {@link IMapTextArea.addTextRenderable} 的相对关系 */
|
/** 文本横坐标,注意 {@link IMapTextArea.addTextRenderable} 的相对关系 */
|
||||||
readonly px?: number;
|
readonly px: number;
|
||||||
/** 文本纵坐标,注意 {@link IMapTextArea.addTextRenderable} 的相对关系 */
|
/** 文本纵坐标,注意 {@link IMapTextArea.addTextRenderable} 的相对关系 */
|
||||||
readonly py?: number;
|
readonly py: number;
|
||||||
/** 文本横向对齐方式 */
|
/** 文本横向对齐方式 */
|
||||||
readonly textAlign?: CanvasTextAlign;
|
readonly textAlign: CanvasTextAlign;
|
||||||
/** 文本纵向对齐方式 */
|
/** 文本纵向对齐方式 */
|
||||||
readonly textBaseline?: CanvasTextBaseline;
|
readonly textBaseline: CanvasTextBaseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapTextRequested {
|
export interface IMapTextRequested {
|
||||||
@ -214,18 +192,17 @@ export interface IMapTextRequested {
|
|||||||
|
|
||||||
export interface IMapTextArea {
|
export interface IMapTextArea {
|
||||||
/** 图块在地图上的索引 */
|
/** 图块在地图上的索引 */
|
||||||
readonly index: number;
|
index: number;
|
||||||
/** 图块横坐标 */
|
/** 图块横坐标 */
|
||||||
readonly mapX: number;
|
mapX: number;
|
||||||
/** 图块纵坐标 */
|
/** 图块纵坐标 */
|
||||||
readonly mapY: number;
|
mapY: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加文字可渲染对象。可渲染对象的坐标相对于图块,而非地图。
|
* 添加文字可渲染对象。可渲染对象的坐标相对于图块,而非地图。
|
||||||
* @param renderable 可渲染对象
|
* @param renderable 可渲染对象
|
||||||
* @returns 添加的可渲染对象的唯一索引标识符
|
|
||||||
*/
|
*/
|
||||||
addTextRenderable(renderable: IMapTextRenderable): number;
|
addTextRenderable(renderable: IMapTextRenderable): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除指定的文字可渲染对象
|
* 移除指定的文字可渲染对象
|
||||||
@ -233,12 +210,6 @@ export interface IMapTextArea {
|
|||||||
*/
|
*/
|
||||||
removeTextRenderable(renderable: IMapTextRenderable): void;
|
removeTextRenderable(renderable: IMapTextRenderable): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据可渲染对象的索引标识符移除文字的可渲染对象
|
|
||||||
* @param index 可渲染对象对应的索引标识符
|
|
||||||
*/
|
|
||||||
removeTextRenderableByIndex(index: number): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除本图块的所有文字可渲染对象
|
* 清除本图块的所有文字可渲染对象
|
||||||
*/
|
*/
|
||||||
@ -246,43 +217,17 @@ export interface IMapTextArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IOnMapTextRenderer {
|
export interface IOnMapTextRenderer {
|
||||||
/** 是否需要修改画布大小 */
|
|
||||||
readonly needResize: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改画布的缩放比例,传入的参数包含 `devicePixelRatio` 以及渲染器自身缩放比例
|
|
||||||
* @param width 画布宽度
|
|
||||||
* @param height 画布高度
|
|
||||||
* @param scaleX 画布横向比例
|
|
||||||
* @param scaleY 画布纵向比例
|
|
||||||
*/
|
|
||||||
resize(width: number, height: number, scaleX: number, scaleY: number): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染地图文字,返回的画布就是文字画到的画布
|
* 渲染地图文字,返回的画布就是文字画到的画布
|
||||||
*/
|
*/
|
||||||
render(data: IMapRenderResult): HTMLCanvasElement;
|
render(): HTMLCanvasElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 申请指定图块坐标的文字管理对象,如果该点已被申请,则会使用已申请的对象
|
* 申请指定图块坐标的文字管理对象
|
||||||
* @param x 图块横坐标
|
|
||||||
* @param y 图块纵坐标
|
|
||||||
* @returns 申请的文字管理对象,如果申请的坐标不在地图上,则会返回 `null`
|
|
||||||
*/
|
|
||||||
requireBlockArea(x: number, y: number): Readonly<IMapTextArea> | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据图块坐标获取已申请的文字管理对象,如果未申请则返回 `null`
|
|
||||||
* @param x 图块横坐标
|
* @param x 图块横坐标
|
||||||
* @param y 图块纵坐标
|
* @param y 图块纵坐标
|
||||||
*/
|
*/
|
||||||
getBlockByLoc(x: number, y: number): Readonly<IMapTextArea> | null;
|
requireBlockArea(x: number, y: number): Readonly<IMapTextArea>;
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据索引获取已申请的文字管理对象,如果未申请则返回 `null`
|
|
||||||
* @param index 管理对象索引
|
|
||||||
*/
|
|
||||||
getBlockByIndex(index: number): Readonly<IMapTextArea> | null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否需要更新
|
* 判断是否需要更新
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import {
|
|||||||
IMapRenderer,
|
IMapRenderer,
|
||||||
IMapRendererPostEffect,
|
IMapRendererPostEffect,
|
||||||
IMapRendererTicker,
|
IMapRendererTicker,
|
||||||
IMapRenderResult,
|
|
||||||
IMapVertexGenerator,
|
IMapVertexGenerator,
|
||||||
IMapViewportController,
|
IMapViewportController,
|
||||||
IMovingBlock,
|
IMovingBlock,
|
||||||
@ -218,7 +217,6 @@ export class MapRenderer
|
|||||||
this.canvas = document.createElement('canvas');
|
this.canvas = document.createElement('canvas');
|
||||||
this.gl = this.canvas.getContext('webgl2')!;
|
this.gl = this.canvas.getContext('webgl2')!;
|
||||||
this.transform = new Transform();
|
this.transform = new Transform();
|
||||||
this.transform.bind(this);
|
|
||||||
this.layerState = layerState;
|
this.layerState = layerState;
|
||||||
this.layerStateHook = layerState.addHook(
|
this.layerStateHook = layerState.addHook(
|
||||||
new RendererLayerStateHook(this)
|
new RendererLayerStateHook(this)
|
||||||
@ -1349,15 +1347,12 @@ export class MapRenderer
|
|||||||
this.updateRequired = true;
|
this.updateRequired = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): IMapRenderResult {
|
render(): HTMLCanvasElement {
|
||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
const data = this.contextData;
|
const data = this.contextData;
|
||||||
if (!this.assetData) {
|
if (!this.assetData) {
|
||||||
logger.error(31);
|
logger.error(31);
|
||||||
return {
|
return this.canvas;
|
||||||
canvas: this.canvas,
|
|
||||||
area: { blockList: [], dirty: [], render: [] }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -1517,7 +1512,7 @@ export class MapRenderer
|
|||||||
this.needUpdateOffsetPool = false;
|
this.needUpdateOffsetPool = false;
|
||||||
this.vertex.renderDynamic();
|
this.vertex.renderDynamic();
|
||||||
|
|
||||||
return { canvas: this.canvas, area };
|
return this.canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
@ -317,13 +317,6 @@ export interface IMapRendererPostEffect {
|
|||||||
): void;
|
): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapRenderResult {
|
|
||||||
/** 渲染结果所在的画布 */
|
|
||||||
readonly canvas: HTMLCanvasElement;
|
|
||||||
/** 渲染内容所包含的分块 */
|
|
||||||
readonly area: IMapRenderData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMapRenderer {
|
export interface IMapRenderer {
|
||||||
/** 地图渲染器使用的资源管理器 */
|
/** 地图渲染器使用的资源管理器 */
|
||||||
readonly manager: IMaterialManager;
|
readonly manager: IMaterialManager;
|
||||||
@ -397,7 +390,7 @@ export interface IMapRenderer {
|
|||||||
/**
|
/**
|
||||||
* 渲染地图
|
* 渲染地图
|
||||||
*/
|
*/
|
||||||
render(): IMapRenderResult;
|
render(): HTMLCanvasElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置地图的变换矩阵
|
* 设置地图的变换矩阵
|
||||||
@ -901,25 +894,6 @@ export interface IMapVertexBlock extends IMapVertexData {
|
|||||||
* @param layer 图层对象
|
* @param layer 图层对象
|
||||||
*/
|
*/
|
||||||
getLayerData(layer: IMapLayer): IMapVertexData | null;
|
getLayerData(layer: IMapLayer): IMapVertexData | null;
|
||||||
|
|
||||||
/**
|
|
||||||
* 在此分块上附着数据,一般用于拓展地图渲染,比如需要自定义分块渲染的场景
|
|
||||||
* @param symbol 附着数据的标识符
|
|
||||||
* @param data 附着数据内容
|
|
||||||
*/
|
|
||||||
attach<T>(symbol: symbol, data: T): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取这个分块上指定的附着数据
|
|
||||||
* @param symbol 附着数据的标识符
|
|
||||||
*/
|
|
||||||
getAttachedData<T>(symbol: symbol): T | undefined;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除这个分块上指定的附着数据
|
|
||||||
* @param symbol 附着数据的标识符
|
|
||||||
*/
|
|
||||||
deleteAttachedData(symbol: symbol): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapBlockUpdateObject {
|
export interface IMapBlockUpdateObject {
|
||||||
|
|||||||
@ -1042,14 +1042,9 @@ class MapVertexBlock implements IMapVertexBlock {
|
|||||||
|
|
||||||
readonly instancedStart: number;
|
readonly instancedStart: number;
|
||||||
|
|
||||||
/** 每个图层的渲染偏移量 */
|
|
||||||
private readonly indexMap: Map<IMapLayer, number> = new Map();
|
private readonly indexMap: Map<IMapLayer, number> = new Map();
|
||||||
/** 每个图层对应的实例化数组 */
|
|
||||||
private readonly instancedMap: Map<IMapLayer, Float32Array> = new Map();
|
private readonly instancedMap: Map<IMapLayer, Float32Array> = new Map();
|
||||||
|
|
||||||
/** 分块的附着数据 */
|
|
||||||
private readonly attachedData: Map<symbol, unknown> = new Map();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建分块的顶点数组对象,此对象不能动态扩展,如果地图变化,需要全部重建
|
* 创建分块的顶点数组对象,此对象不能动态扩展,如果地图变化,需要全部重建
|
||||||
* @param renderer 渲染器对象
|
* @param renderer 渲染器对象
|
||||||
@ -1166,18 +1161,6 @@ class MapVertexBlock implements IMapVertexBlock {
|
|||||||
this.instancedStart + index * this.count * INSTANCED_COUNT
|
this.instancedStart + index * this.count * INSTANCED_COUNT
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
attach<T>(symbol: symbol, data: T): void {
|
|
||||||
this.attachedData.set(symbol, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
getAttachedData<T>(symbol: symbol): T | undefined {
|
|
||||||
return this.attachedData.get(symbol) as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteAttachedData(symbol: symbol): void {
|
|
||||||
this.attachedData.delete(symbol);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
@ -4,10 +4,18 @@ import {
|
|||||||
IActionEvent,
|
IActionEvent,
|
||||||
MotaOffscreenCanvas2D,
|
MotaOffscreenCanvas2D,
|
||||||
Sprite,
|
Sprite,
|
||||||
onTick
|
onTick,
|
||||||
|
transformCanvas
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
// import { WeatherController } from '../weather';
|
import { WeatherController } from '../weather';
|
||||||
import { defineComponent, onUnmounted, reactive, ref } from 'vue';
|
import {
|
||||||
|
defineComponent,
|
||||||
|
onMounted,
|
||||||
|
onUnmounted,
|
||||||
|
reactive,
|
||||||
|
ref,
|
||||||
|
shallowRef
|
||||||
|
} from 'vue';
|
||||||
import { Textbox, Tip } from '../components';
|
import { Textbox, Tip } from '../components';
|
||||||
import { GameUI } from '@motajs/system-ui';
|
import { GameUI } from '@motajs/system-ui';
|
||||||
import {
|
import {
|
||||||
@ -31,8 +39,9 @@ import { getHeroStatusOn, state } from '@user/data-state';
|
|||||||
import { hook } from '@user/data-base';
|
import { hook } from '@user/data-base';
|
||||||
import { FloorChange } from '../legacy/fallback';
|
import { FloorChange } from '../legacy/fallback';
|
||||||
import { mainUIController } from './controller';
|
import { mainUIController } from './controller';
|
||||||
|
import { LayerGroup } from '../elements';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { mainMapExtension, mainMapRenderer } from '../commonIns';
|
import { mainMapRenderer } from '../commonIns';
|
||||||
|
|
||||||
const MainScene = defineComponent(() => {
|
const MainScene = defineComponent(() => {
|
||||||
//#region 基本定义
|
//#region 基本定义
|
||||||
@ -51,10 +60,17 @@ const MainScene = defineComponent(() => {
|
|||||||
width: MAP_WIDTH
|
width: MAP_WIDTH
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const map = shallowRef<LayerGroup>();
|
||||||
const hideStatus = ref(false);
|
const hideStatus = ref(false);
|
||||||
const locked = ref(false);
|
const locked = ref(false);
|
||||||
// const weather = new WeatherController();
|
const weather = new WeatherController();
|
||||||
// weather.extern('main');
|
weather.extern('main');
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (map.value) {
|
||||||
|
weather.bind(map.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const replayStatus: ReplayingStatus = reactive({
|
const replayStatus: ReplayingStatus = reactive({
|
||||||
replaying: false,
|
replaying: false,
|
||||||
@ -160,7 +176,9 @@ const MainScene = defineComponent(() => {
|
|||||||
|
|
||||||
const renderMapMisc = (canvas: MotaOffscreenCanvas2D) => {
|
const renderMapMisc = (canvas: MotaOffscreenCanvas2D) => {
|
||||||
const step = core.status.stepPostfix;
|
const step = core.status.stepPostfix;
|
||||||
if (!step) return;
|
const camera = map.value?.camera;
|
||||||
|
if (!step || !camera) return;
|
||||||
|
transformCanvas(canvas, camera);
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
ctx.fillStyle = '#fff';
|
ctx.fillStyle = '#fff';
|
||||||
step.forEach(({ x, y, direction }) => {
|
step.forEach(({ x, y, direction }) => {
|
||||||
@ -242,7 +260,6 @@ const MainScene = defineComponent(() => {
|
|||||||
<map-render
|
<map-render
|
||||||
renderer={mainMapRenderer}
|
renderer={mainMapRenderer}
|
||||||
layerState={state.layer}
|
layerState={state.layer}
|
||||||
extension={mainMapExtension}
|
|
||||||
loc={[0, 0, MAP_WIDTH, MAP_HEIGHT]}
|
loc={[0, 0, MAP_WIDTH, MAP_HEIGHT]}
|
||||||
/>
|
/>
|
||||||
<Textbox id="main-textbox" {...mainTextboxProps}></Textbox>
|
<Textbox id="main-textbox" {...mainTextboxProps}></Textbox>
|
||||||
|
|||||||
@ -116,7 +116,7 @@ export const GameTitle = defineComponent<GameTitleProps>(props => {
|
|||||||
const hard = main.levelChoose.map<ButtonOption>(v => {
|
const hard = main.levelChoose.map<ButtonOption>(v => {
|
||||||
return {
|
return {
|
||||||
code: v.hard,
|
code: v.hard,
|
||||||
color: core.arrayToRGBA(v.color!),
|
color: core.arrayToRGBA(v.color),
|
||||||
name: v.title,
|
name: v.title,
|
||||||
hard: v.name,
|
hard: v.name,
|
||||||
colorTrans: transitionedColor('#fff', 400, hyper('sin', 'out'))!,
|
colorTrans: transitionedColor('#fff', 400, hyper('sin', 'out'))!,
|
||||||
|
|||||||
@ -46,7 +46,6 @@
|
|||||||
"44": "Cannot bind face direction to main block $1, since main direction cannot be override.",
|
"44": "Cannot bind face direction to main block $1, since main direction cannot be override.",
|
||||||
"45": "Cannot add $1 map renderer extension, since $1 already exists for the given state.",
|
"45": "Cannot add $1 map renderer extension, since $1 already exists for the given state.",
|
||||||
"46": "Cannot execute close door action on $1,$2, since the given position is not empty.",
|
"46": "Cannot execute close door action on $1,$2, since the given position is not empty.",
|
||||||
"47": "Cannot require text area outside the target map.",
|
|
||||||
"1201": "Floor-damage extension needs 'floor-binder' extension as dependency."
|
"1201": "Floor-damage extension needs 'floor-binder' extension as dependency."
|
||||||
},
|
},
|
||||||
"warn": {
|
"warn": {
|
||||||
|
|||||||
@ -12,10 +12,10 @@ export type Props<
|
|||||||
> = T extends keyof JSX.IntrinsicElements
|
> = T extends keyof JSX.IntrinsicElements
|
||||||
? JSX.IntrinsicElements[T]
|
? JSX.IntrinsicElements[T]
|
||||||
: T extends DefineSetupFnComponent<any>
|
: T extends DefineSetupFnComponent<any>
|
||||||
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
||||||
: T extends DefineComponent
|
: T extends DefineComponent
|
||||||
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
||||||
: unknown;
|
: unknown;
|
||||||
|
|
||||||
export type ElementLocator = [
|
export type ElementLocator = [
|
||||||
x?: number,
|
x?: number,
|
||||||
|
|||||||
2
src/types/declaration/control.d.ts
vendored
2
src/types/declaration/control.d.ts
vendored
@ -1035,7 +1035,7 @@ interface Control {
|
|||||||
* @param bgm 背景音乐的文件名,支持全塔属性中映射前的中文名
|
* @param bgm 背景音乐的文件名,支持全塔属性中映射前的中文名
|
||||||
* @param startTime 跳过前多少秒
|
* @param startTime 跳过前多少秒
|
||||||
*/
|
*/
|
||||||
playBgm(bgm: BgmIds, startTime?: number): void;
|
playBgm(bgm: BgmIds | NameMapIn<BgmIds>, startTime?: number): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated 可使用,考虑换用新的 `BgmController` 接口\
|
* @deprecated 可使用,考虑换用新的 `BgmController` 接口\
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user