Skip to content

Commit

Permalink
v1.1.4 squash nested sequences, fix speedBy(), reformat
Browse files Browse the repository at this point in the history
  • Loading branch information
reececomo committed Apr 25, 2024
1 parent 85d3bb2 commit 6c290f4
Show file tree
Hide file tree
Showing 30 changed files with 246 additions and 135 deletions.
16 changes: 7 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ You can customize the speed curve of actions like so:

```ts
// Use the defaults
Action.fadeIn(0.3).easeInOut();
Action.fadeIn(0.3).easeIn();
Action.fadeIn(0.3).easeOut();
Action.fadeIn(0.3).easeInOut();

// Set a TimingMode
Action.fadeIn(0.3).setTimingMode(TimingMode.easeInOutCubic);
Expand Down Expand Up @@ -222,17 +222,15 @@ Actions are stateless and reusable, so you can create complex animations once, a
```ts
/** A nice gentle rock back and forth. */
const rockBackAndForth = Action.repeatForever(
Action.sequence([
Action.group([
Action.group([
Action.sequence([
Action.moveByX(5, 0.33).easeOut(),
Action.rotateByDegrees(-2, 0.33).easeOut(),
]),
Action.group([
Action.moveByX(-10, 0.34).easeInOut(),
Action.rotateByDegrees(4, 0.34).easeInOut(),
]),
Action.group([
Action.moveByX(5, 0.33).easeIn(),
]),
Action.sequence([
Action.rotateByDegrees(-2, 0.33).easeOut(),
Action.rotateByDegrees(4, 0.34).easeInOut(),
Action.rotateByDegrees(-2, 0.33).easeIn(),
]),
])
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pixijs-actions",
"version": "1.1.3",
"version": "1.1.4",
"author": "Reece Como <[email protected]>",
"authors": [
"Reece Como <[email protected]>",
Expand Down
4 changes: 2 additions & 2 deletions src/Action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
FadeByAction,
FadeInAction,
FadeOutAction,
FadeToAction,
FadeAlphaToAction,
FollowPathAction,
GroupAction,
MoveByAction,
Expand Down Expand Up @@ -479,7 +479,7 @@ export abstract class _ extends Action {
* change anything.
*/
public static fadeAlphaTo(alpha: number, duration: TimeInterval): Action {
return new FadeToAction(alpha, duration);
return new FadeAlphaToAction(alpha, duration);
}

/**
Expand Down
111 changes: 110 additions & 1 deletion src/__tests__/Action.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ describe('Action Chaining', () => {
simulateTime(1.0);
expect(node.position.x).toBeCloseTo(10.0);


simulateTime(1.0);
expect(node.position.x).toBeCloseTo(5.0);

Expand All @@ -90,6 +89,68 @@ describe('Action Chaining', () => {
expect(node.position.x).toBeCloseTo(-5.0);
expect(node.hasActions()).toBe(false);
});

it('successfully completes nested sequences', () => {
// this test secretly makes sure squashing works
const action = Action.sequence([
Action.sequence([
Action.sequence([
Action.moveByX(5, 1.0),
Action.moveByX(-5, 1.0)
]),
Action.sequence([
Action.sequence([
Action.moveByX(5, 1.0),
Action.moveByX(5, 1.0),
]),
Action.sequence([ // Runs with custom timing mode
Action.rotateBy(Math.PI, 0.5),
Action.rotateBy(Math.PI, 0.5),
]).easeInOut(),
]),
Action.group([ // Also has 'actions' but not a SequenceAction
Action.fadeOut(0.5),
Action.scaleTo({ width: 2, height: 2 }, 1.0),
]),
]),
Action.sequence([
Action.sequence([
Action.moveByY(-5, 1.0),
Action.moveByY(5, 1.0),
]),
Action.sequence([
Action.sequence([
Action.moveByY(5, 1.0),
Action.moveByY(5, 1.0),
]),
Action.sequence([ // Runs at half speed
Action.fadeAlphaTo(0.25, 1.0),
Action.fadeAlphaBy(0.5, 1.0),
]).setSpeed(2),
]),
]),
]);

expect(action.duration).toBeCloseTo(11.0);
expect(action.scaledDuration).toBeCloseTo(11.0);

const node = new Container();
node.run(action);

simulateTime(11.0);
expect(node.position.x).toBeCloseTo(10);
expect(node.position.y).toBeCloseTo(10);
expect(node.rotation).toBeCloseTo(Math.PI * 2);
expect(node.alpha).toBeCloseTo(0.75);

// Sanity check: We completed.
expect(node.hasActions()).toBe(false);

// Ignore that this tests the underlying implementation.
// Just a lazy hack to make sure it's working nicely.
expect((action as any).actions.length).toBe(2);
expect((action as any)._squashedActions().length).toBe(11);
});
});

describe('group()', () => {
Expand Down Expand Up @@ -373,6 +434,54 @@ describe('Action', () => {
expect(childNode.hasActions()).toBe(false);
});
});

describe('speedTo()', () => {
it('changes the nodes action speed', () => {
const myNode = new Container();

myNode.run(Action.speedTo(2, 0));

simulateTime(0.01, 1);

expect(myNode.speed).toBeCloseTo(2);
});

it('changes the nodes action speed over time', () => {
const myNode = new Container();

myNode.run(Action.speedTo(2, 10.0));

simulateTime(8.0);

// Completes early because speed changes
expect(myNode.speed).toBeCloseTo(2);
expect(myNode.hasActions()).toBe(false);
});
});

describe('speedBy()', () => {
it('changes the nodes action speed', () => {
const myNode = new Container();

myNode.run(Action.speedBy(1, 0));

simulateTime(0.01, 1);

expect(myNode.speed).toBeCloseTo(2);
});

it('changes the nodes action speed over time', () => {
const myNode = new Container();

myNode.run(Action.speedBy(1, 10.0));

simulateTime(8.0);

// Completes early because speed changes
expect(myNode.speed).toBeCloseTo(2);
expect(myNode.hasActions()).toBe(false);
});
});
});

describe('Action and nodes', () => {
Expand Down
7 changes: 1 addition & 6 deletions src/actions/chainable/GroupAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@ export class GroupAction extends Action {
public constructor(
protected readonly actions: Action[]
) {
super(
// Max duration:
Math.max(...actions.map(action => action.scaledDuration))
);

this.actions = actions;
super(Math.max(...actions.map(action => action.scaledDuration)));
}

public reversed(): Action {
Expand Down
24 changes: 13 additions & 11 deletions src/actions/chainable/RepeatAction.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@

import { Action } from '../../lib/Action';
import { IActionTicker } from '../../lib/IActionTicker';
import { ActionTicker } from '../../lib/ActionTicker';

export class RepeatAction extends Action {
public constructor(
protected readonly action: Action,
protected readonly repeats: number,
protected readonly action: Action,
protected readonly repeats: number,
) {
super(
// Duration:
action.scaledDuration * repeats
);
super(action.scaledDuration * repeats);

if (Math.round(repeats) !== repeats || repeats < 0) {
throw new Error('Repeats must be a positive integer.');
if (!Number.isInteger(repeats) || repeats < 0) {
throw new RangeError('The number of repeats must be a positive integer.');
}
}

Expand All @@ -36,8 +32,14 @@ export class RepeatAction extends Action {
};
}

protected onTick(target: TargetNode, t: number, dt: number, ticker: IActionTicker, deltaTime: number): void {
let childTicker: IActionTicker = ticker.data.childTicker;
protected onTick(
target: TargetNode,
t: number,
dt: number,
ticker: IActionTicker,
deltaTime: number
): void {
const childTicker: IActionTicker = ticker.data.childTicker;
let remainingTimeDelta = deltaTime * this.speed;

remainingTimeDelta = childTicker.tick(remainingTimeDelta);
Expand Down
9 changes: 5 additions & 4 deletions src/actions/chainable/RepeatForeverAction.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@

import { Action } from '../../lib/Action';
import { IActionTicker } from '../../lib/IActionTicker';
import { ActionTicker } from '../../lib/ActionTicker';

export class RepeatForeverAction extends Action {
public constructor(
protected readonly action: Action
protected readonly action: Action
) {
super(Infinity);

if (action.duration <= 0) {
throw new Error('The action to be repeated must have a non-instantaneous duration.');
if (action.scaledDuration <= 0) {
throw new TypeError('The action to be repeated must have a non-instantaneous duration.');
}
}

Expand All @@ -21,6 +20,8 @@ export class RepeatForeverAction extends Action {
}

protected onSetupTicker(target: TargetNode, ticker: IActionTicker): any {
ticker.autoComplete = false;

const childTicker = new ActionTicker(undefined, target, this.action);
childTicker.timingMode = (x: number) => ticker.timingMode(childTicker.timingMode(x));

Expand Down
33 changes: 26 additions & 7 deletions src/actions/chainable/SequenceAction.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { Action } from '../../lib/Action';
import { IActionTicker } from '../../lib/IActionTicker';
import { ActionTicker } from '../../lib/ActionTicker';
import { TimingMode } from '../../TimingMode';

export class SequenceAction extends Action {
public constructor(
protected readonly actions: Action[]
protected actions: Action[]
) {
super(
// Total duration:
actions.reduce((total, action) => total + action.scaledDuration, 0)
);
this.actions = actions;
super(actions.reduce((total, action) => total + action.scaledDuration, 0));
}

public reversed(): Action {
Expand All @@ -23,7 +20,8 @@ export class SequenceAction extends Action {
ticker.autoComplete = false;

return {
childTickers: this.actions.map(action => new ActionTicker(undefined, target, action))
childTickers: this._squashedActions()
.map(action => new ActionTicker(undefined, target, action))
};
}

Expand Down Expand Up @@ -62,4 +60,25 @@ export class SequenceAction extends Action {
protected onTickerDidReset(ticker: IActionTicker): any {
ticker.data.childTickers.forEach((ticker: IActionTicker) => ticker.reset());
}

// ----- Implementation: -----

protected _squashedActions(): Action[] {
const actions: Action[] = [];

for (const action of this.actions) {
if (
action instanceof SequenceAction
&& action.speed === 1
&& action.timingMode === TimingMode.linear
) {
actions.push(...action._squashedActions());
}
else {
actions.push(action);
}
}

return actions;
}
}
3 changes: 1 addition & 2 deletions src/actions/custom/CustomAction.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@

import { Action } from '../../lib/Action';

export class CustomAction extends Action {
public constructor(
duration: TimeInterval,
protected readonly stepFn: (target: TargetNode, t: number, dt: number) => void
protected readonly stepFn: (target: TargetNode, t: number, dt: number) => void
) {
super(duration);
}
Expand Down
3 changes: 1 addition & 2 deletions src/actions/custom/RunBlockAction.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@

import { Action } from '../../lib/Action';

export class RunBlockAction extends Action {
public constructor(
protected readonly block: () => void
protected readonly block: () => void
) {
super(0);
}
Expand Down
1 change: 0 additions & 1 deletion src/actions/delay/DelayAction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import { Action } from '../../lib/Action';

export class DelayAction extends Action {
Expand Down
4 changes: 2 additions & 2 deletions src/actions/display-object/RunOnChildWithNameAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Action } from '../../lib/Action';

export class RunOnChildWithNameAction extends Action {
public constructor(
protected readonly action: Action,
protected readonly name: string,
protected readonly action: Action,
protected readonly name: string,
) {
super(0);
}
Expand Down
2 changes: 1 addition & 1 deletion src/actions/display-object/SetVisibleAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Action } from '../../lib/Action';

export class SetVisibleAction extends Action {
public constructor(
protected readonly visible: boolean,
protected readonly visible: boolean,
) {
super(0);
}
Expand Down
Loading

0 comments on commit 6c290f4

Please sign in to comment.