Compare commits

...

2 Commits

Author SHA1 Message Date
8eadffffea feat: 地图文字类型标注 2026-02-28 20:14:06 +08:00
3917b29510 fix: 停止移动时同时停止跟随者 2026-02-28 20:13:49 +08:00
3 changed files with 153 additions and 13 deletions

View File

@ -298,16 +298,11 @@ export class MapHeroRenderer implements IMapHeroRenderer {
this.entities.forEach(v => this.endEntityMoving(v));
}
stopMove(stopFollower: boolean): void {
if (stopFollower) {
this.entities.forEach(v => {
v.block.endMoving();
this.endEntityMoving(v);
});
} else {
this.heroEntity.block.endMoving();
this.endEntityMoving(this.heroEntity);
}
stopMove(): void {
this.entities.forEach(v => {
v.block.endMoving();
this.endEntityMoving(v);
});
}
async move(direction: FaceDirection, time: number): Promise<void> {

View File

@ -0,0 +1,63 @@
import { IMapRenderer } from '../types';
import { IMapTextArea, IMapTextRenderable, IOnMapTextRenderer } from './types';
export class OnMapTextRenderer implements IOnMapTextRenderer {
/** 画布元素 */
readonly canvas: HTMLCanvasElement;
/** 画布 Canvas2D 上下文 */
readonly ctx: CanvasRenderingContext2D;
/** 图块索引到图块文本对象的映射 */
readonly areaMap: Map<number, MapTextArea> = new Map();
private dirty: boolean = false;
constructor(readonly renderer: IMapRenderer) {
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d')!;
}
render(): HTMLCanvasElement {
return this.canvas;
}
requireBlockArea(x: number, y: number): Readonly<IMapTextArea> {
const index = y * this.renderer.mapWidth + x;
const exist = this.areaMap.get(index);
if (exist) return exist;
const area = new MapTextArea(this, x, y);
this.areaMap.set(index, area);
return area;
}
needUpdate(): boolean {
return this.dirty;
}
clear(): void {}
destroy(): void {}
}
class MapTextArea implements IMapTextArea {
index: number;
constructor(
readonly renderer: OnMapTextRenderer,
public mapX: number,
public mapY: number
) {
this.index = mapY * renderer.renderer.mapWidth + mapX;
}
addTextRenderable(renderable: IMapTextRenderable): void {
throw new Error('Method not implemented.');
}
removeTextRenderable(renderable: IMapTextRenderable): void {
throw new Error('Method not implemented.');
}
clear(): void {
throw new Error('Method not implemented.');
}
}

View File

@ -5,6 +5,7 @@ import {
IHeroState,
IMapLayer
} from '@user/data-state';
import { Font } from '@motajs/render-style';
export interface IMapExtensionManager {
/**
@ -79,10 +80,9 @@ export interface IMapHeroRenderer {
waitMoveEnd(waitFollower: boolean): Promise<void>;
/**
*
* @param stopFollower
*
*/
stopMove(stopFollower: boolean): void;
stopMove(): void;
/**
*
@ -162,3 +162,85 @@ export interface IMapDoorRenderer {
*/
destroy(): void;
}
export interface IMapTextRenderable {
/** 文本内容 */
readonly text: string;
/** 文本字体 */
readonly font: Font;
/** 文本填充样式 */
readonly fillStyle: CanvasStyle;
/** 文本描边样式 */
readonly strokeStyle: CanvasStyle;
/** 文本横坐标,注意 {@link IMapTextArea.addTextRenderable} 的相对关系 */
readonly px: number;
/** 文本纵坐标,注意 {@link IMapTextArea.addTextRenderable} 的相对关系 */
readonly py: number;
/** 文本横向对齐方式 */
readonly textAlign: CanvasTextAlign;
/** 文本纵向对齐方式 */
readonly textBaseline: CanvasTextBaseline;
}
export interface IMapTextRequested {
/**
*
* @param blocks
*/
requestBlocks(blocks: IMapTextArea[]): void;
}
export interface IMapTextArea {
/** 图块在地图上的索引 */
index: number;
/** 图块横坐标 */
mapX: number;
/** 图块纵坐标 */
mapY: number;
/**
*
* @param renderable
*/
addTextRenderable(renderable: IMapTextRenderable): void;
/**
*
* @param renderable
*/
removeTextRenderable(renderable: IMapTextRenderable): void;
/**
*
*/
clear(): void;
}
export interface IOnMapTextRenderer {
/**
*
*/
render(): HTMLCanvasElement;
/**
*
* @param x
* @param y
*/
requireBlockArea(x: number, y: number): Readonly<IMapTextArea>;
/**
*
*/
needUpdate(): boolean;
/**
*
*/
clear(): void;
/**
*
*/
destroy(): void;
}