import Component from '@/ecs/component.js'; import {hexToHsl, hslToHex} from '@/util/color.js'; export default class Sprite extends Component { instanceFromSchema() { return class SpriteInstance extends super.instanceFromSchema() { $$anchor = {x: 0.5, y: 0.5}; $$hue = 0; $$saturation = 0; $$lightness = 1; $$scale = {x: 1, y: 1}; $$sourceJson = {}; get anchor() { return this.$$anchor; } get anchorX() { return this.$$anchor.x; } set anchorX(anchorX) { this.$$anchor = {x: anchorX, y: this.anchorY}; super.anchorX = anchorX; } get anchorY() { return this.$$anchor.y; } set anchorY(anchorY) { this.$$anchor = {x: this.anchorX, y: anchorY}; super.anchorY = anchorY; } get animation() { return super.animation; } set animation(animation) { if (this.$$animation === animation) { return; } super.animation = animation; // eslint-disable-next-line no-self-assign this.frame = this.frame; } get frame() { return super.frame; } set frame(frame) { super.frame = this.frames ? frame % this.frames : 0; } get frames() { if ( !this.animation || !this.$$sourceJson.animations || !(this.animation in this.$$sourceJson.animations) ) { return 0; } return this.$$sourceJson.animations[this.animation].length; } hasAnimation(animation) { if ( !this.$$sourceJson.animations || !(animation in this.$$sourceJson.animations) ) { return false; } return true; } get hue() { return this.$$hue; } set hue(hue) { this.$$hue = hue; const [, s, l] = hexToHsl(this.$$tint); super.tint = hslToHex(hue, s, l); } initialize(values, defaults) { let { animation = defaults.animation, anchorX = defaults.anchorX, anchorY = defaults.anchorY, frame = defaults.frame, scaleX = defaults.scaleX, scaleY = defaults.scaleY, } = values; this.$$anchor = {x: anchorX, y: anchorY}; this.$$scale = {x: scaleX, y: scaleY}; super.initialize(values, defaults); this.frame = frame; this.animation = animation; } get lightness() { return this.$$lightness; } set lightness(lightness) { this.$$lightness = lightness; const [h, s] = hexToHsl(this.$$tint); super.tint = hslToHex(h, s, lightness); } get rotates() { if (!this.$$sourceJson.meta) { return false; } return 'rotation' in this.$$sourceJson.meta; } get rotation() { if (!this.$$sourceJson.meta) { return 0; } return this.$$sourceJson.meta.rotation; } get saturation() { return this.$$saturation; } set saturation(saturation) { this.$$saturation = saturation; const [h, , l] = hexToHsl(this.$$tint); super.tint = hslToHex(h, saturation, l); } get scale() { return this.$$scale; } set scale(scale) { if ('number' === typeof scale) { scale = {x: scale, y: scale}; } this.scaleX = scale.x; this.scaleY = scale.y; } get scaleX() { return this.$$scale.x; } set scaleX(scaleX) { this.$$scale = {x: scaleX, y: this.scaleY}; super.scaleX = scaleX; } get scaleY() { return this.$$scale.y; } set scaleY(scaleY) { this.$$scale = {x: this.scaleX, y: scaleY}; super.scaleY = scaleY; } get size() { if (!this.$$sourceJson.frames) { return {x: 16, y: 16}; } const frame = this.animation ? this.$$sourceJson.animations[this.animation][this.frame] : ''; return this.$$sourceJson.frames[frame].sourceSize; } get tint() { return super.tint; } set tint(tint) { [ this.$$hue, this.$$saturation, this.$$lightness, ] = hexToHsl(tint) super.tint = tint; } toNet(recipient, data) { // eslint-disable-next-line no-unused-vars const {elapsed, ...rest} = super.toNet(recipient, data); return rest; } update(values) { for (const key in values) { switch (key) { case 'anchorX': { this.$$anchor.x = values[key]; break; } case 'anchorY': { this.$$anchor.y = values[key]; break; } case 'scaleX': { this.$$scale.x = values[key]; break; } case 'scaleY': { this.$$scale.y = values[key]; break; } default: { continue; } } } return super.update(values); } }; } async load(instance) { if (instance.source) { instance.$$sourceJson = await this.ecs.readJson(instance.source); } } markChange(entityId, key, value) { if ('elapsed' === key) { return; } super.markChange(entityId, key, value); } static properties = { alpha: {defaultValue: 1, type: 'float32'}, anchorX: {defaultValue: 0.5, type: 'float32'}, anchorY: {defaultValue: 0.5, type: 'float32'}, animation: {type: 'string'}, elapsed: {type: 'float32'}, frame: {type: 'uint16'}, isAnimating: {defaultValue: 1, type: 'uint8'}, scaleX: {defaultValue: 1, type: 'float32'}, scaleY: {defaultValue: 1, type: 'float32'}, source: {type: 'string'}, speed: {type: 'float32'}, tint: {defaultValue: 0xffffff, type: 'uint32'}, }; }