From b9cbccede8b400486a304e2377616634c40b0d57 Mon Sep 17 00:00:00 2001 From: cha0s Date: Mon, 18 Mar 2019 22:20:03 -0500 Subject: [PATCH] feat: Animated trait --- packages/entity/traits/animated.js | 96 ++++++++++++++++++++++++++++++ packages/entity/traits/registry.js | 3 + 2 files changed, 99 insertions(+) create mode 100644 packages/entity/traits/animated.js diff --git a/packages/entity/traits/animated.js b/packages/entity/traits/animated.js new file mode 100644 index 0000000..481d865 --- /dev/null +++ b/packages/entity/traits/animated.js @@ -0,0 +1,96 @@ +import {compose} from '@avocado/core'; +import {Image, Sprite} from '@avocado/graphics'; +import {Vector} from '@avocado/math'; + +import {simpleState, Trait} from '../trait'; + +const decorate = compose( + simpleState('currentFrame', { + track: true, + }), +); + +class AnimatedBase extends Trait { + + static defaultParams() { + return { + frameCount: 0, + frameRate: 0, + frameSize: [0, 0], + image: '', + }; + } + + static defaultState() { + return { + currentFrame: 0, + }; + } + + constructor(entity) { + super(entity); + this.sprite = undefined; + } + + get frameRect() { + const direction = ('direction' in this.entity) ? this.entity.direction : 0; + return [ + this.entity.currentFrame * this.frameSize[0], + direction * this.frameSize[1], + this.frameSize[0], + this.frameSize[1], + ]; + } + + fromJSON(json) { + super.fromJSON(json); + this.frameCount = json.params.frameCount; + this.frameRate = json.params.frameRate; + this.frameSize = json.params.frameSize; + this.image = json.params.image; + this.frameCaret = this.frameRate; + return this; + } + + listeners() { + return { + currentFrameChanged: () => { + if (this.sprite) { + this.sprite.sourceRectangle = this.frameRect; + } + }, + directionChanged: () => { + if (this.sprite) { + this.sprite.sourceRectangle = this.frameRect; + } + }, + tick: (elapsed) => { + this.frameCaret -= elapsed; + if (this.frameCaret > 0) { + return; + } + const newFrame = (this.entity.currentFrame + 1) % this.frameCount; + this.entity.currentFrame = newFrame; + if (this.frameCaret < 0) { + this.frameCaret = this.frameRate - this.frameCaret; + } + }, + traitAdded: (trait) => { + if ('graphical' !== trait.constructor.type()) { + return; + } + if (!this.entity.container.isValid) { + return; + } + Image.load(this.image).then((image) => { + this.sprite = new Sprite(image); + this.sprite.sourceRectangle = this.frameRect; + this.entity.container.addChild(this.sprite); + }); + }, + }; + } + +} + +export class Animated extends decorate(AnimatedBase) {} diff --git a/packages/entity/traits/registry.js b/packages/entity/traits/registry.js index 25621fc..22c51e9 100644 --- a/packages/entity/traits/registry.js +++ b/packages/entity/traits/registry.js @@ -16,6 +16,9 @@ export function lookupTrait(type) { } // Register core traits. +import {Animated} from './animated'; +registerTrait(Animated); + import {Directional} from './directional'; registerTrait(Directional);