feat: LFO
This commit is contained in:
parent
b11be0c0a3
commit
e2fe91dffd
|
@ -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]);
|
||||
return modulatorFunction(modulator.f)(modulator);
|
||||
});
|
||||
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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user