From 1c27014ab326c7a1619df38eeb7f8ef82ae9def4 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 25 Nov 2025 23:49:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=BB=98=E8=AE=A4=E5=B8=A7=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client-base/src/material/fallback.ts | 7 ++- .../client-base/src/material/manager.ts | 33 ++++++++++---- .../client-base/src/material/types.ts | 39 +++++++++++----- .../src/render/map/shader/map.frag | 1 - .../client-modules/src/render/map/vertex.ts | 44 ++++++++++++++----- 5 files changed, 90 insertions(+), 34 deletions(-) diff --git a/packages-user/client-base/src/material/fallback.ts b/packages-user/client-base/src/material/fallback.ts index 5dcabf5..6b3444a 100644 --- a/packages-user/client-base/src/material/fallback.ts +++ b/packages-user/client-base/src/material/fallback.ts @@ -1,6 +1,7 @@ import { ITexture } from '@motajs/render-assets'; import { materials } from './ins'; import { IBlockIdentifier, IIndexedIdentifier } from './types'; +import { isNil } from 'lodash-es'; function extractClsBlocks>( cls: C, @@ -52,7 +53,11 @@ export function fallbackLoad() { const idNumMap: Record = {}; for (const [key, value] of Object.entries(core.maps.blocksInfo)) { - idNumMap[value.id] = Number(key); + const num = Number(key); + idNumMap[value.id] = Number(num); + if (!isNil(value.animate)) { + materials.setDefaultFrame(num, value.animate - 1); + } } const terrains = extractClsBlocks('terrains', idNumMap, icons.terrains); diff --git a/packages-user/client-base/src/material/manager.ts b/packages-user/client-base/src/material/manager.ts index 36b4c5e..5c23611 100644 --- a/packages-user/client-base/src/material/manager.ts +++ b/packages-user/client-base/src/material/manager.ts @@ -65,6 +65,8 @@ export class MaterialManager implements IMaterialManager { readonly numIdMap: Map = new Map(); /** 图块数字到图块类型的映射 */ readonly clsMap: Map = new Map(); + /** 图块的默认帧数 */ + readonly defaultFrames: Map = new Map(); /** 网格切分器 */ readonly gridSplitter: TextureGridSplitter = new TextureGridSplitter(); @@ -218,7 +220,19 @@ export class MaterialManager implements IMaterialManager { return data; } - getTile(identifier: number): IMaterialFramedData | null { + setDefaultFrame(identifier: number, defaultFrame: number): void { + this.defaultFrames.set(identifier, defaultFrame); + const bigImageData = this.bigImageData.get(identifier); + if (bigImageData) { + bigImageData.defaultFrame = defaultFrame; + } + } + + getDefaultFrame(identifier: number): number { + return this.defaultFrames.get(identifier) ?? -1; + } + + getTile(identifier: number): Readonly | null { if (identifier < 10000) { const cls = this.clsMap.get(identifier) ?? BlockCls.Unknown; if ( @@ -233,7 +247,8 @@ export class MaterialManager implements IMaterialManager { texture, cls, offset: 32, - frames: getTextureFrame(cls, texture) + frames: getTextureFrame(cls, texture), + defaultFrame: this.defaultFrames.get(identifier) ?? -1 }; } else { const texture = this.cacheTileset(identifier); @@ -242,7 +257,8 @@ export class MaterialManager implements IMaterialManager { texture, cls: BlockCls.Tileset, offset: 32, - frames: 1 + frames: 1, + defaultFrame: -1 }; } } @@ -255,7 +271,7 @@ export class MaterialManager implements IMaterialManager { return this.imageStore.getTexture(identifier); } - getTileByAlias(alias: string): IMaterialFramedData | null { + getTileByAlias(alias: string): Readonly | null { if (/X\d{5,}/.test(alias)) { return this.getTile(parseInt(alias.slice(1))); } else { @@ -537,7 +553,8 @@ export class MaterialManager implements IMaterialManager { texture: image, cls, offset: image.width / 4, - frames + frames, + defaultFrame: this.defaultFrames.get(identifier) ?? -1 }; this.bigImageData.set(identifier, store); const data: IBigImageReturn = { @@ -551,17 +568,17 @@ export class MaterialManager implements IMaterialManager { return this.bigImageData.has(identifier); } - getBigImage(identifier: number): IMaterialFramedData | null { + getBigImage(identifier: number): Readonly | null { return this.bigImageData.get(identifier) ?? null; } - getBigImageByAlias(alias: string): IMaterialFramedData | null { + getBigImageByAlias(alias: string): Readonly | null { const identifier = this.idNumMap.get(alias); if (isNil(identifier)) return null; return this.bigImageData.get(identifier) ?? null; } - getIfBigImage(identifier: number): IMaterialFramedData | null { + getIfBigImage(identifier: number): Readonly | null { const bigImage = this.bigImageData.get(identifier); if (bigImage) return bigImage; else return this.getTile(identifier); diff --git a/packages-user/client-base/src/material/types.ts b/packages-user/client-base/src/material/types.ts index 4903795..ab02e46 100644 --- a/packages-user/client-base/src/material/types.ts +++ b/packages-user/client-base/src/material/types.ts @@ -90,13 +90,15 @@ export interface IBigImageReturn { export interface IMaterialFramedData { /** 贴图对象 */ - readonly texture: ITexture; + texture: ITexture; /** 图块类型 */ - readonly cls: BlockCls; + cls: BlockCls; /** 贴图总帧数 */ - readonly frames: number; + frames: number; /** 每帧的横向偏移量 */ - readonly offset: number; + offset: number; + /** 默认帧数 */ + defaultFrame: number; } export interface IMaterialAsset @@ -160,7 +162,7 @@ export interface IAutotileProcessor { * @returns 连接方式的可渲染对象,可以通过偏移量依次获取其他帧 */ renderWith( - tile: IMaterialFramedData, + tile: Readonly, connection: number ): ITextureRenderable | null; @@ -171,7 +173,7 @@ export interface IAutotileProcessor { * @returns 连接方式的可渲染对象,可以通过偏移量依次获取其他帧 */ renderWithoutCheck( - tile: IMaterialFramedData, + tile: Readonly, connection: number ): ITextureRenderable | null; @@ -193,7 +195,7 @@ export interface IAutotileProcessor { * @returns 生成器,每一个输出代表每一帧的渲染对象,不同自动元件的帧数可能不同 */ renderAnimatedWith( - tile: IMaterialFramedData, + tile: Readonly, connection: number ): Generator; } @@ -203,7 +205,7 @@ export interface IMaterialGetter { * 根据图块数字获取图块,可以获取额外素材,会自动将未缓存的额外素材缓存 * @param identifier 图块的图块数字 */ - getTile(identifier: number): IMaterialFramedData | null; + getTile(identifier: number): Readonly | null; /** * 根据图块标识符获取图块类型 @@ -221,14 +223,14 @@ export interface IMaterialGetter { * 根据图块标识符获取一个图块的 `bigImage` 贴图 * @param identifier 图块标识符,即图块数字 */ - getBigImage(identifier: number): IMaterialFramedData | null; + getBigImage(identifier: number): Readonly | null; /** * 根据图块标识符,首先判断是否是 `bigImage` 贴图,如果是,则返回 `bigImage` 贴图, * 否则返回普通贴图。如果图块不存在,则返回 `null` * @param identifier 图块标识符,即图块数字 */ - getIfBigImage(identifier: number): IMaterialFramedData | null; + getIfBigImage(identifier: number): Readonly | null; /** * 根据标识符获取图集信息 @@ -254,7 +256,7 @@ export interface IMaterialAliasGetter { * 根据图块 id 获取图块,可以获取额外素材,会自动将未缓存的额外素材缓存 * @param alias 图块 id */ - getTileByAlias(alias: string): IMaterialFramedData | null; + getTileByAlias(alias: string): Readonly | null; /** * 根据额外素材名称获取额外素材 @@ -284,7 +286,7 @@ export interface IMaterialAliasGetter { * 根据图块别名获取一个图块的 `bigImage` 贴图 * @param alias 图块别名,即图块的 id */ - getBigImageByAlias(alias: string): IMaterialFramedData | null; + getBigImageByAlias(alias: string): Readonly | null; } export interface IMaterialManager @@ -364,6 +366,19 @@ export interface IMaterialManager identifier: IIndexedIdentifier ): IMaterialData; + /** + * 设置指定图块默认显示第几帧 + * @param identifier 图块标识符,即图块数字 + * @param defaultFrame 图块的默认帧数 + */ + setDefaultFrame(identifier: number, defaultFrame: number): void; + + /** + * 获取图块的默认帧数,-1 表示正常动画,非负整数表示默认使用指定帧数,除非单独指定 + * @param identifier 图块标识符,即图块数字 + */ + getDefaultFrame(identifier: number): number; + /** * 缓存某个 tileset,当需要缓存多个时,请使用 {@link cacheTilesetList} 方法 * @param identifier tileset 的标识符,即图块数字 diff --git a/packages-user/client-modules/src/render/map/shader/map.frag b/packages-user/client-modules/src/render/map/shader/map.frag index 231de34..360bf3e 100644 --- a/packages-user/client-modules/src/render/map/shader/map.frag +++ b/packages-user/client-modules/src/render/map/shader/map.frag @@ -14,5 +14,4 @@ void main() { // todo: 透明像素应该如何解决?? if (alpha < 0.1) discard; outColor = vec4(texColor.rgb, alpha); - // outColor = vec4(texColor.a * 0.001, v_texCoord.x * 6.0, v_texCoord.y * 0.0, v_texCoord.a); } diff --git a/packages-user/client-modules/src/render/map/vertex.ts b/packages-user/client-modules/src/render/map/vertex.ts index b62863d..72822a9 100644 --- a/packages-user/client-modules/src/render/map/vertex.ts +++ b/packages-user/client-modules/src/render/map/vertex.ts @@ -44,6 +44,8 @@ export interface IMapDataGetter { } interface BlockMapPos { + /** 图块的图块数字 */ + readonly num: number; /** 地图中的横坐标 */ readonly mapX: number; /** 地图中的纵坐标 */ @@ -77,11 +79,15 @@ interface VertexArrayOfBlock { const enum VertexUpdate { /** 更新顶点位置信息 */ - Position = 0b01, + Position = 0b001, /** 更新贴图信息 */ - Texture = 0b10, + Texture = 0b010, + /** 是否更新默认帧数 */ + Frame = 0b100, + /** 除帧数外全部更新 */ + NoFrame = 0b011, /** 全部更新 */ - All = 0b11 + All = 0b111 } /** @@ -153,6 +159,7 @@ export class MapVertexGenerator staticCount * INSTANCED_COUNT, count * INSTANCED_COUNT ); + // 不透明度默认是 1,帧数默认是 -1 for (let i = 0; i < count; i++) { const start = i * INSTANCED_COUNT; this.instancedArray[start + 9] = 1; @@ -405,6 +412,12 @@ export class MapVertexGenerator instancedArray[startIndex + 14] = offsetIndex; instancedArray[startIndex + 15] = assetIndex; } + if (update & VertexUpdate.Frame) { + const defaultFrame = this.renderer.manager.getDefaultFrame( + index.num + ); + instancedArray[startIndex + 12] = defaultFrame; + } } /** @@ -473,11 +486,14 @@ export class MapVertexGenerator if (!vertex) return; const bx = mx - block.dataX; const by = my - block.dataY; + const mapIndex = my * this.mapWidth + mx; + const num = mapArray[mapIndex]; const newIndex: BlockIndex = { layer, + num, mapX: mx, mapY: my, - mapIndex: my * this.mapWidth + mx, + mapIndex, blockX: bx, blockY: by, blockIndex: by * block.width + bx @@ -489,6 +505,7 @@ export class MapVertexGenerator vertex, newIndex, tile, + // 周围一圈的自动元件应该只更新贴图,不需要更新位置和默认帧数 VertexUpdate.Texture, false ); @@ -525,6 +542,7 @@ export class MapVertexGenerator return; } + // todo: 这样的话,如果更新了指定分块,那么本来设置的帧数也会重置为默认帧数,如何修改? if (tile.cls === BlockCls.Autotile) { // 如果图块是自动元件 this.updateAutotile( @@ -532,6 +550,7 @@ export class MapVertexGenerator vertex, index, tile, + // 图块变了,所以全部要更新 VertexUpdate.All, dynamic ); @@ -560,6 +579,7 @@ export class MapVertexGenerator assetIndex, offsetIndex, tile.frames, + // 图块变了,所以全部要更新 VertexUpdate.All, dynamic ); @@ -590,6 +610,7 @@ export class MapVertexGenerator const dIndex = dy * block.width + dx; const index: BlockIndex = { layer, + num, mapX: x, mapY: y, mapIndex: y * this.mapWidth + x, @@ -790,8 +811,10 @@ export class MapVertexGenerator const mapX = nx + block.dataX; const mapY = ny + block.dataY; const mapIndex = mapY * this.mapWidth + mapX; + const num = array[mapIndex]; const index: BlockIndex = { layer, + num, blockX: nx, blockY: ny, blockIndex: ny * block.width + nx, @@ -799,13 +822,7 @@ export class MapVertexGenerator mapY, mapIndex }; - this.updateVertexArray( - array, - vertex, - index, - array[mapIndex], - false - ); + this.updateVertexArray(array, vertex, index, num, false); } } }); @@ -823,6 +840,7 @@ export class MapVertexGenerator }; const index: IndexedBlockMapPos = { layer: block.layer, + num: block.tile, mapX: block.x, mapY: block.y, blockIndex: block.index @@ -833,7 +851,9 @@ export class MapVertexGenerator logger.error(40, block.tile.toString()); return; } - const update = updateTexture ? VertexUpdate.All : VertexUpdate.Position; + const update = updateTexture + ? VertexUpdate.NoFrame + : VertexUpdate.Position; if (cls === BlockCls.Autotile) { // 自动元件使用全部不连接 const renderable = this.renderer.autotile.renderWithoutCheck(