silphius/app/ecs/components/sprite.js
2024-08-04 21:56:31 -05:00

215 lines
5.7 KiB
JavaScript

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) {
const [, s, l] = hexToHsl(this.$$tint);
this.tint = hslToHex(hue, s, l);
}
initialize(values, defaults) {
let {
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;
}
get lightness() {
return this.$$lightness;
}
set lightness(lightness) {
const [h, s] = hexToHsl(this.$$tint);
this.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) {
const [h, , l] = hexToHsl(this.$$tint);
this.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'},
};
}