| OLD | NEW |
| 1 part of sprites; | 1 part of sprites; |
| 2 | 2 |
| 3 typedef void ActionCallback(); | 3 typedef void ActionCallback(); |
| 4 | 4 |
| 5 abstract class Action { | 5 abstract class Action { |
| 6 Object _tag; | 6 Object _tag; |
| 7 bool _finished = false; | 7 bool _finished = false; |
| 8 bool _added = false; |
| 8 | 9 |
| 9 void step(double dt); | 10 void step(double dt); |
| 10 void update(double t) { | 11 void update(double t) { |
| 11 } | 12 } |
| 12 | 13 |
| 14 void _reset() { |
| 15 _finished = false; |
| 16 } |
| 17 |
| 13 double get duration => 0.0; | 18 double get duration => 0.0; |
| 14 } | 19 } |
| 15 | 20 |
| 16 abstract class ActionInterval extends Action { | 21 abstract class ActionInterval extends Action { |
| 17 double _duration; | 22 double _duration; |
| 18 | 23 |
| 19 bool _firstTick = true; | 24 bool _firstTick = true; |
| 20 double _elapsed = 0.0; | 25 double _elapsed = 0.0; |
| 21 | 26 |
| 22 double get duration => _duration; | 27 double get duration => _duration; |
| 28 Curve curve; |
| 23 | 29 |
| 24 ActionInterval([this._duration = 0.0]); | 30 ActionInterval([this._duration = 0.0, this.curve]); |
| 25 | 31 |
| 26 void step(double dt) { | 32 void step(double dt) { |
| 27 if (_firstTick) { | 33 if (_firstTick) { |
| 28 _firstTick = false; | 34 _firstTick = false; |
| 29 } else { | 35 } else { |
| 30 _elapsed += dt; | 36 _elapsed += dt; |
| 31 } | 37 } |
| 32 | 38 |
| 33 double t; | 39 double t; |
| 34 if (this._duration == 0.0) { | 40 if (this._duration == 0.0) { |
| 35 t = 1.0; | 41 t = 1.0; |
| 36 } else { | 42 } else { |
| 37 t = (_elapsed / _duration).clamp(0.0, 1.0); | 43 t = (_elapsed / _duration).clamp(0.0, 1.0); |
| 38 } | 44 } |
| 39 | 45 |
| 40 update(t); | 46 if (curve == null) { |
| 47 update(t); |
| 48 } else { |
| 49 update(curve.transform(t)); |
| 50 } |
| 41 | 51 |
| 42 if (t >= 1.0) _finished = true; | 52 if (t >= 1.0) _finished = true; |
| 43 } | 53 } |
| 44 } | 54 } |
| 45 | 55 |
| 46 class ActionRepeat extends ActionInterval { | 56 class ActionRepeat extends ActionInterval { |
| 47 final int numRepeats; | 57 final int numRepeats; |
| 48 final ActionInterval action; | 58 final ActionInterval action; |
| 59 int _lastFinishedRepeat = -1; |
| 49 | 60 |
| 50 ActionRepeat(this.action, this.numRepeats) { | 61 ActionRepeat(this.action, this.numRepeats) { |
| 51 _duration = action.duration * numRepeats; | 62 _duration = action.duration * numRepeats; |
| 52 } | 63 } |
| 53 | 64 |
| 54 void update(double t) { | 65 void update(double t) { |
| 55 action.update((t * numRepeats.toDouble()) % numRepeats.toDouble()); | 66 int currentRepeat = Math.min((t * numRepeats.toDouble()).toInt(), numRepeats
- 1); |
| 67 for (int i = Math.max(_lastFinishedRepeat, 0); i < currentRepeat; i++) { |
| 68 if (!action._finished) action.update(1.0); |
| 69 action._reset(); |
| 70 } |
| 71 _lastFinishedRepeat = currentRepeat; |
| 72 |
| 73 double ta = (t * numRepeats.toDouble()) % 1.0; |
| 74 action.update(ta); |
| 75 |
| 76 if (t >= 1.0) { |
| 77 action.update(1.0); |
| 78 action._finished = true; |
| 79 } |
| 56 } | 80 } |
| 57 } | 81 } |
| 58 | 82 |
| 83 class ActionRepeatForever extends Action { |
| 84 final ActionInterval action; |
| 85 double _elapsedInAction = 0.0; |
| 86 |
| 87 ActionRepeatForever(this.action); |
| 88 |
| 89 step(double dt) { |
| 90 _elapsedInAction += dt; |
| 91 while (_elapsedInAction > action.duration) { |
| 92 _elapsedInAction -= action.duration; |
| 93 if (!action._finished) action.update(1.0); |
| 94 action._reset(); |
| 95 } |
| 96 _elapsedInAction = Math.max(_elapsedInAction, 0.0); |
| 97 |
| 98 double t; |
| 99 if (action._duration == 0.0) { |
| 100 t = 1.0; |
| 101 } else { |
| 102 t = (_elapsedInAction / action._duration).clamp(0.0, 1.0); |
| 103 } |
| 104 |
| 105 action.update(t); |
| 106 } |
| 107 } |
| 108 |
| 59 class ActionSequence extends ActionInterval { | 109 class ActionSequence extends ActionInterval { |
| 60 Action _a; | 110 Action _a; |
| 61 Action _b; | 111 Action _b; |
| 62 double _split; | 112 double _split; |
| 63 | 113 |
| 64 ActionSequence(List<Action> actions) { | 114 ActionSequence(List<Action> actions) { |
| 65 assert(actions.length >= 2); | 115 assert(actions.length >= 2); |
| 66 | 116 |
| 67 if (actions.length == 2) { | 117 if (actions.length == 2) { |
| 68 // Base case | 118 // Base case |
| (...skipping 15 matching lines...) Expand all Loading... |
| 84 | 134 |
| 85 void update(double t) { | 135 void update(double t) { |
| 86 if (t < _split) { | 136 if (t < _split) { |
| 87 // Play first action | 137 // Play first action |
| 88 double ta; | 138 double ta; |
| 89 if (_split > 0.0) { | 139 if (_split > 0.0) { |
| 90 ta = (t / _split).clamp(0.0, 1.0); | 140 ta = (t / _split).clamp(0.0, 1.0); |
| 91 } else { | 141 } else { |
| 92 ta = 1.0; | 142 ta = 1.0; |
| 93 } | 143 } |
| 94 _a.update(ta); | 144 _updateWithCurve(_a, ta); |
| 95 } else if (t >= 1.0) { | 145 } else if (t >= 1.0) { |
| 96 // Make sure everything is finished | 146 // Make sure everything is finished |
| 97 if (!_a._finished) _a.update(1.0); | 147 if (!_a._finished) _finish(_a); |
| 98 if (!_b._finished) _b.update(1.0); | 148 if (!_b._finished) _finish(_b); |
| 99 } else { | 149 } else { |
| 100 // Play second action, but first make sure the first has finished | 150 // Play second action, but first make sure the first has finished |
| 101 if (!_a._finished) _a.update(1.0); | 151 if (!_a._finished) _finish(_a); |
| 102 double tb; | 152 double tb; |
| 103 if (_split < 1.0) { | 153 if (_split < 1.0) { |
| 104 tb = (1.0 - (1.0 - t) / (1.0 - _split)).clamp(0.0, 1.0); | 154 tb = (1.0 - (1.0 - t) / (1.0 - _split)).clamp(0.0, 1.0); |
| 105 } else { | 155 } else { |
| 106 tb = 1.0; | 156 tb = 1.0; |
| 107 } | 157 } |
| 108 _b.update(tb); | 158 _updateWithCurve(_b, tb); |
| 159 } |
| 160 } |
| 161 |
| 162 void _updateWithCurve(Action action, double t) { |
| 163 if (action is ActionInterval) { |
| 164 ActionInterval actionInterval = action; |
| 165 if (actionInterval.curve == null) { |
| 166 action.update(t); |
| 167 } else { |
| 168 action.update(actionInterval.curve.transform(t)); |
| 169 } |
| 170 } else { |
| 171 action.update(t); |
| 172 } |
| 173 |
| 174 if (t >= 1.0) { |
| 175 action._finished = true; |
| 176 } |
| 177 } |
| 178 |
| 179 void _finish(Action action) { |
| 180 action.update(1.0); |
| 181 action._finished = true; |
| 182 } |
| 183 |
| 184 void _reset() { |
| 185 super._reset(); |
| 186 _a._reset(); |
| 187 _b._reset(); |
| 188 } |
| 189 } |
| 190 |
| 191 class ActionGroup extends ActionInterval { |
| 192 List<Action> _actions; |
| 193 |
| 194 ActionGroup(this._actions) { |
| 195 for (Action action in _actions) { |
| 196 if (action.duration > _duration) { |
| 197 _duration = action.duration; |
| 198 } |
| 199 } |
| 200 } |
| 201 |
| 202 void update(double t) { |
| 203 if (t >= 1.0) { |
| 204 // Finish all unfinished actions |
| 205 for (Action action in _actions) { |
| 206 if (!action._finished) { |
| 207 action.update(1.0); |
| 208 action._finished = true; |
| 209 } |
| 210 } |
| 211 } else { |
| 212 for (Action action in _actions) { |
| 213 if (action.duration == 0.0) { |
| 214 // Fire all instant actions immediately |
| 215 if (!action._finished) { |
| 216 action.update(1.0); |
| 217 action._finished = true; |
| 218 } |
| 219 } else { |
| 220 // Update child actions |
| 221 double ta = (t / (action.duration / duration)).clamp(0.0, 1.0); |
| 222 if (ta < 1.0) { |
| 223 if (action is ActionInterval) { |
| 224 ActionInterval actionInterval = action; |
| 225 if (actionInterval.curve == null) { |
| 226 action.update(ta); |
| 227 } else { |
| 228 action.update(actionInterval.curve.transform(ta)); |
| 229 } |
| 230 } else { |
| 231 action.update(ta); |
| 232 } |
| 233 } else if (!action._finished){ |
| 234 action.update(1.0); |
| 235 action._finished = true; |
| 236 } |
| 237 } |
| 238 } |
| 239 } |
| 240 } |
| 241 |
| 242 void _reset() { |
| 243 for (Action action in _actions) { |
| 244 action._reset(); |
| 109 } | 245 } |
| 110 } | 246 } |
| 111 } | 247 } |
| 112 | 248 |
| 113 abstract class ActionInstant extends Action { | 249 abstract class ActionInstant extends Action { |
| 114 | 250 |
| 115 void step(double dt) { | 251 void step(double dt) { |
| 116 } | 252 } |
| 117 | 253 |
| 118 void update(double t) { | 254 void update(double t) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 136 class ActionRemoveNode extends ActionInstant { | 272 class ActionRemoveNode extends ActionInstant { |
| 137 Node _node; | 273 Node _node; |
| 138 | 274 |
| 139 ActionRemoveNode(this._node); | 275 ActionRemoveNode(this._node); |
| 140 | 276 |
| 141 void fire() { | 277 void fire() { |
| 142 _node.removeFromParent(); | 278 _node.removeFromParent(); |
| 143 } | 279 } |
| 144 } | 280 } |
| 145 | 281 |
| 146 class ActionRepeatForever extends Action { | |
| 147 final ActionInterval action; | |
| 148 double _elapsedInAction = 0.0; | |
| 149 | |
| 150 ActionRepeatForever(this.action); | |
| 151 | |
| 152 step(double dt) { | |
| 153 _elapsedInAction += dt; | |
| 154 while (_elapsedInAction > action.duration) { | |
| 155 _elapsedInAction -= action.duration; | |
| 156 } | |
| 157 _elapsedInAction = Math.max(_elapsedInAction, 0.0); | |
| 158 | |
| 159 double t; | |
| 160 if (action._duration == 0.0) { | |
| 161 t = 1.0; | |
| 162 } else { | |
| 163 t = (_elapsedInAction / action._duration).clamp(0.0, 1.0); | |
| 164 } | |
| 165 | |
| 166 action.update(t); | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 class ActionTween extends ActionInterval { | 282 class ActionTween extends ActionInterval { |
| 171 final Function setter; | 283 final Function setter; |
| 172 final startVal; | 284 final startVal; |
| 173 final endVal; | 285 final endVal; |
| 174 | 286 |
| 175 var _delta; | 287 var _delta; |
| 176 | 288 |
| 177 ActionTween(this.setter, this.startVal, this.endVal, double duration) : super(
duration) { | 289 ActionTween(this.setter, this.startVal, this.endVal, double duration, [Curve c
urve]) : super(duration, curve) { |
| 178 _computeDelta(); | 290 _computeDelta(); |
| 179 } | 291 } |
| 180 | 292 |
| 181 void _computeDelta() { | 293 void _computeDelta() { |
| 182 if (startVal is Point) { | 294 if (startVal is Point) { |
| 295 // Point |
| 183 double xStart = startVal.x; | 296 double xStart = startVal.x; |
| 184 double yStart = startVal.y; | 297 double yStart = startVal.y; |
| 185 double xEnd = endVal.x; | 298 double xEnd = endVal.x; |
| 186 double yEnd = endVal.y; | 299 double yEnd = endVal.y; |
| 187 _delta = new Point(xEnd - xStart, yEnd - yStart); | 300 _delta = new Point(xEnd - xStart, yEnd - yStart); |
| 301 } else if (startVal is Size) { |
| 302 // Size |
| 303 double wStart = startVal.width; |
| 304 double hStart = startVal.height; |
| 305 double wEnd = endVal.width; |
| 306 double hEnd = endVal.height; |
| 307 _delta = new Size(wEnd - wStart, hEnd - hStart); |
| 308 } else if (startVal is Rect) { |
| 309 // Rect |
| 310 double lStart = startVal.left; |
| 311 double tStart = startVal.top; |
| 312 double rStart = startVal.right; |
| 313 double bStart = startVal.bottom; |
| 314 double lEnd = endVal.left; |
| 315 double tEnd = endVal.top; |
| 316 double rEnd = endVal.right; |
| 317 double bEnd = endVal.bottom; |
| 318 _delta = new Rect.fromLTRB(lEnd - lStart, tEnd - tStart, rEnd - rStart, bE
nd - bStart); |
| 188 } else if (startVal is double) { | 319 } else if (startVal is double) { |
| 320 // Double |
| 189 _delta = endVal - startVal; | 321 _delta = endVal - startVal; |
| 190 } else if (startVal is Color) { | 322 } else if (startVal is Color) { |
| 323 // Color |
| 191 int aDelta = endVal.alpha - startVal.alpha; | 324 int aDelta = endVal.alpha - startVal.alpha; |
| 192 int rDelta = endVal.red - startVal.red; | 325 int rDelta = endVal.red - startVal.red; |
| 193 int gDelta = endVal.green - startVal.green; | 326 int gDelta = endVal.green - startVal.green; |
| 194 int bDelta = endVal.blue - startVal.blue; | 327 int bDelta = endVal.blue - startVal.blue; |
| 195 _delta = new _ColorDiff(aDelta, rDelta, gDelta, bDelta); | 328 _delta = new _ColorDiff(aDelta, rDelta, gDelta, bDelta); |
| 196 } else { | 329 } else { |
| 197 assert(false); | 330 assert(false); |
| 198 } | 331 } |
| 199 } | 332 } |
| 200 | 333 |
| 201 void update(double t) { | 334 void update(double t) { |
| 202 var newVal; | 335 var newVal; |
| 203 | 336 |
| 204 if (startVal is Point) { | 337 if (startVal is Point) { |
| 205 // Point | 338 // Point |
| 206 double xStart = startVal.x; | 339 double xStart = startVal.x; |
| 207 double yStart = startVal.y; | 340 double yStart = startVal.y; |
| 208 double xDelta = _delta.x; | 341 double xDelta = _delta.x; |
| 209 double yDelta = _delta.y; | 342 double yDelta = _delta.y; |
| 210 newVal = new Point(xStart + xDelta * t, yStart + yDelta * t); | 343 newVal = new Point(xStart + xDelta * t, yStart + yDelta * t); |
| 344 } else if (startVal is Size) { |
| 345 // Size |
| 346 double wStart = startVal.width; |
| 347 double hStart = startVal.height; |
| 348 double wDelta = _delta.width; |
| 349 double hDelta = _delta.height; |
| 350 newVal = new Size(wStart + wDelta * t, hStart + hDelta * t); |
| 351 } else if (startVal is Rect) { |
| 352 // Rect |
| 353 double lStart = startVal.left; |
| 354 double tStart = startVal.top; |
| 355 double rStart = startVal.right; |
| 356 double bStart = startVal.bottom; |
| 357 double lDelta = _delta.left; |
| 358 double tDelta = _delta.top; |
| 359 double rDelta = _delta.right; |
| 360 double bDelta = _delta.bottom; |
| 361 newVal = new Rect.fromLTRB(lStart + lDelta * t, tStart + tDelta * t, rStar
t + rDelta * t, bStart + bDelta * t); |
| 211 } else if (startVal is double) { | 362 } else if (startVal is double) { |
| 212 // Doubles | 363 // Doubles |
| 213 newVal = startVal + _delta * t; | 364 newVal = startVal + _delta * t; |
| 214 } else if (startVal is Color) { | 365 } else if (startVal is Color) { |
| 215 // Colors | 366 // Colors |
| 216 int aNew = (startVal.alpha + (_delta.alpha * t).toInt()).clamp(0, 255); | 367 int aNew = (startVal.alpha + (_delta.alpha * t).toInt()).clamp(0, 255); |
| 217 int rNew = (startVal.red + (_delta.red * t).toInt()).clamp(0, 255); | 368 int rNew = (startVal.red + (_delta.red * t).toInt()).clamp(0, 255); |
| 218 int gNew = (startVal.green + (_delta.green * t).toInt()).clamp(0, 255); | 369 int gNew = (startVal.green + (_delta.green * t).toInt()).clamp(0, 255); |
| 219 int bNew = (startVal.blue + (_delta.blue * t).toInt()).clamp(0, 255); | 370 int bNew = (startVal.blue + (_delta.blue * t).toInt()).clamp(0, 255); |
| 220 newVal = new Color.fromARGB(aNew, rNew, gNew, bNew); | 371 newVal = new Color.fromARGB(aNew, rNew, gNew, bNew); |
| 221 } else { | 372 } else { |
| 222 // Oopses | 373 // Oopses |
| 223 assert(false); | 374 assert(false); |
| 224 } | 375 } |
| 225 | 376 |
| 226 setter(newVal); | 377 setter(newVal); |
| 227 } | 378 } |
| 228 } | 379 } |
| 229 | 380 |
| 230 class ActionController { | 381 class ActionController { |
| 231 | 382 |
| 232 List<Action> _actions = []; | 383 List<Action> _actions = []; |
| 233 | 384 |
| 234 ActionController(); | 385 ActionController(); |
| 235 | 386 |
| 236 void run(Action action, [Object tag]) { | 387 void run(Action action, [Object tag]) { |
| 388 assert(!action._added); |
| 389 |
| 237 action._tag = tag; | 390 action._tag = tag; |
| 391 action._added = true; |
| 238 action.update(0.0); | 392 action.update(0.0); |
| 239 _actions.add(action); | 393 _actions.add(action); |
| 240 } | 394 } |
| 241 | 395 |
| 242 void stop(Action action) { | 396 void stop(Action action) { |
| 243 _actions.remove(action); | 397 if (_actions.remove(action)) { |
| 398 action._added = false; |
| 399 action._reset(); |
| 400 } |
| 401 } |
| 402 |
| 403 void _stopAtIndex(int i) { |
| 404 Action action = _actions[i]; |
| 405 action._added = false; |
| 406 action._reset(); |
| 407 _actions.removeAt(i); |
| 244 } | 408 } |
| 245 | 409 |
| 246 void stopWithTag(Object tag) { | 410 void stopWithTag(Object tag) { |
| 247 for (int i = _actions.length - 1; i >= 0; i--) { | 411 for (int i = _actions.length - 1; i >= 0; i--) { |
| 248 Action action = _actions[i]; | 412 Action action = _actions[i]; |
| 249 if (action._tag == tag) { | 413 if (action._tag == tag) { |
| 250 _actions.removeAt(i); | 414 _stopAtIndex(i); |
| 251 print("removing tag: $tag"); | |
| 252 } | 415 } |
| 253 } | 416 } |
| 254 } | 417 } |
| 255 | 418 |
| 256 void stopAll() { | 419 void stopAll() { |
| 257 _actions.clear(); | 420 for (int i = _actions.length - 1; i >= 0; i--) { |
| 421 _stopAtIndex(i); |
| 422 } |
| 258 } | 423 } |
| 259 | 424 |
| 260 void step(double dt) { | 425 void step(double dt) { |
| 261 for (int i = _actions.length - 1; i >= 0; i--) { | 426 for (int i = _actions.length - 1; i >= 0; i--) { |
| 262 Action action = _actions[i]; | 427 Action action = _actions[i]; |
| 263 action.step(dt); | 428 action.step(dt); |
| 264 | 429 |
| 265 if (action._finished) { | 430 if (action._finished) { |
| 431 action._added = false; |
| 266 _actions.removeAt(i); | 432 _actions.removeAt(i); |
| 267 } | 433 } |
| 268 } | 434 } |
| 269 } | 435 } |
| 270 } | 436 } |
| 271 | 437 |
| 272 class _ColorDiff { | 438 class _ColorDiff { |
| 273 final int alpha; | 439 final int alpha; |
| 274 final int red; | 440 final int red; |
| 275 final int green; | 441 final int green; |
| 276 final int blue; | 442 final int blue; |
| 277 | 443 |
| 278 _ColorDiff(this.alpha, this.red, this.green, this.blue); | 444 _ColorDiff(this.alpha, this.red, this.green, this.blue); |
| 279 } | 445 } |
| 446 |
| 447 double _bounce(double t) |
| 448 { |
| 449 if (t < 1.0 / 2.75) { |
| 450 return 7.5625 * t * t; |
| 451 } else if (t < 2 / 2.75) { |
| 452 t -= 1.5 / 2.75; |
| 453 return 7.5625 * t * t + 0.75; |
| 454 } else if (t < 2.5 / 2.75) { |
| 455 t -= 2.25 / 2.75; |
| 456 return 7.5625 * t * t + 0.9375; |
| 457 } |
| 458 t -= 2.625 / 2.75; |
| 459 return 7.5625 * t * t + 0.984375; |
| 460 } |
| 461 |
| 462 class BounceOutCurve implements Curve { |
| 463 const BounceOutCurve(); |
| 464 |
| 465 double transform(double t) { |
| 466 return _bounce(t); |
| 467 } |
| 468 } |
| 469 |
| 470 const BounceOutCurve bounceOut = const BounceOutCurve(); |
| OLD | NEW |