feat: LFO

This commit is contained in:
cha0s 2021-02-04 00:03:54 -06:00
parent b11be0c0a3
commit e2fe91dffd
3 changed files with 73 additions and 38 deletions

View File

@ -1,5 +1,5 @@
import {Property} from '@avocado/core';
import {compose, EventEmitter} from '@latus/core';
import {Class, compose, EventEmitter} from '@latus/core';
import Transition from '../transition';
@ -33,23 +33,24 @@ const decorate = compose(
}),
Property('magnitude', {
default: 0,
track: true,
}),
EventEmitter,
);
class ModulatedProperty {
export default class ModulatedProperty extends decorate(Class) {
constructor(
object, key,
{
factor = 1,
frequency,
location,
location = 0,
magnitude,
median,
modulators,
},
) {
super();
this.object = object;
this.key = key;
if (!modulators) {
@ -60,14 +61,13 @@ class ModulatedProperty {
// eslint-disable-next-line no-param-reassign
modulators = [modulators];
}
this.factor = factor;
this.median = median;
this.on('magnitudeChanged', this.onMagnitudeChanged, this);
this.setFrequency(frequency);
this.setLocation(location || 0);
this.setMagnitude(magnitude);
if (this.median) {
this.min = this.median - magnitude;
}
this.frequency = frequency;
this.location = location;
this.magnitude = magnitude;
this.median = 'undefined' === typeof median ? magnitude / 2 : median;
this.min = this.median - (magnitude / 2);
const modulatorFunction = (modulator) => {
if ('string' === typeof modulator) {
return Modulator[modulator] ? Modulator[modulator] : Modulator.Linear;
@ -81,41 +81,27 @@ class ModulatedProperty {
if ('object' !== typeof modulator) {
return modulatorFunction(modulator)(modulator);
}
if (modulator.f) {
return modulatorFunction(modulator.f)(modulator);
}
// eslint-disable-next-line no-param-reassign
[key] = Object.keys(modulator);
return modulatorFunction(key)(modulator[key]);
});
this.transitions = [];
}
destroy() {
this.off('magnitudeChanged', this.onMagnitudeChanged);
}
onMagnitudeChanged() {
this.magnitude2 = this.magnitude() * 2;
}
tick(elapsed) {
this.transitions.forEach((transition) => {
transition.tick(elapsed);
});
const frequency = this.frequency();
let location = this.location();
for (let i = 0; i < this.transitions.length; i++) {
this.transitions[i].tick(elapsed);
}
const {frequency} = this;
let {location} = this;
location += elapsed;
if (location > frequency) {
if (location >= frequency) {
location -= frequency;
}
this.setLocation(location);
const min = this.median ? this.min : this.object[this.key];
this.location = location;
const value = this.modulators.reduce(
(value, m) => value + m(location / frequency),
0,
) / this.modulators.length;
this.object[this.key] = min + value * this.magnitude2;
this.object[this.key] = this.min + this.factor * value * this.magnitude;
}
transition(...args) {
@ -128,5 +114,3 @@ class ModulatedProperty {
}
}
export default decorate(ModulatedProperty);

View File

@ -1,5 +1,6 @@
import {TickingPromise} from '@avocado/core';
import LfoResult from '../../lfo/result';
import TransitionResult from '../../transition/result';
export default (Entity) => class EvolvingEntity extends Entity {
@ -10,6 +11,20 @@ export default (Entity) => class EvolvingEntity extends Entity {
...description,
children: {
...description.children,
lfo: {
args: [
{
label: 'Properties',
type: 'object',
},
{
label: 'Duration',
type: 'number',
},
],
label: 'Oscillates properties.',
type: 'void',
},
transition: {
args: [
{
@ -28,6 +43,22 @@ export default (Entity) => class EvolvingEntity extends Entity {
};
}
lfo(props, duration, context) {
if (!context) {
// eslint-disable-next-line no-param-reassign
duration = 0;
}
const result = new LfoResult(this, props, duration);
return new TickingPromise(
(resolve) => {
resolve(result.promise);
},
(elapsed) => {
result.tick(elapsed);
},
);
}
transition(props, duration, easing) {
const result = new TransitionResult(this, props, duration, easing);
return new TickingPromise(

View File

@ -1,5 +1,25 @@
import {expect} from 'chai';
it('exists', () => {
expect(true).to.be.true;
import LfoResult from '../src/lfo/result';
it('can do linear oscillation', () => {
const object = {x: 0};
const result = new LfoResult(
object,
{
x: {
frequency: 1,
magnitude: 100,
median: 50,
},
},
);
result.tick(0.1);
expect(object.x).to.equal(10);
result.tick(0.5);
expect(object.x).to.equal(60);
result.tick(0.25);
expect(object.x).to.equal(85);
result.tick(0.4);
expect(object.x).to.equal(25);
});