@megavr/ecsy-babylon
Version:
babylon.js ecsy binding and helpers
919 lines (892 loc) • 35.8 kB
JavaScript
(function (BABYLON, ecsy) {
'use strict';
/**
* @example
* ```
* entity.addComponent(Scene, { color: { clear: "123ABCFF" } });
* ```
*/
class Scene {
}
/**
* Translate degree to radians.
* @param degree Degree
*/
function degreeToRadians(degree) {
return BABYLON.Angle.FromDegrees(degree).radians();
}
/**
* Convert XYZProperties value to Vector3.
* @param properties XYZProperties value
*/
function xyzToVector3(properties) {
return new BABYLON.Vector3(properties.x, properties.y, properties.z);
}
/**
* Convert XYZProperties degree value to Vector3 in radians.
* @param properties XYZProperties value in degrees
*/
function xyzToVector3Radians(properties) {
return new BABYLON.Vector3(degreeToRadians(properties.x), degreeToRadians(properties.y), degreeToRadians(properties.z));
}
/**
* @hidden
* Create object by XYZ values or create all zero object.
* @param x value
* @param y value
* @param z value
* @returns Object matches XYZProperties
*/
function xyz(x, y, z) {
if (x && y && z) {
return { x: x, y: y, z: z };
}
else {
return { x: 0, y: 0, z: 0 };
}
}
/**
* @example
* ```
* entity.addComponent(Transform);
* ```
*/
class Transform {
constructor() {
/** @default 0,0,0 */
this.position = xyz();
/** @default 0,0,0 */
this.rotation = xyz();
/** @default 1,1,1 */
this.scale = xyz(1, 1, 1);
}
}
/**
* @example
* ```
* entity.addComponent(Camera, { pointerLock: true });
* ```
*/
class Camera {
constructor() {
/**
* Lock pointer when using the camera.
* @see https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API
* @default false
*/
this.pointerLock = false;
}
}
var MeshTypes;
(function (MeshTypes) {
MeshTypes["Box"] = "Box";
MeshTypes["Plane"] = "Plane";
MeshTypes["Sphere"] = "Sphere";
MeshTypes["Ground"] = "Ground";
MeshTypes["Url"] = "Url";
})(MeshTypes || (MeshTypes = {}));
/**
* @example
* ```
* entity.addComponent(Mesh);
* entity.addComponent(Mesh, { type: MeshTypes.Ground, options: { width: 2, height: 2 } });
* entity.addComponent(Mesh, { type: MeshTypes.Sphere, options: { diameter: 2 } });
* entity.addComponent(Mesh, { type: MeshTypes.Url, url: "PATH_TO_MESH" });
* ```
*/
class Mesh {
constructor() {
/** @default "Box" */
this.type = MeshTypes.Box;
}
}
var LightTypes;
(function (LightTypes) {
LightTypes["Point"] = "Point";
LightTypes["Directional"] = "Directional";
LightTypes["Spot"] = "Spot";
LightTypes["Hemispheric"] = "Hemispheric";
})(LightTypes || (LightTypes = {}));
/**
* @example
* ```
* entity.addComponent(Light, { color: { diffuse: "#AAFFAA" } });
* entity.addComponent(Light, { type: LightTypes.Point, intensity: 2 });
* entity.addComponent(Light, { type: LightTypes.Directional, direction: { x: 0, y: 0, z: 1 } });
* entity.addComponent(Light, { type: LightTypes.Spot, direction: { x: 0, y: 0, z: 1 }, angle: 30, exponent: 2 });
* ```
*/
class Light {
constructor() {
/** @default "Hemispheric" */
this.type = LightTypes.Hemispheric;
/**
* @see https://doc.babylonjs.com/api/classes/babylon.shadowlight#direction
* @default 0,0,0
*/
this.direction = xyz();
}
}
/**
* @hidden
* Update value of Babylon.js object's property from a property in component with same name.
* @param component Component contains Babylon.js object
* @param name Name of property in the component
*/
function updateObjectValue(component, name) {
component.object[name] = component[name];
}
/**
* @hidden
* Update Vector3 of Babylon.js object's property from property in component with same name.
* @param component Component contains Babylon.js object
* @param name Name of property in the component, value of property should matches XYZProperties
*/
function updateObjectVector3(component, name) {
component.object[name] = xyzToVector3(component[name]);
}
/**
* @hidden
* Update transformation of ObjectComponents in entity.
* @param entity Entity to be updated
*/
function updateObjectsTransform(entity) {
let components = entity.getComponents();
for (let prop in components) {
let component = components[prop];
(component.object && entity.hasComponent(Transform)) && updateObjectTransform(entity.getMutableComponent(Transform), component);
}
}
/**
* @hidden
* Update transformation to an ObjectComponent.
* @param transform Transfrom component in the entity
* @param component A component has Babylon.js object
*/
function updateObjectTransform(transform, component) {
let object = component.object;
object.position && (object.position = xyzToVector3(transform.position));
object.rotation && (object.rotation = xyzToVector3Radians(transform.rotation));
object.scaling && (object.scaling = xyzToVector3(transform.scale));
}
/**
* @hidden
* Dispose Babylon.js object in the component.
* @param object Component contains Babylon.js object
*/
function disposeObject(component) {
component.object && component.object.dispose();
}
/**
* @hidden
* Update texture object to a component for its texture properties.
* @param component TextureComponent in the entity
* @param textureProperties Texture properties to be update
* @param assetManager AssetManager to process textures
*/
function updateTexture(component, textureProperties, assetManager) {
for (let prop in textureProperties) {
let textureAttributes = textureProperties[prop];
let task = assetManager.addTextureTask(prop, textureAttributes.url);
task.onSuccess = (task) => {
let textureObject = task.texture;
for (let attr in textureAttributes) {
attr !== "url" && (textureObject[attr] = textureAttributes[attr]);
}
let textureName = `${prop}Texture`;
let componentObject = component.object;
componentObject[textureName] && disposeObject(componentObject[textureName]);
componentObject[textureName] = textureObject;
};
}
assetManager.load();
assetManager.reset();
}
/**
* @hidden
* Create object of material color values or create a material color object with white diffuse.
* @param diffuse Diffuse color in hex string. e.g., #123ABC
* @returns Object matches MaterialColorProperties
*/
function materialColorHex(diffuse) {
if (diffuse) {
return { diffuse: diffuse };
}
else {
return { diffuse: "#ffffff" };
}
}
/**
* Convert hex color value to Color3.
* @param hexString Text of hex color value(e.g., #123ABC)
*/
function hexToColor3(hexString) {
return BABYLON.Color3.FromHexString(hexString);
}
/**
* Convert hex color value to Color4 (has alpha).
* @param hexString Text of hex color value(e.g., #123ABCFF)
*/
function hexToColor4(hexString) {
return BABYLON.Color4.FromHexString(hexString);
}
/**
* @example
* ```
* entity.addComponent(Mesh).addComponent(Material, {
* alpha: 0.7,
* color: { diffuse: "#E74C3C" }
* });
* entity.addComponent(Mesh).addComponent(Material, {
* texture: {
* diffuse: { url: "PATH_TO_TEXTURE", uScale: 4, vScale: 4 }
* }
* });
* ```
*/
class Material {
constructor() {
/** @default { diffuse: "#ffffff" } */
this.color = materialColorHex();
}
}
var ParticleTypes;
(function (ParticleTypes) {
ParticleTypes["Point"] = "Point";
ParticleTypes["Box"] = "Box";
ParticleTypes["Sphere"] = "Sphere";
ParticleTypes["DirectedSphere"] = "DirectedSphere";
ParticleTypes["Hemisphere"] = "Hemisphere";
ParticleTypes["Cylinder"] = "Cylinder";
ParticleTypes["DirectedCylinder"] = "DirectedCylinder";
ParticleTypes["Cone"] = "Cone";
})(ParticleTypes || (ParticleTypes = {}));
/**
* @example
* ```
* entity.addComponent(Particle, {
* emitter: { x: 0, y: 0, z: 1 },
* texture: {
* diffuse: { url: "PATH_TO_PARTICLE_TEXTURE" }
* }
* });
* ```
*/
class Particle {
constructor() {
/** @default "Point" */
this.type = ParticleTypes.Point;
/**
* @see https://doc.babylonjs.com/api/classes/babylon.particlesystem#constructor
* @default 100
*/
this.capacity = 100;
/**
* @see https://doc.babylonjs.com/api/classes/babylon.particlesystem#emitter
* @default 0,0,0
*/
this.emitter = xyz();
/**
* @memberof Point, Box, DirectedSphere, Cylinder
* @default 0,0,0
*/
this.direction1 = xyz();
/**
* @memberof Point, Box, DirectedSphere, Cylinder
* @default 10,10,10
*/
this.direction2 = xyz(10, 10, 10);
/**
* @memberof Box
* @default 0,0,0
*/
this.minEmitBox = xyz();
/**
* @memberof Box
* @default 0,0,0
*/
this.maxEmitBox = xyz();
}
}
var InputTypes;
(function (InputTypes) {
InputTypes["Keyboard"] = "Keyboard";
})(InputTypes || (InputTypes = {}));
/**
* @example Keyboard
* ```
* entity.addComponent(Input, { onKey: onKey });
* function onKey(key, down, up) {
* if (down) console.log(key + " is pressing.");
* }
* ```
*/
class Input {
constructor() {
/** @default "Keyboard" */
this.type = InputTypes.Keyboard;
}
}
/**
* @hidden
* Hack on ecsy to get World instance from system itself.
* @param system A registered ecsy System class
* @returns ecsy world
*/
function getWorld(system) {
return system["world"];
}
/** Core system of ecsy-babylon. */
class GameSystem extends ecsy.System {
constructor() {
super(...arguments);
/** <Scene UID, BABYLON.AssetsManager> */
this._assetManagers = new Map();
/** Observable event when active scene is switched. */
this.onSceneSwitched = new BABYLON.Observable();
}
/** Get canvas used for rendering. */
get renderingCanvas() { return this._engine.getRenderingCanvas(); }
/** Get all scenes in engine. */
get scenes() { return this._engine.scenes; }
/** Get active scene. */
get activeScene() { return this._activeScene; }
/** @hidden */
init() {
this._render = this._render.bind(this);
}
/** @hidden */
execute() {
this.queries.scene.added.forEach((entity) => {
let scene = entity.getComponent(Scene);
scene.object = new BABYLON.Scene(this._engine, scene.options);
this._engine.scenes.length === 1 && (this._activeScene = scene.object);
this._updateScene(entity);
// add assetManager for each scenes
let assetManager = new BABYLON.AssetsManager(scene.object);
assetManager.useDefaultLoadingScreen = false;
this._assetManagers.set(scene.object.uid, assetManager);
});
this.queries.scene.changed.forEach((entity) => {
this._updateScene(entity);
});
this.queries.scene.removed.forEach((entity) => {
let scene = entity.getComponent(Scene);
disposeObject(scene);
});
}
_updateScene(entity) {
let scene = entity.getComponent(Scene);
for (let prop in scene) {
switch (prop) {
case "texture":
updateTexture(scene, scene.texture, this.getAssetManager(entity));
break;
case "color":
this._updateColor(scene, scene.color);
break;
default:
updateObjectValue(scene, prop);
break;
}
}
}
_updateColor(scene, color) {
for (let prop in color) {
switch (prop) {
case "clear":
scene.object[`${prop}Color`] = hexToColor4(color[prop]);
break;
default:
scene.object[`${prop}Color`] = hexToColor3(color[prop]);
break;
}
}
}
/**
* Start game system in the world can be used by other systems & components.
* @see https://doc.babylonjs.com/api/classes/babylon.engine#constructor
* @param canvas WebGL context to be used for rendering
* @param antialias defines enable antialiasing (default: false)
* @param options @see https://doc.babylonjs.com/api/interfaces/babylon.engineoptions
* @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
*/
start(canvas, antialias, options, adaptToDeviceRatio) {
this._engine = new BABYLON.Engine(canvas, antialias, options, adaptToDeviceRatio);
this._engine.runRenderLoop(this._render);
return this;
}
/**
* Switch to a scene by given scene entity.
* @param scene Scene entity
*/
switchScene(scene) {
this._activeScene = scene.getComponent(Scene).object;
this.onSceneSwitched.notifyObservers(this._activeScene);
return this;
}
/**
* Get scene AssetManager or return AssetManager in active scene.
* @param scene Scene entity
*/
getAssetManager(scene) {
if (scene) {
return this._assetManagers.get(scene.getComponent(Scene).object.uid);
}
else {
return this._assetManagers.get(this._activeScene.uid);
}
}
_render() {
getWorld(this).execute(this._engine.getDeltaTime(), performance.now());
getWorld(this).enabled && this._activeScene.render();
}
}
/** @hidden */
GameSystem.queries = {
scene: { components: [Scene], listen: { added: true, removed: true, changed: [Scene] } },
};
/** System for Transform component */
class TransformSystem extends ecsy.System {
/** @hidden */
execute() {
this.queries.transforms.changed.forEach((entity) => {
updateObjectsTransform(entity);
});
}
}
/** @hidden */
TransformSystem.queries = {
transforms: { components: [Transform], listen: { changed: [Transform] } },
};
/** @hidden */
function getSystem(self, target) {
return getWorld(self).getSystem(target);
}
/**
* @hidden
* Get canvas used for rendering.
* @param system A registered ecsy System class
*/
function getRenderingCanvas(system) {
return getSystem(system, GameSystem).renderingCanvas;
}
/**
* @hidden
* Get all scenes in engine.
* @param system A registered ecsy System class
*/
function getScenes(system) {
return getSystem(system, GameSystem).scenes;
}
/**
* Get a scene or return active scene.
* @param system A registered ecsy System class
* @param scene Scene entity
*/
function getScene(system, scene) {
if (scene) {
return scene.getComponent(Scene).object;
}
else {
return getSystem(system, GameSystem).activeScene;
}
}
/**
* Get scene AssetManager or return AssetManager in active scene.
* @param system A registered ecsy System class
* @param scene Scene entity
*/
function getAssetManager(system, scene) {
return getSystem(system, GameSystem).getAssetManager(scene);
}
/** System for Camera component */
class CameraSystem extends ecsy.System {
constructor() {
super(...arguments);
/** <BABYLON.Scene.uid, Camera component> */
this._cameras = new Map();
}
/** @hidden */
init() {
getSystem(this, GameSystem).onSceneSwitched.add(scene => this._updateControl(scene));
this._pointerLock = this._pointerLock.bind(this);
}
/** @hidden */
execute() {
this.queries.camera.added.forEach((entity) => {
let camera = entity.getComponent(Camera);
let scene = getScene(this, camera.scene);
camera.object = new BABYLON.FreeCamera("", BABYLON.Vector3.Zero(), scene);
updateObjectsTransform(entity);
this._cameras.set(scene.uid, camera);
this._updateControl(scene);
});
this.queries.camera.removed.forEach((entity) => {
let camera = entity.getComponent(Camera);
let scene = getScene(this, camera.scene);
this._removeControl(scene);
this._cameras.has(scene.uid) && this._cameras.delete(scene.uid);
disposeObject(camera);
});
}
_updateControl(targetScene) {
if (targetScene.uid === getScene(this).uid) {
getScenes(this).forEach(scene => this._removeControl(scene));
let camera = this._cameras.get(targetScene.uid);
camera.object.attachControl(getRenderingCanvas(this));
camera.pointerLock ? targetScene.onPointerObservable.add(this._pointerLock) : document.exitPointerLock();
}
}
_removeControl(scene) {
this._cameras.forEach((camera, sceneUID) => sceneUID === scene.uid && camera.object.detachControl(getRenderingCanvas(this)));
scene.onPointerObservable.removeCallback(this._pointerLock);
}
_pointerLock(pointerInfo) {
pointerInfo.event.type === "pointerdown" && (document.pointerLockElement || getRenderingCanvas(this).requestPointerLock());
}
}
/** @hidden */
CameraSystem.queries = {
camera: { components: [Camera], listen: { added: true, removed: true } },
};
/** System for Mesh component */
class MeshSystem extends ecsy.System {
/** @hidden */
execute() {
this.queries.mesh.added.forEach((entity) => {
this._updateMesh(entity, entity.getComponent(Mesh));
});
this.queries.mesh.changed.forEach((entity) => {
disposeObject(entity.getComponent(Mesh));
this._updateMesh(entity, entity.getComponent(Mesh));
});
this.queries.mesh.removed.forEach((entity) => {
disposeObject(entity.getComponent(Mesh));
});
}
_updateMesh(entity, mesh) {
switch (mesh.type) {
case MeshTypes.Url:
mesh.url && BABYLON.SceneLoader.IsPluginForExtensionAvailable(this._fileExt(mesh.url)) ?
this._loadUrlMesh(entity, mesh, mesh.url) :
this._unsupportedMesh(entity, mesh);
break;
default:
mesh.object = BABYLON.MeshBuilder[`Create${mesh.type}`].call(this, mesh.type, mesh.options ? mesh.options : {}, getScene(this, mesh.scene));
this._updateMeshValue(mesh);
updateObjectsTransform(entity);
break;
}
}
_fileExt(url) {
return url.substring(url.lastIndexOf("."), url.length);
}
_loadUrlMesh(entity, mesh, url) {
let assetManager = getAssetManager(this, mesh.scene);
let filenameIndex = url.lastIndexOf("/") + 1;
let task = assetManager.addMeshTask(mesh.type, "", url.substring(0, filenameIndex), url.substring(filenameIndex, url.length));
task.onSuccess = (task) => {
mesh.object = task.loadedMeshes[0];
this._updateMeshValue(mesh);
updateObjectsTransform(entity);
};
task.onError = () => { this._unsupportedMesh(entity, mesh); };
assetManager.load();
assetManager.reset();
}
_updateMeshValue(mesh) {
for (let prop in mesh) {
updateObjectValue(mesh, prop);
}
}
_unsupportedMesh(entity, mesh) {
let scene = getScene(this, mesh.scene);
mesh.object = BABYLON.MeshBuilder.CreatePlane("", {}, scene);
let material = new BABYLON.StandardMaterial("", scene);
const errorData = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAgMAAADXB5lNAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAMUExURSgoKCgoKCgoKO88OVVpm6AAAAACdFJOU/LlgHlY8AAAAP9JREFUOMvN1MFtwzAMBVB3nU7RcQsSKDcI96EPvrPAZ0nZkRUZKXKMb36xPr+UxMvX8nB9LDRdy+fj/ff7gES4bKYUBPYDdLOQcEgDY1cx6AqIjUADQFYvUNohkAFBEbFP+Y1MRAPboU1JOKdUj8rgp1BLWo+jaQutQUdotDuqMS+eRxblzM8F3kHDkIAD8kNxcBbukCuidmADaILcITOheST/g2wDVIYEX+Gckj2q7NkjmyYMTRlU4K/+HJQNEWttGDtIwZZffgcH8rkJgtFBC2h44oYCHeCWoRztUBugQP0E15pCP32JyzT2AiZT0zyL2gvd4T3+YpeXwfy6+ANZO9QlB5svlAAAAABJRU5ErkJggg==";
// BABYLON.Texture.BILINEAR_SAMPLINGMODE = 2
material.diffuseTexture = new BABYLON.Texture("data:errorData", scene, false, false, 2, null, null, errorData, true);
mesh.object.material = material;
updateObjectsTransform(entity);
}
}
/** @hidden */
MeshSystem.queries = {
mesh: { components: [Mesh], listen: { added: true, removed: true, changed: [Mesh] } },
};
/** System for Light component */
class LightSystem extends ecsy.System {
/** @hidden */
execute() {
this.queries.light.added.forEach((entity) => {
let light = entity.getComponent(Light);
let direction = xyzToVector3(light.direction);
let scene = getScene(this, light.scene);
switch (light.type) {
case LightTypes.Point:
light.object = new BABYLON.PointLight(light.type, BABYLON.Vector3.Zero(), scene);
break;
case LightTypes.Directional:
light.object = new BABYLON.DirectionalLight(light.type, direction, scene);
break;
case LightTypes.Spot:
light.object = new BABYLON.SpotLight(light.type, BABYLON.Vector3.Zero(), direction, degreeToRadians(light.angle), light.exponent, scene);
break;
default:
light.object = new BABYLON.HemisphericLight(LightTypes.Hemispheric, direction, scene);
break;
}
this._updateLight(light);
updateObjectsTransform(entity);
});
this.queries.light.changed.forEach((entity) => {
this._updateLight(entity.getComponent(Light));
});
this.queries.light.removed.forEach((entity) => {
disposeObject(entity.getComponent(Light));
});
}
_updateLight(light) {
for (let prop in light) {
switch (prop) {
case "direction":
updateObjectVector3(light, prop);
break;
case "color":
this._updateColor(light, light.color);
break;
default:
updateObjectValue(light, prop);
break;
}
}
}
_updateColor(light, color) {
for (let prop in color) {
light.object[prop] = hexToColor3(color[prop]);
}
}
}
/** @hidden */
LightSystem.queries = {
light: { components: [Light], listen: { added: true, removed: true, changed: [Light] } },
};
/** System for Material component */
class MaterialSystem extends ecsy.System {
/** @hidden */
execute() {
this.queries.meshMaterial.added.forEach((entity) => {
if (!this._isUrlMesh(entity)) {
let material = entity.getComponent(Material);
material.object = new BABYLON.StandardMaterial(material.color.diffuse, getScene(this, material.scene));
this._updateMaterial(material);
let mesh = entity.getComponent(Mesh);
mesh.object.material = material.object;
}
});
this.queries.meshMaterial.changed.forEach((entity) => {
this._isUrlMesh(entity) || this._updateMaterial(entity.getComponent(Material));
});
this.queries.meshMaterial.removed.forEach((entity) => {
if (!this._isUrlMesh(entity)) {
disposeObject(entity.getComponent(Material));
entity.getComponent(Mesh).object.material = null;
}
});
}
_isUrlMesh(entity) {
return entity.getComponent(Mesh).type === MeshTypes.Url;
}
_updateMaterial(material) {
for (let prop in material) {
switch (prop) {
case "color":
this._updateColor(material, material.color);
break;
case "texture":
updateTexture(material, material.texture, getAssetManager(this, material.scene));
break;
default:
updateObjectValue(material, prop);
break;
}
}
}
_updateColor(material, color) {
for (let prop in color) {
(material.object[`${prop}Color`] = hexToColor3(color[prop]));
}
}
}
/** @hidden */
MaterialSystem.queries = {
meshMaterial: { components: [Mesh, Material], listen: { added: true, removed: true, changed: [Material] } },
};
/** System for Particle component */
class ParticleSystem extends ecsy.System {
/** @hidden */
execute() {
this.queries.particle.added.forEach((entity) => {
let particle = entity.getComponent(Particle);
particle.object = new BABYLON.ParticleSystem(particle.type, particle.capacity, getScene(this, particle.scene));
let particleObject = particle.object;
switch (particle.type) {
case ParticleTypes.Point:
particleObject.createPointEmitter(xyzToVector3(particle.direction1), xyzToVector3(particle.direction2));
break;
case ParticleTypes.Box:
particleObject.createBoxEmitter(xyzToVector3(particle.direction1), xyzToVector3(particle.direction2), xyzToVector3(particle.minEmitBox), xyzToVector3(particle.maxEmitBox));
break;
case ParticleTypes.Sphere:
particleObject.createSphereEmitter(particle.radius, particle.radiusRange);
break;
case ParticleTypes.DirectedSphere:
particleObject.createDirectedSphereEmitter(particle.radius, xyzToVector3(particle.direction1), xyzToVector3(particle.direction2));
break;
case ParticleTypes.Hemisphere:
particleObject.createHemisphericEmitter(particle.radius, particle.radiusRange);
break;
case ParticleTypes.Cylinder:
particleObject.createCylinderEmitter(particle.radius, particle.height, particle.radiusRange, Math.random());
break;
case ParticleTypes.DirectedCylinder:
particleObject.createDirectedCylinderEmitter(particle.radius, particle.height, particle.radiusRange, xyzToVector3(particle.direction1), xyzToVector3(particle.direction2));
break;
case ParticleTypes.Cone:
particleObject.createConeEmitter(particle.radius, particle.angle);
break;
}
this._updateParticle(particle);
updateObjectsTransform(entity);
particleObject.start();
});
this.queries.particle.changed.forEach((entity) => {
this._updateParticle(entity.getComponent(Particle));
});
this.queries.particle.removed.forEach((entity) => {
let particle = entity.getComponent(Particle);
particle.object.stop();
disposeObject(particle);
});
}
_updateParticle(particle) {
for (let prop in particle) {
switch (prop) {
case "emitter":
case "direction1":
case "direction2":
case "minEmitBox":
case "maxEmitBox":
updateObjectVector3(particle, prop);
break;
case "texture":
updateTexture(particle, particle.texture, getAssetManager(this, particle.scene));
break;
case "color":
this._updateColor(particle, particle.color);
break;
default:
updateObjectValue(particle, prop);
break;
}
}
}
_updateColor(particle, color) {
for (let prop in color) {
particle.object[prop] = hexToColor4(color[prop]);
}
}
}
/** @hidden */
ParticleSystem.queries = {
particle: { components: [Particle], listen: { added: true, removed: true, changed: [Particle] } },
};
/** System for Input component */
class InputSystem extends ecsy.System {
constructor() {
super(...arguments);
this._inputs = new Map();
}
init() {
getSystem(this, GameSystem).onSceneSwitched.add(scene => this._updateOnKey(scene));
this._onKey = this._onKey.bind(this);
}
/** @hidden */
execute() {
this.queries.input.added.forEach((entity) => {
let input = entity.getComponent(Input);
let scene = getScene(this, input.scene);
switch (input.type) {
default:
if (!this._inputs.has(scene.uid)) {
this._inputs.set(scene.uid, input);
this._updateOnKey(scene);
}
break;
}
});
this.queries.input.removed.forEach((entity) => {
let input = entity.getComponent(Input);
let scene = getScene(this, input.scene);
switch (input.type) {
default:
if (this._inputs.has(scene.uid)) {
this._inputs.delete(scene.uid);
this._removeOnKey(scene);
}
break;
}
});
}
_updateOnKey(targetScene) {
if (targetScene.uid === getScene(this).uid) {
getScenes(this).forEach(scene => this._removeOnKey(scene));
this._input = this._inputs.get(targetScene.uid);
this._input.onKey && targetScene.onKeyboardObservable.add(this._onKey);
}
}
_removeOnKey(scene) {
scene.onKeyboardObservable.removeCallback(this._onKey);
}
_onKey(keyInfo) {
// BABYLON.KeyboardEventTypes.KEYDOWN = 1, BABYLON.KeyboardEventTypes.KEYUP = 2
this._input.onKey.call(this._input, keyInfo.event.key, keyInfo.type === 1, keyInfo.type === 2);
}
}
/** @hidden */
InputSystem.queries = {
input: { components: [Input], listen: { added: true, removed: true } },
};
var EB = /*#__PURE__*/Object.freeze({
__proto__: null,
GameSystem: GameSystem,
TransformSystem: TransformSystem,
CameraSystem: CameraSystem,
MeshSystem: MeshSystem,
LightSystem: LightSystem,
MaterialSystem: MaterialSystem,
ParticleSystem: ParticleSystem,
InputSystem: InputSystem,
Scene: Scene,
Transform: Transform,
Camera: Camera,
get MeshTypes () { return MeshTypes; },
Mesh: Mesh,
get LightTypes () { return LightTypes; },
Light: Light,
Material: Material,
get ParticleTypes () { return ParticleTypes; },
Particle: Particle,
get InputTypes () { return InputTypes; },
Input: Input,
getScene: getScene,
getAssetManager: getAssetManager,
degreeToRadians: degreeToRadians,
xyzToVector3: xyzToVector3,
xyzToVector3Radians: xyzToVector3Radians,
hexToColor3: hexToColor3,
hexToColor4: hexToColor4
});
window.EB = EB;
}(BABYLON, ECSY));