feat: scan animater & refactor: 动画输出类型

This commit is contained in:
unanmed 2025-10-20 12:18:37 +08:00
parent fc1c0b14d6
commit 77246b571a
5 changed files with 117 additions and 49 deletions

View File

@ -105,6 +105,7 @@
"71": "Cannot start animate when animater not created on texture.", "71": "Cannot start animate when animater not created on texture.",
"72": "Frame count delivered to frame-based animater need to exactly divide texture's height.", "72": "Frame count delivered to frame-based animater need to exactly divide texture's height.",
"73": "Consistent size is needed when using WebGL2 composer.", "73": "Consistent size is needed when using WebGL2 composer.",
"74": "Frame size not match texture's size, incomplete data will be skipped.",
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency.", "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." "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."
} }

View File

@ -1,10 +1,5 @@
import { logger } from '@motajs/common'; import { logger } from '@motajs/common';
import { import { IRect, ITexture, ITextureAnimater, ITextureRenderable } from './types';
IRect,
ITexture,
ITextureAnimater,
ITextureListedRenderable
} from './types';
/** /**
* *
@ -41,31 +36,31 @@ export abstract class FrameBasedAnimater<T>
return true; return true;
} }
abstract open(init: T): Generator<ITextureListedRenderable> | null; abstract open(init: T): Generator<ITextureRenderable> | null;
abstract cycled(init: T): Generator<ITextureListedRenderable> | null; abstract cycled(init: T): Generator<ITextureRenderable> | null;
} }
/** /**
* *
*/ */
export class TextureRowAnimater extends FrameBasedAnimater<void> { export class TextureRowAnimater extends FrameBasedAnimater<void> {
*open(): Generator<ITextureListedRenderable> | null { *open(): Generator<ITextureRenderable> | null {
if (!this.check()) return null; if (!this.check()) return null;
const renderable = this.texture!.static(); const renderable = this.texture!.static();
const { x: ox, y: oy } = renderable.rect; const { x: ox, y: oy } = renderable.rect;
const { width: w, height } = this.texture!; const { width: w, height } = this.texture!;
const h = height / this.frames; const h = height / this.frames;
for (let i = 0; i < this.frames; i++) { for (let i = 0; i < this.frames; i++) {
const renderable: ITextureListedRenderable = { const renderable: ITextureRenderable = {
source: this.texture!.source, source: this.texture!.source,
rect: [{ x: ox, y: i * h + oy, w, h }] rect: { x: ox, y: i * h + oy, w, h }
}; };
yield renderable; yield renderable;
} }
} }
*cycled(): Generator<ITextureListedRenderable> | null { *cycled(): Generator<ITextureRenderable> | null {
if (!this.check()) return null; if (!this.check()) return null;
const renderable = this.texture!.static(); const renderable = this.texture!.static();
const { x: ox, y: oy } = renderable.rect; const { x: ox, y: oy } = renderable.rect;
@ -74,9 +69,9 @@ export class TextureRowAnimater extends FrameBasedAnimater<void> {
let i = 0; let i = 0;
while (true) { while (true) {
if (i === this.frames) i = 0; if (i === this.frames) i = 0;
const renderable: ITextureListedRenderable = { const renderable: ITextureRenderable = {
source: this.texture!.source, source: this.texture!.source,
rect: [{ x: ox, y: i * h + oy, w, h }] rect: { x: ox, y: i * h + oy, w, h }
}; };
yield renderable; yield renderable;
} }
@ -87,22 +82,22 @@ export class TextureRowAnimater extends FrameBasedAnimater<void> {
* *
*/ */
export class TextureColumnAnimater extends FrameBasedAnimater<void> { export class TextureColumnAnimater extends FrameBasedAnimater<void> {
*open(): Generator<ITextureListedRenderable> | null { *open(): Generator<ITextureRenderable> | null {
if (!this.check()) return null; if (!this.check()) return null;
const renderable = this.texture!.static(); const renderable = this.texture!.static();
const { x: ox, y: oy } = renderable.rect; const { x: ox, y: oy } = renderable.rect;
const { width, height: h } = this.texture!; const { width, height: h } = this.texture!;
const w = width / this.frames; const w = width / this.frames;
for (let i = 0; i < this.frames; i++) { for (let i = 0; i < this.frames; i++) {
const renderable: ITextureListedRenderable = { const renderable: ITextureRenderable = {
source: this.texture!.source, source: this.texture!.source,
rect: [{ x: i * width + ox, y: oy, w, h }] rect: { x: i * width + ox, y: oy, w, h }
}; };
yield renderable; yield renderable;
} }
} }
*cycled(): Generator<ITextureListedRenderable> | null { *cycled(): Generator<ITextureRenderable> | null {
if (!this.check()) return null; if (!this.check()) return null;
const renderable = this.texture!.static(); const renderable = this.texture!.static();
const { x: ox, y: oy } = renderable.rect; const { x: ox, y: oy } = renderable.rect;
@ -111,15 +106,92 @@ export class TextureColumnAnimater extends FrameBasedAnimater<void> {
let i = 0; let i = 0;
while (true) { while (true) {
if (i === this.frames) i = 0; if (i === this.frames) i = 0;
const renderable: ITextureListedRenderable = { const renderable: ITextureRenderable = {
source: this.texture!.source, source: this.texture!.source,
rect: [{ x: i * w + ox, y: oy, w, h }] rect: { x: i * w + ox, y: oy, w, h }
}; };
yield renderable; yield renderable;
} }
} }
} }
export interface IScanAnimaterCreate {
/** 每帧的宽度 */
readonly width: number;
/** 每帧的高度 */
readonly height: number;
/** 总帧数 */
readonly frames: number;
}
/**
*
*/
export class TextureScanAnimater
implements ITextureAnimater<IScanAnimaterCreate, void>
{
texture: ITexture<IScanAnimaterCreate, void> | null = null;
private width: number = 0;
private height: number = 0;
private frames: number = 0;
private frameX: number = 0;
private frameY: number = 0;
create(texture: ITexture, data: IScanAnimaterCreate): void {
if (this.texture) {
logger.warn(70);
return;
}
this.texture = texture;
this.width = data.width;
this.height = data.height;
this.frames = data.frames;
// 如果尺寸不匹配
if (
texture.width % data.width !== 0 ||
texture.height % data.height !== 0
) {
logger.warn(74);
}
const frameX = Math.floor(texture.width / data.width);
const frameY = Math.floor(texture.height / data.height);
const possibleFrames = frameX * frameY;
// 如果传入的帧数超出了可能的帧数上限
if (this.frames > possibleFrames) {
this.frames = possibleFrames;
}
}
*open(): Generator<ITextureRenderable, void> | null {
const texture = this.texture;
if (!texture) return null;
const w = this.width;
const h = this.height;
for (let y = 0; y < this.frameY; y++) {
for (let x = 0; x < this.frameX; x++) {
const rect: IRect = { x: x * w, y: y * h, w, h };
const data: ITextureRenderable = {
source: texture.source,
rect
};
yield data;
}
}
}
cycled(): Generator<ITextureRenderable, void> | null {
throw new Error('Method not implemented.');
}
}
export interface IAnimaterTranslatedInit<T> { export interface IAnimaterTranslatedInit<T> {
/** 以此矩形作为参考矩形 */ /** 以此矩形作为参考矩形 */
readonly rect: Readonly<IRect>; readonly rect: Readonly<IRect>;
@ -141,11 +213,15 @@ export class TextureAnimaterTranslated<T> implements AdderImplements<T> {
texture: AdderTexture<T> | null = null; texture: AdderTexture<T> | null = null;
create(texture: ITexture): void { create(texture: ITexture): void {
if (this.texture) {
logger.warn(70);
return;
}
this.texture = texture; this.texture = texture;
} }
*output( *output(
ani: Generator<ITextureListedRenderable>, ani: Generator<ITextureRenderable>,
origin: Readonly<IRect>, origin: Readonly<IRect>,
rect: Readonly<IRect> rect: Readonly<IRect>
) { ) {
@ -157,13 +233,11 @@ export class TextureAnimaterTranslated<T> implements AdderImplements<T> {
const next = ani.next(); const next = ani.next();
if (next.done) break; if (next.done) break;
const renderable = next.value; const renderable = next.value;
const list: IRect[] = []; const { x, y, w, h } = renderable.rect;
renderable.rect.forEach(({ x, y, w, h }) => { const translated: IRect = { x: x - ox + nx, y: y - oy + ny, w, h };
list.push({ x: x - ox + nx, y: y - oy + ny, w, h }); const res: ITextureRenderable = {
});
const res: ITextureListedRenderable = {
source, source,
rect: list rect: translated
}; };
yield res; yield res;
} }
@ -171,7 +245,7 @@ export class TextureAnimaterTranslated<T> implements AdderImplements<T> {
open( open(
init: IAnimaterTranslatedInit<T> init: IAnimaterTranslatedInit<T>
): Generator<ITextureListedRenderable> | null { ): Generator<ITextureRenderable> | null {
const ani = init.texture.dynamic(init.data); const ani = init.texture.dynamic(init.data);
const origin = init.texture.static().rect; const origin = init.texture.static().rect;
if (!ani || !origin) return null; if (!ani || !origin) return null;
@ -180,7 +254,7 @@ export class TextureAnimaterTranslated<T> implements AdderImplements<T> {
cycled( cycled(
init: IAnimaterTranslatedInit<T> init: IAnimaterTranslatedInit<T>
): Generator<ITextureListedRenderable> | null { ): Generator<ITextureRenderable> | null {
const ani = init.texture.cycled(init.data); const ani = init.texture.cycled(init.data);
const origin = init.texture.static().rect; const origin = init.texture.static().rect;
if (!ani || !origin) return null; if (!ani || !origin) return null;

View File

@ -55,7 +55,8 @@ interface GridNeededSize {
} }
/** /**
* *
*
*/ */
export class TextureGridComposer<T> export class TextureGridComposer<T>
implements TranslatedComposer<IGridComposerData, T> implements TranslatedComposer<IGridComposerData, T>

View File

@ -2,8 +2,7 @@ import { logger } from '@motajs/common';
import { import {
ITexture, ITexture,
ITextureAnimater, ITextureAnimater,
ITextureListedRenderable, ITextureRenderable,
ITextureSingleRenderable,
ITextureSplitter, ITextureSplitter,
SizedCanvasImageSource SizedCanvasImageSource
} from './types'; } from './types';
@ -63,20 +62,20 @@ export class Texture<T = unknown, A = unknown> implements ITexture<T, A> {
animater.create(this, data); animater.create(this, data);
} }
static(): ITextureSingleRenderable { static(): ITextureRenderable {
const renderable: ITextureSingleRenderable = { const renderable: ITextureRenderable = {
source: this.source, source: this.source,
rect: { x: this.cx, y: this.cy, w: this.width, h: this.height } rect: { x: this.cx, y: this.cy, w: this.width, h: this.height }
}; };
return renderable; return renderable;
} }
dynamic(data: A): Generator<ITextureListedRenderable> | null { dynamic(data: A): Generator<ITextureRenderable> | null {
if (!this.animater) return null; if (!this.animater) return null;
return this.animater.open(data); return this.animater.open(data);
} }
cycled(data: A): Generator<ITextureListedRenderable> | null { cycled(data: A): Generator<ITextureRenderable> | null {
if (!this.animater) return null; if (!this.animater) return null;
return this.animater.cycled(data); return this.animater.cycled(data);
} }

View File

@ -12,20 +12,13 @@ export interface IRect {
h: number; h: number;
} }
export interface ITextureSingleRenderable { export interface ITextureRenderable {
/** 可渲染贴图对象的图像源 */ /** 可渲染贴图对象的图像源 */
readonly source: SizedCanvasImageSource; readonly source: SizedCanvasImageSource;
/** 贴图裁剪区域 */ /** 贴图裁剪区域 */
readonly rect: Readonly<IRect>; readonly rect: Readonly<IRect>;
} }
export interface ITextureListedRenderable {
/** 可渲染贴图对象的图像源 */
readonly source: SizedCanvasImageSource;
/** 贴图裁剪区域 */
readonly rect: Readonly<IRect>[];
}
export interface ITextureComposedData<T = unknown, A = unknown> { export interface ITextureComposedData<T = unknown, A = unknown> {
/** 这个纹理图集的贴图对象 */ /** 这个纹理图集的贴图对象 */
readonly texture: ITexture<T, A>; readonly texture: ITexture<T, A>;
@ -69,13 +62,13 @@ export interface ITextureAnimater<T, I> {
* *
* @param init * @param init
*/ */
open(init: I): Generator<ITextureListedRenderable, void> | null; open(init: I): Generator<ITextureRenderable, void> | null;
/** /**
* *
* @param init * @param init
*/ */
cycled(init: I): Generator<ITextureListedRenderable, void> | null; cycled(init: I): Generator<ITextureRenderable, void> | null;
} }
export interface ITexture<T = unknown, A = unknown> { export interface ITexture<T = unknown, A = unknown> {
@ -111,19 +104,19 @@ export interface ITexture<T = unknown, A = unknown> {
/** /**
* *
*/ */
static(): ITextureSingleRenderable; static(): ITextureRenderable;
/** /**
* *
* @param data * @param data
*/ */
dynamic(data: A): Generator<ITextureListedRenderable, void> | null; dynamic(data: A): Generator<ITextureRenderable, void> | null;
/** /**
* *
* @param data * @param data
*/ */
cycled(data: A): Generator<ITextureListedRenderable, void> | null; cycled(data: A): Generator<ITextureRenderable, void> | null;
/** /**
* 使 * 使