playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
122 lines (121 loc) • 3.88 kB
JavaScript
import { AnimTrack } from "../../anim/evaluator/anim-track.js";
import { Component } from "../component.js";
import { ComponentSystem } from "../system.js";
import { AnimComponent } from "./component.js";
import { AnimComponentData } from "./data.js";
const _schema = [
"enabled"
];
class AnimComponentSystem extends ComponentSystem {
constructor(app) {
super(app);
this.id = "anim";
this.ComponentType = AnimComponent;
this.DataType = AnimComponentData;
this.schema = _schema;
this.on("beforeremove", this.onBeforeRemove, this);
this.app.systems.on("animationUpdate", this.onAnimationUpdate, this);
}
initializeComponentData(component, data, properties) {
super.initializeComponentData(component, data, _schema);
const complexProperties = ["animationAssets", "stateGraph", "layers", "masks"];
Object.keys(data).forEach((key) => {
if (complexProperties.includes(key)) return;
component[key] = data[key];
});
if (data.stateGraph) {
component.stateGraph = data.stateGraph;
component.loadStateGraph(component.stateGraph);
}
if (data.layers) {
data.layers.forEach((layer, i) => {
layer._controller.states.forEach((stateKey) => {
layer._controller._states[stateKey]._animationList.forEach((node) => {
if (!node.animTrack || node.animTrack === AnimTrack.EMPTY) {
const animationAsset = this.app.assets.get(layer._component._animationAssets[`${layer.name}:${node.name}`].asset);
if (animationAsset && !animationAsset.loaded) {
animationAsset.once("load", () => {
component.layers[i].assignAnimation(node.name, animationAsset.resource);
});
}
} else {
component.layers[i].assignAnimation(node.name, node.animTrack);
}
});
});
});
}
if (data.animationAssets) {
component.animationAssets = Object.assign(component.animationAssets, data.animationAssets);
}
if (data.masks) {
Object.keys(data.masks).forEach((key) => {
if (component.layers[key]) {
const maskData = data.masks[key].mask;
const mask = {};
Object.keys(maskData).forEach((maskKey) => {
mask[decodeURI(maskKey)] = maskData[maskKey];
});
component.layers[key].mask = mask;
}
});
}
}
onAnimationUpdate(dt) {
const components = this.store;
for (const id in components) {
if (components.hasOwnProperty(id)) {
const component = components[id].entity.anim;
const componentData = component.data;
if (componentData.enabled && component.entity.enabled && component.playing) {
component.update(dt);
}
}
}
}
cloneComponent(entity, clone) {
let masks;
if (!entity.anim.rootBone || entity.anim.rootBone === entity) {
masks = {};
entity.anim.layers.forEach((layer, i) => {
if (layer.mask) {
const mask = {};
Object.keys(layer.mask).forEach((path) => {
const pathArr = path.split("/");
pathArr.shift();
const clonePath = [clone.name, ...pathArr].join("/");
mask[clonePath] = layer.mask[path];
});
masks[i] = { mask };
}
});
}
const data = {
enabled: entity.anim.enabled,
stateGraphAsset: entity.anim.stateGraphAsset,
animationAssets: entity.anim.animationAssets,
speed: entity.anim.speed,
activate: entity.anim.activate,
playing: entity.anim.playing,
rootBone: entity.anim.rootBone,
stateGraph: entity.anim.stateGraph,
layers: entity.anim.layers,
layerIndices: entity.anim.layerIndices,
parameters: entity.anim.parameters,
normalizeWeights: entity.anim.normalizeWeights,
masks
};
return this.addComponent(clone, data);
}
onBeforeRemove(entity, component) {
component.onBeforeRemove();
}
destroy() {
super.destroy();
this.app.systems.off("animationUpdate", this.onAnimationUpdate, this);
}
}
Component._buildAccessors(AnimComponent.prototype, _schema);
export {
AnimComponentSystem
};