You've already forked Nitro_Render_V3
mirror of
https://github.com/duckietm/Nitro_Render_V3.git
synced 2026-06-20 07:26:18 +00:00
☁️ Fase 1 done, adding animated landscapes
This commit is contained in:
@@ -14,10 +14,11 @@ export class RoomContentLoader implements IRoomContentLoader
|
|||||||
private static PLACE_HOLDER_PET: string = 'place_holder_pet';
|
private static PLACE_HOLDER_PET: string = 'place_holder_pet';
|
||||||
private static PLACE_HOLDER_DEFAULT: string = RoomContentLoader.PLACE_HOLDER;
|
private static PLACE_HOLDER_DEFAULT: string = RoomContentLoader.PLACE_HOLDER;
|
||||||
private static ROOM: string = 'room';
|
private static ROOM: string = 'room';
|
||||||
|
private static LANDSCAPE: string = 'landscape';
|
||||||
private static TILE_CURSOR: string = 'tile_cursor';
|
private static TILE_CURSOR: string = 'tile_cursor';
|
||||||
private static SELECTION_ARROW: string = 'selection_arrow';
|
private static SELECTION_ARROW: string = 'selection_arrow';
|
||||||
|
|
||||||
public static MANDATORY_LIBRARIES: string[] = [RoomContentLoader.PLACE_HOLDER, RoomContentLoader.PLACE_HOLDER_WALL, RoomContentLoader.PLACE_HOLDER_PET, RoomContentLoader.ROOM, RoomContentLoader.TILE_CURSOR, RoomContentLoader.SELECTION_ARROW];
|
public static MANDATORY_LIBRARIES: string[] = [RoomContentLoader.PLACE_HOLDER, RoomContentLoader.PLACE_HOLDER_WALL, RoomContentLoader.PLACE_HOLDER_PET, RoomContentLoader.ROOM, RoomContentLoader.LANDSCAPE, RoomContentLoader.TILE_CURSOR, RoomContentLoader.SELECTION_ARROW];
|
||||||
|
|
||||||
private _iconListener: IRoomContentListener;
|
private _iconListener: IRoomContentListener;
|
||||||
private _images: Map<string, HTMLImageElement> = new Map();
|
private _images: Map<string, HTMLImageElement> = new Map();
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { IAssetPlaneVisualizationLayer, IAssetRoomVisualizationData, IRoomGeometry, IRoomPlane, IVector3D } from '@nitrots/api';
|
import { IAssetPlaneVisualizationAnimatedLayer, IAssetPlaneVisualizationLayer, IAssetRoomVisualizationData, IRoomGeometry, IRoomPlane, IVector3D } from '@nitrots/api';
|
||||||
import { GetAssetManager } from '@nitrots/assets';
|
import { GetAssetManager } from '@nitrots/assets';
|
||||||
import { GetRenderer, GetTexturePool, PlaneMaskFilter, Vector3d } from '@nitrots/utils';
|
import { GetRenderer, GetTexturePool, PlaneMaskFilter, Vector3d } from '@nitrots/utils';
|
||||||
import { Container, Filter, Matrix, Point, Sprite, Texture, TilingSprite } from 'pixi.js';
|
import { Container, Filter, Graphics, Matrix, Point, RenderTexture, Sprite, Texture, TilingSprite } from 'pixi.js';
|
||||||
import { RoomGeometry } from '../../../utils';
|
import { RoomGeometry } from '../../../utils';
|
||||||
|
import { PlaneVisualizationAnimationLayer } from './animated';
|
||||||
import { RoomPlaneBitmapMask } from './RoomPlaneBitmapMask';
|
import { RoomPlaneBitmapMask } from './RoomPlaneBitmapMask';
|
||||||
import { RoomPlaneRectangleMask } from './RoomPlaneRectangleMask';
|
import { RoomPlaneRectangleMask } from './RoomPlaneRectangleMask';
|
||||||
import { PlaneMaskManager } from './mask';
|
import { PlaneMaskManager } from './mask';
|
||||||
@@ -17,6 +18,7 @@ export class RoomPlane implements IRoomPlane
|
|||||||
'64': new RoomGeometry(64, new Vector3d(RoomPlane.HORIZONTAL_ANGLE_DEFAULT, RoomPlane.VERTICAL_ANGLE_DEFAULT), new Vector3d(-10, 0, 0))
|
'64': new RoomGeometry(64, new Vector3d(RoomPlane.HORIZONTAL_ANGLE_DEFAULT, RoomPlane.VERTICAL_ANGLE_DEFAULT), new Vector3d(-10, 0, 0))
|
||||||
};
|
};
|
||||||
private static LANDSCAPE_COLOR: number = 0x0082F0;
|
private static LANDSCAPE_COLOR: number = 0x0082F0;
|
||||||
|
private static ANIMATION_UPDATE_INTERVAL: number = 500;
|
||||||
|
|
||||||
public static TYPE_UNDEFINED: number = 0;
|
public static TYPE_UNDEFINED: number = 0;
|
||||||
public static TYPE_WALL: number = 1;
|
public static TYPE_WALL: number = 1;
|
||||||
@@ -67,6 +69,18 @@ export class RoomPlane implements IRoomPlane
|
|||||||
private _planeTexture: Texture = null;
|
private _planeTexture: Texture = null;
|
||||||
private _maskFilter: Filter = null;
|
private _maskFilter: Filter = null;
|
||||||
|
|
||||||
|
private _animationLayers: PlaneVisualizationAnimationLayer[] = [];
|
||||||
|
private _isAnimated: boolean = false;
|
||||||
|
private _lastAnimationUpdate: number = 0;
|
||||||
|
private _animationCanvasWidth: number = 0;
|
||||||
|
private _animationCanvasHeight: number = 0;
|
||||||
|
private _landscapeRenderWidth: number = 0;
|
||||||
|
private _landscapeRenderHeight: number = 0;
|
||||||
|
private _landscapeOffsetX: number = 0;
|
||||||
|
private _landscapeOffsetY: number = 0;
|
||||||
|
private _hasWindowMask: boolean = false;
|
||||||
|
private _windowMasks: { leftSideLoc: number; rightSideLoc: number }[] = [];
|
||||||
|
|
||||||
constructor(origin: IVector3D, location: IVector3D, leftSide: IVector3D, rightSide: IVector3D, type: number, usesMask: boolean, secondaryNormals: IVector3D[], randomSeed: number, textureOffsetX: number = 0, textureOffsetY: number = 0, textureMaxX: number = 0, textureMaxY: number = 0)
|
constructor(origin: IVector3D, location: IVector3D, leftSide: IVector3D, rightSide: IVector3D, type: number, usesMask: boolean, secondaryNormals: IVector3D[], randomSeed: number, textureOffsetX: number = 0, textureOffsetY: number = 0, textureMaxX: number = 0, textureMaxY: number = 0)
|
||||||
{
|
{
|
||||||
this._randomSeed = randomSeed;
|
this._randomSeed = randomSeed;
|
||||||
@@ -122,6 +136,15 @@ export class RoomPlane implements IRoomPlane
|
|||||||
this._planeTexture = null;
|
this._planeTexture = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this._animationLayers)
|
||||||
|
{
|
||||||
|
for(const layer of this._animationLayers)
|
||||||
|
{
|
||||||
|
if(layer) layer.dispose();
|
||||||
|
}
|
||||||
|
this._animationLayers = [];
|
||||||
|
}
|
||||||
|
|
||||||
this._disposed = true;
|
this._disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,9 +159,12 @@ export class RoomPlane implements IRoomPlane
|
|||||||
needsUpdate = true;
|
needsUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!needsUpdate || !this._canBeVisible)
|
const needsAnimationUpdate = this._isAnimated && this._type === RoomPlane.TYPE_LANDSCAPE &&
|
||||||
|
(timeSinceStartMs - this._lastAnimationUpdate) >= RoomPlane.ANIMATION_UPDATE_INTERVAL;
|
||||||
|
|
||||||
|
if(!needsUpdate && !needsAnimationUpdate)
|
||||||
{
|
{
|
||||||
if(!this.visible) return false;
|
if(!this._canBeVisible || !this.visible) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(needsUpdate)
|
if(needsUpdate)
|
||||||
@@ -208,16 +234,43 @@ export class RoomPlane implements IRoomPlane
|
|||||||
const dataType: keyof IAssetRoomVisualizationData = (planeType === RoomPlane.TYPE_FLOOR) ? 'floorData' : (planeType === RoomPlane.TYPE_WALL) ? 'wallData' : 'landscapeData';
|
const dataType: keyof IAssetRoomVisualizationData = (planeType === RoomPlane.TYPE_FLOOR) ? 'floorData' : (planeType === RoomPlane.TYPE_WALL) ? 'wallData' : 'landscapeData';
|
||||||
|
|
||||||
const roomCollection = GetAssetManager().getCollection('room');
|
const roomCollection = GetAssetManager().getCollection('room');
|
||||||
const planeVisualizationData = roomCollection?.data?.roomVisualization?.[dataType];
|
let planeVisualizationData = roomCollection?.data?.roomVisualization?.[dataType];
|
||||||
const plane = planeVisualizationData?.planes?.find(plane => (plane.id === planeId));
|
let plane = planeVisualizationData?.planes?.find(plane => (plane.id === planeId));
|
||||||
|
let assetCollection = roomCollection;
|
||||||
|
|
||||||
|
if(!plane && planeType === RoomPlane.TYPE_LANDSCAPE)
|
||||||
|
{
|
||||||
|
const landscapeCollection = GetAssetManager().getCollection('landscape');
|
||||||
|
if(landscapeCollection?.data?.roomVisualization?.landscapeData)
|
||||||
|
{
|
||||||
|
planeVisualizationData = landscapeCollection.data.roomVisualization.landscapeData;
|
||||||
|
plane = planeVisualizationData?.planes?.find(p => (p.id === planeId));
|
||||||
|
if(plane) assetCollection = landscapeCollection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const planeVisualization = ((dataType === 'landscapeData') ? plane?.animatedVisualization : plane?.visualizations)?.find(visualization => (visualization.size === planeGeometry.scale)) ?? null;
|
const planeVisualization = ((dataType === 'landscapeData') ? plane?.animatedVisualization : plane?.visualizations)?.find(visualization => (visualization.size === planeGeometry.scale)) ?? null;
|
||||||
const planeLayer = planeVisualization?.allLayers?.[0] as IAssetPlaneVisualizationLayer;
|
const planeLayer = planeVisualization?.allLayers?.[0] as IAssetPlaneVisualizationLayer;
|
||||||
const planeMaterialId = planeLayer?.materialId;
|
const planeMaterialId = planeLayer?.materialId;
|
||||||
const planeColor = planeLayer?.color;
|
const planeColor = planeLayer?.color;
|
||||||
const planeAssetName = planeVisualizationData?.textures?.find(texture => (texture.id === planeMaterialId))?.bitmaps?.[0]?.assetName;
|
const planeAssetName = planeVisualizationData?.textures?.find(texture => (texture.id === planeMaterialId))?.bitmaps?.[0]?.assetName;
|
||||||
const texture = GetAssetManager().getAsset(planeAssetName)?.texture;
|
const texture = assetCollection ? GetAssetManager().getAsset(planeAssetName)?.texture : null;
|
||||||
|
|
||||||
return { texture, color: planeColor };
|
const animationLayers: PlaneVisualizationAnimationLayer[] = [];
|
||||||
|
if(planeType === RoomPlane.TYPE_LANDSCAPE && planeVisualization?.allLayers && assetCollection)
|
||||||
|
{
|
||||||
|
for(const layer of planeVisualization.allLayers)
|
||||||
|
{
|
||||||
|
const animatedLayer = layer as IAssetPlaneVisualizationAnimatedLayer;
|
||||||
|
if(animatedLayer?.items && animatedLayer.items.length > 0)
|
||||||
|
{
|
||||||
|
const animLayer = new PlaneVisualizationAnimationLayer(animatedLayer.items, assetCollection);
|
||||||
|
if(animLayer.hasItems) animationLayers.push(animLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { texture, color: planeColor, animationLayers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const planeData = getTextureAndColorForPlane(this._id, this._type);
|
const planeData = getTextureAndColorForPlane(this._id, this._type);
|
||||||
@@ -304,6 +357,23 @@ export class RoomPlane implements IRoomPlane
|
|||||||
const renderOffsetX = Math.trunc(this._textureOffsetX * Math.abs((_local_13.x - _local_15.x)));
|
const renderOffsetX = Math.trunc(this._textureOffsetX * Math.abs((_local_13.x - _local_15.x)));
|
||||||
const renderOffsetY = Math.trunc(this._textureOffsetY * Math.abs((_local_13.y - _local_14.y)));
|
const renderOffsetY = Math.trunc(this._textureOffsetY * Math.abs((_local_13.y - _local_14.y)));
|
||||||
|
|
||||||
|
this._landscapeRenderWidth = width;
|
||||||
|
this._landscapeRenderHeight = height;
|
||||||
|
this._animationCanvasWidth = renderMaxX;
|
||||||
|
this._animationCanvasHeight = renderMaxY;
|
||||||
|
this._landscapeOffsetX = renderOffsetX;
|
||||||
|
this._landscapeOffsetY = renderOffsetY;
|
||||||
|
|
||||||
|
if(this._animationLayers)
|
||||||
|
{
|
||||||
|
for(const layer of this._animationLayers)
|
||||||
|
{
|
||||||
|
if(layer) layer.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._animationLayers = planeData.animationLayers || [];
|
||||||
|
this._isAnimated = this._animationLayers.length > 0;
|
||||||
|
|
||||||
this._planeSprite = new TilingSprite({
|
this._planeSprite = new TilingSprite({
|
||||||
texture,
|
texture,
|
||||||
width,
|
width,
|
||||||
@@ -349,7 +419,18 @@ export class RoomPlane implements IRoomPlane
|
|||||||
|
|
||||||
this._planeTexture.source.label = `room_plane_${ this._uniqueId.toString() }`;
|
this._planeTexture.source.label = `room_plane_${ this._uniqueId.toString() }`;
|
||||||
|
|
||||||
if(needsUpdate)
|
let animationUpdate = false;
|
||||||
|
if(this._isAnimated && this._type === RoomPlane.TYPE_LANDSCAPE)
|
||||||
|
{
|
||||||
|
const timeSinceLastUpdate = timeSinceStartMs - this._lastAnimationUpdate;
|
||||||
|
if(timeSinceLastUpdate >= RoomPlane.ANIMATION_UPDATE_INTERVAL || needsUpdate)
|
||||||
|
{
|
||||||
|
animationUpdate = true;
|
||||||
|
this._lastAnimationUpdate = timeSinceStartMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(needsUpdate || animationUpdate)
|
||||||
{
|
{
|
||||||
GetRenderer().render({
|
GetRenderer().render({
|
||||||
target: this._planeTexture,
|
target: this._planeTexture,
|
||||||
@@ -357,11 +438,78 @@ export class RoomPlane implements IRoomPlane
|
|||||||
transform: this.getMatrixForDimensions(this._planeSprite.width, this._planeSprite.height),
|
transform: this.getMatrixForDimensions(this._planeSprite.width, this._planeSprite.height),
|
||||||
clear: true
|
clear: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(this._isAnimated && this._type === RoomPlane.TYPE_LANDSCAPE && this._animationLayers.length > 0 && this._hasWindowMask)
|
||||||
|
{
|
||||||
|
this.renderAnimationLayers(timeSinceStartMs, geometry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private renderAnimationLayers(timeSinceStartMs: number, geometry: IRoomGeometry): void
|
||||||
|
{
|
||||||
|
if(!this._planeTexture || this._animationCanvasWidth <= 0 || this._animationCanvasHeight <= 0) return;
|
||||||
|
|
||||||
|
const canvasWidth = this._landscapeRenderWidth;
|
||||||
|
const canvasHeight = this._landscapeRenderHeight;
|
||||||
|
|
||||||
|
if(canvasWidth <= 0 || canvasHeight <= 0) return;
|
||||||
|
|
||||||
|
const animationCanvas = RenderTexture.create({ width: canvasWidth, height: canvasHeight });
|
||||||
|
|
||||||
|
for(const layer of this._animationLayers)
|
||||||
|
{
|
||||||
|
if(!layer) continue;
|
||||||
|
|
||||||
|
layer.render(
|
||||||
|
animationCanvas,
|
||||||
|
this._landscapeOffsetX,
|
||||||
|
this._landscapeOffsetY,
|
||||||
|
this._animationCanvasWidth,
|
||||||
|
this._animationCanvasHeight,
|
||||||
|
this._leftSide.length,
|
||||||
|
this._rightSide.length,
|
||||||
|
timeSinceStartMs
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const animContainer = new Container();
|
||||||
|
const animSprite = new Sprite(animationCanvas);
|
||||||
|
animContainer.addChild(animSprite);
|
||||||
|
|
||||||
|
if(this._maskFilter)
|
||||||
|
{
|
||||||
|
animContainer.filters = [this._maskFilter];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._planeSprite && this._planeSprite.children)
|
||||||
|
{
|
||||||
|
for(const child of this._planeSprite.children)
|
||||||
|
{
|
||||||
|
if(child instanceof Sprite)
|
||||||
|
{
|
||||||
|
const maskClone = new Sprite(child.texture);
|
||||||
|
maskClone.position.copyFrom(child.position);
|
||||||
|
maskClone.scale.copyFrom(child.scale);
|
||||||
|
animContainer.addChild(maskClone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const transform = this.getMatrixForDimensions(canvasWidth, canvasHeight);
|
||||||
|
|
||||||
|
GetRenderer().render({
|
||||||
|
target: this._planeTexture,
|
||||||
|
container: animContainer,
|
||||||
|
transform,
|
||||||
|
clear: false
|
||||||
|
});
|
||||||
|
|
||||||
|
animationCanvas.destroy(true);
|
||||||
|
}
|
||||||
|
|
||||||
private updateCorners(geometry: IRoomGeometry): void
|
private updateCorners(geometry: IRoomGeometry): void
|
||||||
{
|
{
|
||||||
this._cornerA.assign(geometry.getScreenPosition(this._location));
|
this._cornerA.assign(geometry.getScreenPosition(this._location));
|
||||||
@@ -434,6 +582,9 @@ export class RoomPlane implements IRoomPlane
|
|||||||
|
|
||||||
public resetBitmapMasks(): void
|
public resetBitmapMasks(): void
|
||||||
{
|
{
|
||||||
|
this._hasWindowMask = false;
|
||||||
|
this._windowMasks = [];
|
||||||
|
|
||||||
if(this._disposed || !this._useMask || !this._bitmapMasks.length) return;
|
if(this._disposed || !this._useMask || !this._bitmapMasks.length) return;
|
||||||
|
|
||||||
this._maskChanged = true;
|
this._maskChanged = true;
|
||||||
@@ -459,6 +610,12 @@ export class RoomPlane implements IRoomPlane
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addWindowMask(leftSideLoc: number, rightSideLoc: number): void
|
||||||
|
{
|
||||||
|
this._windowMasks.push({ leftSideLoc, rightSideLoc });
|
||||||
|
this._hasWindowMask = true;
|
||||||
|
}
|
||||||
|
|
||||||
public resetRectangleMasks(): void
|
public resetRectangleMasks(): void
|
||||||
{
|
{
|
||||||
if(!this._useMask || !this._rectangleMasks.length) return;
|
if(!this._useMask || !this._rectangleMasks.length) return;
|
||||||
@@ -653,4 +810,14 @@ export class RoomPlane implements IRoomPlane
|
|||||||
{
|
{
|
||||||
this._isHighlighter = flag;
|
this._isHighlighter = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get hasWindowMask(): boolean
|
||||||
|
{
|
||||||
|
return this._hasWindowMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set hasWindowMask(flag: boolean)
|
||||||
|
{
|
||||||
|
this._hasWindowMask = flag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -817,6 +817,7 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements
|
|||||||
if(!plane.canBeVisible) _local_6 = true;
|
if(!plane.canBeVisible) _local_6 = true;
|
||||||
|
|
||||||
plane.canBeVisible = true;
|
plane.canBeVisible = true;
|
||||||
|
plane.addWindowMask(leftSideLoc, rightSideLoc);
|
||||||
|
|
||||||
_local_5.push(i);
|
_local_5.push(i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { IGraphicAsset } from '@nitrots/api';
|
||||||
|
import { Point } from 'pixi.js';
|
||||||
|
|
||||||
|
export class AnimationItem
|
||||||
|
{
|
||||||
|
private _x: number;
|
||||||
|
private _y: number;
|
||||||
|
private _speedX: number;
|
||||||
|
private _speedY: number;
|
||||||
|
private _asset: IGraphicAsset;
|
||||||
|
|
||||||
|
constructor(x: number, y: number, speedX: number, speedY: number, asset: IGraphicAsset)
|
||||||
|
{
|
||||||
|
this._x = x;
|
||||||
|
this._y = y;
|
||||||
|
this._speedX = speedX;
|
||||||
|
this._speedY = speedY;
|
||||||
|
this._asset = asset;
|
||||||
|
|
||||||
|
if(isNaN(this._x)) this._x = 0;
|
||||||
|
if(isNaN(this._y)) this._y = 0;
|
||||||
|
if(isNaN(this._speedX)) this._speedX = 0;
|
||||||
|
if(isNaN(this._speedY)) this._speedY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get bitmapData(): IGraphicAsset
|
||||||
|
{
|
||||||
|
return this._asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this._asset = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPosition(maxX: number, maxY: number, dimensionX: number, dimensionY: number, timeSinceStartMs: number): Point
|
||||||
|
{
|
||||||
|
let x = this._x;
|
||||||
|
let y = this._y;
|
||||||
|
|
||||||
|
if(dimensionX > 0) x = (x + (((this._speedX / dimensionX) * timeSinceStartMs) / 1000));
|
||||||
|
if(dimensionY > 0) y = (y + (((this._speedY / dimensionY) * timeSinceStartMs) / 1000));
|
||||||
|
|
||||||
|
const localX = Math.trunc((x % 1) * maxX);
|
||||||
|
const localY = Math.trunc((y % 1) * maxY);
|
||||||
|
|
||||||
|
return new Point(localX, localY);
|
||||||
|
}
|
||||||
|
}
|
||||||
+150
@@ -0,0 +1,150 @@
|
|||||||
|
import { IAssetPlaneVisualizationAnimatedLayerItem, IGraphicAssetCollection } from '@nitrots/api';
|
||||||
|
import { TextureUtils } from '@nitrots/utils';
|
||||||
|
import { RenderTexture, Sprite } from 'pixi.js';
|
||||||
|
import { AnimationItem } from './AnimationItem';
|
||||||
|
|
||||||
|
export class PlaneVisualizationAnimationLayer
|
||||||
|
{
|
||||||
|
private _isDisposed: boolean = false;
|
||||||
|
private _items: AnimationItem[] = [];
|
||||||
|
|
||||||
|
constructor(items: IAssetPlaneVisualizationAnimatedLayerItem[], assets: IGraphicAssetCollection)
|
||||||
|
{
|
||||||
|
if(items && assets)
|
||||||
|
{
|
||||||
|
for(const item of items)
|
||||||
|
{
|
||||||
|
if(!item) continue;
|
||||||
|
|
||||||
|
const assetName = item.assetId;
|
||||||
|
|
||||||
|
if(assetName)
|
||||||
|
{
|
||||||
|
const asset = assets.getAsset(assetName);
|
||||||
|
|
||||||
|
if(asset)
|
||||||
|
{
|
||||||
|
const x = this.parseCoordinate(item.x, item.randomX);
|
||||||
|
const y = this.parseCoordinate(item.y, item.randomY);
|
||||||
|
|
||||||
|
this._items.push(new AnimationItem(x, y, item.speedX || 0, item.speedY || 0, asset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseCoordinate(value: string, randomValue: string): number
|
||||||
|
{
|
||||||
|
let result = 0;
|
||||||
|
|
||||||
|
if(value)
|
||||||
|
{
|
||||||
|
if(value.includes('%'))
|
||||||
|
{
|
||||||
|
result = parseFloat(value.replace('%', '')) / 100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = parseFloat(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(randomValue)
|
||||||
|
{
|
||||||
|
const random = parseFloat(randomValue);
|
||||||
|
if(!isNaN(random)) result += (Math.random() * random);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get disposed(): boolean
|
||||||
|
{
|
||||||
|
return this._isDisposed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get hasItems(): boolean
|
||||||
|
{
|
||||||
|
return this._items.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this._isDisposed = true;
|
||||||
|
|
||||||
|
if(this._items)
|
||||||
|
{
|
||||||
|
for(const item of this._items)
|
||||||
|
{
|
||||||
|
if(item) item.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._items = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(
|
||||||
|
canvas: RenderTexture,
|
||||||
|
offsetX: number,
|
||||||
|
offsetY: number,
|
||||||
|
maxX: number,
|
||||||
|
maxY: number,
|
||||||
|
dimensionX: number,
|
||||||
|
dimensionY: number,
|
||||||
|
timeSinceStartMs: number
|
||||||
|
): RenderTexture
|
||||||
|
{
|
||||||
|
if(maxX <= 0 || maxY <= 0) return canvas;
|
||||||
|
|
||||||
|
for(const item of this._items)
|
||||||
|
{
|
||||||
|
if(!item || !item.bitmapData) continue;
|
||||||
|
|
||||||
|
const point = item.getPosition(maxX, maxY, dimensionX, dimensionY, timeSinceStartMs);
|
||||||
|
point.x = Math.trunc(point.x - offsetX);
|
||||||
|
point.y = Math.trunc(point.y - offsetY);
|
||||||
|
|
||||||
|
const assetWidth = item.bitmapData.width;
|
||||||
|
const assetHeight = item.bitmapData.height;
|
||||||
|
|
||||||
|
// Render at primary position
|
||||||
|
if(this.isVisible(point.x, point.y, assetWidth, assetHeight, canvas.width, canvas.height))
|
||||||
|
{
|
||||||
|
this.renderSprite(item, point.x, point.y, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap horizontally (left side)
|
||||||
|
if(this.isVisible(point.x - maxX, point.y, assetWidth, assetHeight, canvas.width, canvas.height))
|
||||||
|
{
|
||||||
|
this.renderSprite(item, point.x - maxX, point.y, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap vertically (top side)
|
||||||
|
if(this.isVisible(point.x, point.y - maxY, assetWidth, assetHeight, canvas.width, canvas.height))
|
||||||
|
{
|
||||||
|
this.renderSprite(item, point.x, point.y - maxY, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap both (top-left corner)
|
||||||
|
if(this.isVisible(point.x - maxX, point.y - maxY, assetWidth, assetHeight, canvas.width, canvas.height))
|
||||||
|
{
|
||||||
|
this.renderSprite(item, point.x - maxX, point.y - maxY, canvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isVisible(x: number, y: number, width: number, height: number, canvasWidth: number, canvasHeight: number): boolean
|
||||||
|
{
|
||||||
|
return (x > -width) && (x < canvasWidth) && (y > -height) && (y < canvasHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderSprite(item: AnimationItem, x: number, y: number, canvas: RenderTexture): void
|
||||||
|
{
|
||||||
|
const sprite = new Sprite(item.bitmapData.texture);
|
||||||
|
sprite.position.set(x, y);
|
||||||
|
TextureUtils.writeToTexture(sprite, canvas, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './AnimationItem';
|
||||||
|
export * from './PlaneVisualizationAnimationLayer';
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export * from './animated';
|
||||||
export * from './PlaneDrawingData';
|
export * from './PlaneDrawingData';
|
||||||
export * from './RoomPlane';
|
export * from './RoomPlane';
|
||||||
export * from './RoomPlaneBitmapMask';
|
export * from './RoomPlaneBitmapMask';
|
||||||
|
|||||||
Reference in New Issue
Block a user