| Index: sky/sdk/example/game/lib/action.dart
|
| diff --git a/sky/sdk/example/game/lib/action.dart b/sky/sdk/example/game/lib/action.dart
|
| index 0c6119d528a3937a7b938b18fba62953699ac465..54073173e09704e9f75bb4c1c9825c0b4dbd6bfe 100644
|
| --- a/sky/sdk/example/game/lib/action.dart
|
| +++ b/sky/sdk/example/game/lib/action.dart
|
| @@ -5,11 +5,16 @@ typedef void ActionCallback();
|
| abstract class Action {
|
| Object _tag;
|
| bool _finished = false;
|
| + bool _added = false;
|
|
|
| void step(double dt);
|
| void update(double t) {
|
| }
|
|
|
| + void _reset() {
|
| + _finished = false;
|
| + }
|
| +
|
| double get duration => 0.0;
|
| }
|
|
|
| @@ -20,8 +25,9 @@ abstract class ActionInterval extends Action {
|
| double _elapsed = 0.0;
|
|
|
| double get duration => _duration;
|
| + Curve curve;
|
|
|
| - ActionInterval([this._duration = 0.0]);
|
| + ActionInterval([this._duration = 0.0, this.curve]);
|
|
|
| void step(double dt) {
|
| if (_firstTick) {
|
| @@ -37,7 +43,11 @@ abstract class ActionInterval extends Action {
|
| t = (_elapsed / _duration).clamp(0.0, 1.0);
|
| }
|
|
|
| - update(t);
|
| + if (curve == null) {
|
| + update(t);
|
| + } else {
|
| + update(curve.transform(t));
|
| + }
|
|
|
| if (t >= 1.0) _finished = true;
|
| }
|
| @@ -46,13 +56,53 @@ abstract class ActionInterval extends Action {
|
| class ActionRepeat extends ActionInterval {
|
| final int numRepeats;
|
| final ActionInterval action;
|
| + int _lastFinishedRepeat = -1;
|
|
|
| ActionRepeat(this.action, this.numRepeats) {
|
| _duration = action.duration * numRepeats;
|
| }
|
|
|
| void update(double t) {
|
| - action.update((t * numRepeats.toDouble()) % numRepeats.toDouble());
|
| + int currentRepeat = Math.min((t * numRepeats.toDouble()).toInt(), numRepeats - 1);
|
| + for (int i = Math.max(_lastFinishedRepeat, 0); i < currentRepeat; i++) {
|
| + if (!action._finished) action.update(1.0);
|
| + action._reset();
|
| + }
|
| + _lastFinishedRepeat = currentRepeat;
|
| +
|
| + double ta = (t * numRepeats.toDouble()) % 1.0;
|
| + action.update(ta);
|
| +
|
| + if (t >= 1.0) {
|
| + action.update(1.0);
|
| + action._finished = true;
|
| + }
|
| + }
|
| +}
|
| +
|
| +class ActionRepeatForever extends Action {
|
| + final ActionInterval action;
|
| + double _elapsedInAction = 0.0;
|
| +
|
| + ActionRepeatForever(this.action);
|
| +
|
| + step(double dt) {
|
| + _elapsedInAction += dt;
|
| + while (_elapsedInAction > action.duration) {
|
| + _elapsedInAction -= action.duration;
|
| + if (!action._finished) action.update(1.0);
|
| + action._reset();
|
| + }
|
| + _elapsedInAction = Math.max(_elapsedInAction, 0.0);
|
| +
|
| + double t;
|
| + if (action._duration == 0.0) {
|
| + t = 1.0;
|
| + } else {
|
| + t = (_elapsedInAction / action._duration).clamp(0.0, 1.0);
|
| + }
|
| +
|
| + action.update(t);
|
| }
|
| }
|
|
|
| @@ -91,21 +141,107 @@ class ActionSequence extends ActionInterval {
|
| } else {
|
| ta = 1.0;
|
| }
|
| - _a.update(ta);
|
| + _updateWithCurve(_a, ta);
|
| } else if (t >= 1.0) {
|
| // Make sure everything is finished
|
| - if (!_a._finished) _a.update(1.0);
|
| - if (!_b._finished) _b.update(1.0);
|
| + if (!_a._finished) _finish(_a);
|
| + if (!_b._finished) _finish(_b);
|
| } else {
|
| // Play second action, but first make sure the first has finished
|
| - if (!_a._finished) _a.update(1.0);
|
| + if (!_a._finished) _finish(_a);
|
| double tb;
|
| if (_split < 1.0) {
|
| tb = (1.0 - (1.0 - t) / (1.0 - _split)).clamp(0.0, 1.0);
|
| } else {
|
| tb = 1.0;
|
| }
|
| - _b.update(tb);
|
| + _updateWithCurve(_b, tb);
|
| + }
|
| + }
|
| +
|
| + void _updateWithCurve(Action action, double t) {
|
| + if (action is ActionInterval) {
|
| + ActionInterval actionInterval = action;
|
| + if (actionInterval.curve == null) {
|
| + action.update(t);
|
| + } else {
|
| + action.update(actionInterval.curve.transform(t));
|
| + }
|
| + } else {
|
| + action.update(t);
|
| + }
|
| +
|
| + if (t >= 1.0) {
|
| + action._finished = true;
|
| + }
|
| + }
|
| +
|
| + void _finish(Action action) {
|
| + action.update(1.0);
|
| + action._finished = true;
|
| + }
|
| +
|
| + void _reset() {
|
| + super._reset();
|
| + _a._reset();
|
| + _b._reset();
|
| + }
|
| +}
|
| +
|
| +class ActionGroup extends ActionInterval {
|
| + List<Action> _actions;
|
| +
|
| + ActionGroup(this._actions) {
|
| + for (Action action in _actions) {
|
| + if (action.duration > _duration) {
|
| + _duration = action.duration;
|
| + }
|
| + }
|
| + }
|
| +
|
| + void update(double t) {
|
| + if (t >= 1.0) {
|
| + // Finish all unfinished actions
|
| + for (Action action in _actions) {
|
| + if (!action._finished) {
|
| + action.update(1.0);
|
| + action._finished = true;
|
| + }
|
| + }
|
| + } else {
|
| + for (Action action in _actions) {
|
| + if (action.duration == 0.0) {
|
| + // Fire all instant actions immediately
|
| + if (!action._finished) {
|
| + action.update(1.0);
|
| + action._finished = true;
|
| + }
|
| + } else {
|
| + // Update child actions
|
| + double ta = (t / (action.duration / duration)).clamp(0.0, 1.0);
|
| + if (ta < 1.0) {
|
| + if (action is ActionInterval) {
|
| + ActionInterval actionInterval = action;
|
| + if (actionInterval.curve == null) {
|
| + action.update(ta);
|
| + } else {
|
| + action.update(actionInterval.curve.transform(ta));
|
| + }
|
| + } else {
|
| + action.update(ta);
|
| + }
|
| + } else if (!action._finished){
|
| + action.update(1.0);
|
| + action._finished = true;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _reset() {
|
| + for (Action action in _actions) {
|
| + action._reset();
|
| }
|
| }
|
| }
|
| @@ -143,30 +279,6 @@ class ActionRemoveNode extends ActionInstant {
|
| }
|
| }
|
|
|
| -class ActionRepeatForever extends Action {
|
| - final ActionInterval action;
|
| - double _elapsedInAction = 0.0;
|
| -
|
| - ActionRepeatForever(this.action);
|
| -
|
| - step(double dt) {
|
| - _elapsedInAction += dt;
|
| - while (_elapsedInAction > action.duration) {
|
| - _elapsedInAction -= action.duration;
|
| - }
|
| - _elapsedInAction = Math.max(_elapsedInAction, 0.0);
|
| -
|
| - double t;
|
| - if (action._duration == 0.0) {
|
| - t = 1.0;
|
| - } else {
|
| - t = (_elapsedInAction / action._duration).clamp(0.0, 1.0);
|
| - }
|
| -
|
| - action.update(t);
|
| - }
|
| -}
|
| -
|
| class ActionTween extends ActionInterval {
|
| final Function setter;
|
| final startVal;
|
| @@ -174,20 +286,41 @@ class ActionTween extends ActionInterval {
|
|
|
| var _delta;
|
|
|
| - ActionTween(this.setter, this.startVal, this.endVal, double duration) : super(duration) {
|
| + ActionTween(this.setter, this.startVal, this.endVal, double duration, [Curve curve]) : super(duration, curve) {
|
| _computeDelta();
|
| }
|
|
|
| void _computeDelta() {
|
| if (startVal is Point) {
|
| + // Point
|
| double xStart = startVal.x;
|
| double yStart = startVal.y;
|
| double xEnd = endVal.x;
|
| double yEnd = endVal.y;
|
| _delta = new Point(xEnd - xStart, yEnd - yStart);
|
| + } else if (startVal is Size) {
|
| + // Size
|
| + double wStart = startVal.width;
|
| + double hStart = startVal.height;
|
| + double wEnd = endVal.width;
|
| + double hEnd = endVal.height;
|
| + _delta = new Size(wEnd - wStart, hEnd - hStart);
|
| + } else if (startVal is Rect) {
|
| + // Rect
|
| + double lStart = startVal.left;
|
| + double tStart = startVal.top;
|
| + double rStart = startVal.right;
|
| + double bStart = startVal.bottom;
|
| + double lEnd = endVal.left;
|
| + double tEnd = endVal.top;
|
| + double rEnd = endVal.right;
|
| + double bEnd = endVal.bottom;
|
| + _delta = new Rect.fromLTRB(lEnd - lStart, tEnd - tStart, rEnd - rStart, bEnd - bStart);
|
| } else if (startVal is double) {
|
| + // Double
|
| _delta = endVal - startVal;
|
| } else if (startVal is Color) {
|
| + // Color
|
| int aDelta = endVal.alpha - startVal.alpha;
|
| int rDelta = endVal.red - startVal.red;
|
| int gDelta = endVal.green - startVal.green;
|
| @@ -208,6 +341,24 @@ class ActionTween extends ActionInterval {
|
| double xDelta = _delta.x;
|
| double yDelta = _delta.y;
|
| newVal = new Point(xStart + xDelta * t, yStart + yDelta * t);
|
| + } else if (startVal is Size) {
|
| + // Size
|
| + double wStart = startVal.width;
|
| + double hStart = startVal.height;
|
| + double wDelta = _delta.width;
|
| + double hDelta = _delta.height;
|
| + newVal = new Size(wStart + wDelta * t, hStart + hDelta * t);
|
| + } else if (startVal is Rect) {
|
| + // Rect
|
| + double lStart = startVal.left;
|
| + double tStart = startVal.top;
|
| + double rStart = startVal.right;
|
| + double bStart = startVal.bottom;
|
| + double lDelta = _delta.left;
|
| + double tDelta = _delta.top;
|
| + double rDelta = _delta.right;
|
| + double bDelta = _delta.bottom;
|
| + newVal = new Rect.fromLTRB(lStart + lDelta * t, tStart + tDelta * t, rStart + rDelta * t, bStart + bDelta * t);
|
| } else if (startVal is double) {
|
| // Doubles
|
| newVal = startVal + _delta * t;
|
| @@ -234,27 +385,41 @@ class ActionController {
|
| ActionController();
|
|
|
| void run(Action action, [Object tag]) {
|
| + assert(!action._added);
|
| +
|
| action._tag = tag;
|
| + action._added = true;
|
| action.update(0.0);
|
| _actions.add(action);
|
| }
|
|
|
| void stop(Action action) {
|
| - _actions.remove(action);
|
| + if (_actions.remove(action)) {
|
| + action._added = false;
|
| + action._reset();
|
| + }
|
| + }
|
| +
|
| + void _stopAtIndex(int i) {
|
| + Action action = _actions[i];
|
| + action._added = false;
|
| + action._reset();
|
| + _actions.removeAt(i);
|
| }
|
|
|
| void stopWithTag(Object tag) {
|
| for (int i = _actions.length - 1; i >= 0; i--) {
|
| Action action = _actions[i];
|
| if (action._tag == tag) {
|
| - _actions.removeAt(i);
|
| - print("removing tag: $tag");
|
| + _stopAtIndex(i);
|
| }
|
| }
|
| }
|
|
|
| void stopAll() {
|
| - _actions.clear();
|
| + for (int i = _actions.length - 1; i >= 0; i--) {
|
| + _stopAtIndex(i);
|
| + }
|
| }
|
|
|
| void step(double dt) {
|
| @@ -263,6 +428,7 @@ class ActionController {
|
| action.step(dt);
|
|
|
| if (action._finished) {
|
| + action._added = false;
|
| _actions.removeAt(i);
|
| }
|
| }
|
| @@ -276,4 +442,29 @@ class _ColorDiff {
|
| final int blue;
|
|
|
| _ColorDiff(this.alpha, this.red, this.green, this.blue);
|
| -}
|
| +}
|
| +
|
| +double _bounce(double t)
|
| +{
|
| + if (t < 1.0 / 2.75) {
|
| + return 7.5625 * t * t;
|
| + } else if (t < 2 / 2.75) {
|
| + t -= 1.5 / 2.75;
|
| + return 7.5625 * t * t + 0.75;
|
| + } else if (t < 2.5 / 2.75) {
|
| + t -= 2.25 / 2.75;
|
| + return 7.5625 * t * t + 0.9375;
|
| + }
|
| + t -= 2.625 / 2.75;
|
| + return 7.5625 * t * t + 0.984375;
|
| +}
|
| +
|
| +class BounceOutCurve implements Curve {
|
| + const BounceOutCurve();
|
| +
|
| + double transform(double t) {
|
| + return _bounce(t);
|
| + }
|
| +}
|
| +
|
| +const BounceOutCurve bounceOut = const BounceOutCurve();
|
|
|