- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443
- 444
- 445
- 446
- 447
- 448
- 449
- 450
- 451
- 452
- 453
- 454
- 455
- 456
- 457
- 458
- 459
- 460
- 461
- 462
- 463
- 464
- 465
- 466
- 467
- 468
- 469
- 470
- 471
import timer from "./../system/timer.js";
import * as event from "./../system/event.js";
import { game } from "../index.js";
import { Easing } from "./easing.js";
import { Interpolation } from "./interpolation.js";
/*
* Tween.js - Licensed under the MIT license
* https://github.com/tweenjs/tween.js
*/
/**
* @classdesc
* Javascript Tweening Engine<p>
* Super simple, fast and easy to use tweening engine which incorporates optimised Robert Penner's equation<p>
* <a href="https://github.com/sole/Tween.js">https://github.com/sole/Tween.js</a><p>
* author sole / http://soledadpenades.com<br>
* author mr.doob / http://mrdoob.com<br>
* author Robert Eisele / http://www.xarg.org<br>
* author Philippe / http://philippe.elsass.me<br>
* author Robert Penner / http://www.robertpenner.com/easing_terms_of_use.html<br>
* author Paul Lewis / http://www.aerotwist.com/<br>
* author lechecacharro<br>
* author Josh Faul / http://jocafa.com/
*/
export default class Tween {
/**
* @param {object} object - object on which to apply the tween
* @example
* // add a tween to change the object pos.x and pos.y variable to 200 in 3 seconds
* tween = new me.Tween(myObject.pos).to({
* x: 200,
* y: 200,
* }, {
* duration: 3000,
* easing: me.Tween.Easing.Bounce.Out,
* autoStart : true
* }).onComplete(myFunc);
*/
constructor (object) {
this.setProperties(object);
}
/**
* reset the tween object to default value
* @ignore
*/
onResetEvent(object) {
this.setProperties(object);
}
/**
* @ignore
*/
setProperties(object) {
this._object = object;
this._valuesStart = {};
this._valuesEnd = {};
this._valuesStartRepeat = {};
this._duration = 1000;
this._repeat = 0;
this._yoyo = false;
this._reversed = false;
this._delayTime = 0;
this._startTime = null;
this._easingFunction = Easing.Linear.None;
this._interpolationFunction = Interpolation.Linear;
this._chainedTweens = [];
this._onStartCallback = null;
this._onStartCallbackFired = false;
this._onUpdateCallback = null;
this._onCompleteCallback = null;
// tweens are synchronized with the game update loop
this._tweenTimeTracker = game.lastUpdate;
// reset flags to default value
this.isPersistent = false;
// this is not really supported
this.updateWhenPaused = false;
// comply with the container contract
this.isRenderable = false;
// Set all starting values present on the target object
for (let field in object) {
if (typeof object !== "object") {
this._valuesStart[ field ] = parseFloat(object[field]);
}
}
}
/**
* @ignore
*/
_resumeCallback(elapsed) {
if (this._startTime) {
this._startTime += elapsed;
}
}
/**
* subscribe to the resume event when added
* @ignore
*/
onActivateEvent() {
event.on(event.STATE_RESUME, this._resumeCallback, this);
}
/**
* Unsubscribe when tween is removed
* @ignore
*/
onDeactivateEvent() {
event.off(event.STATE_RESUME, this._resumeCallback);
}
/**
* object properties to be updated and duration
* @name to
* @memberof Tween
* @public
* @param {object} properties - hash of properties
* @param {object|number} [options] - object of tween properties, or a duration if a numeric value is passed
* @param {number} [options.duration] - tween duration
* @param {Tween.Easing} [options.easing] - easing function
* @param {number} [options.delay] - delay amount expressed in milliseconds
* @param {boolean} [options.yoyo] - allows the tween to bounce back to their original value when finished. To be used together with repeat to create endless loops.
* @param {number} [options.repeat] - amount of times the tween should be repeated
* @param {Tween.Interpolation} [options.interpolation] - interpolation function
* @param {boolean} [options.autoStart] - allow this tween to start automatically. Otherwise call me.Tween.start().
* @returns {Tween} this instance for object chaining
*/
to(properties, options) {
this._valuesEnd = properties;
if (typeof options !== "undefined") {
if (typeof options === "number") {
// for backward compatiblity
this._duration = options;
} else if (typeof options === "object") {
if (options.duration) { this._duration = options.duration; }
if (options.yoyo) { this.yoyo(options.yoyo); }
if (options.easing) { this.easing(options.easing); }
if (options.repeat) { this.repeat(options.repeat); }
if (options.delay) { this.delay(options.delay); }
if (options.interpolation) { this.interpolation(options.interpolation); }
if (options.autoStart) {
this.start();
}
}
}
return this;
}
/**
* start the tween
* @name start
* @memberof Tween
* @public
* @param {number} [time] - the current time when the tween was started
* @returns {Tween} this instance for object chaining
*/
start(time = timer.getTime()) {
this._onStartCallbackFired = false;
// add the tween to the object pool on start
game.world.addChild(this);
this._startTime = time + this._delayTime;
for (let property in this._valuesEnd) {
// check if an Array was provided as property value
if (this._valuesEnd[ property ] instanceof Array) {
if (this._valuesEnd[ property ].length === 0) {
continue;
}
// create a local copy of the Array with the start value at the front
this._valuesEnd[ property ] = [ this._object[ property ] ].concat(this._valuesEnd[ property ]);
}
this._valuesStart[ property ] = this._object[ property ];
if ((this._valuesStart[ property ] instanceof Array) === false) {
this._valuesStart[ property ] *= 1.0; // Ensures we're using numbers, not strings
}
this._valuesStartRepeat[ property ] = this._valuesStart[ property ] || 0;
}
return this;
}
/**
* stop the tween
* @name stop
* @memberof Tween
* @public
* @returns {Tween} this instance for object chaining
*/
stop() {
// remove the tween from the world container
game.world.removeChildNow(this);
return this;
}
/**
* delay the tween
* @name delay
* @memberof Tween
* @public
* @param {number} amount - delay amount expressed in milliseconds
* @returns {Tween} this instance for object chaining
*/
delay(amount) {
this._delayTime = amount;
return this;
}
/**
* Repeat the tween
* @name repeat
* @memberof Tween
* @public
* @param {number} times - amount of times the tween should be repeated
* @returns {Tween} this instance for object chaining
*/
repeat(times) {
this._repeat = times;
return this;
}
/**
* Allows the tween to bounce back to their original value when finished.
* To be used together with repeat to create endless loops.
* @name yoyo
* @memberof Tween
* @public
* @see Tween#repeat
* @param {boolean} yoyo
* @returns {Tween} this instance for object chaining
*/
yoyo(yoyo) {
this._yoyo = yoyo;
return this;
}
/**
* set the easing function
* @name easing
* @memberof Tween
* @public
* @param {Tween.Easing} easing - easing function
* @returns {Tween} this instance for object chaining
*/
easing(easing) {
if (typeof easing !== "function") {
throw new Error("invalid easing function for me.Tween.easing()");
}
this._easingFunction = easing;
return this;
}
/**
* set the interpolation function
* @name interpolation
* @memberof Tween
* @public
* @param {Tween.Interpolation} interpolation - interpolation function
* @returns {Tween} this instance for object chaining
*/
interpolation(interpolation) {
this._interpolationFunction = interpolation;
return this;
}
/**
* chain the tween
* @name chain
* @memberof Tween
* @public
* @param {...Tween} chainedTween - Tween(s) to be chained
* @returns {Tween} this instance for object chaining
*/
chain() {
this._chainedTweens = arguments;
return this;
}
/**
* onStart callback
* @name onStart
* @memberof Tween
* @public
* @param {Function} onStartCallback - callback
* @returns {Tween} this instance for object chaining
*/
onStart(onStartCallback) {
this._onStartCallback = onStartCallback;
return this;
}
/**
* onUpdate callback
* @name onUpdate
* @memberof Tween
* @public
* @param {Function} onUpdateCallback - callback
* @returns {Tween} this instance for object chaining
*/
onUpdate(onUpdateCallback) {
this._onUpdateCallback = onUpdateCallback;
return this;
}
/**
* onComplete callback
* @name onComplete
* @memberof Tween
* @public
* @param {Function} onCompleteCallback - callback
* @returns {Tween} this instance for object chaining
*/
onComplete(onCompleteCallback) {
this._onCompleteCallback = onCompleteCallback;
return this;
}
/** @ignore */
update(dt) {
// the original Tween implementation expect
// a timestamp and not a time delta
this._tweenTimeTracker = (game.lastUpdate > this._tweenTimeTracker) ? game.lastUpdate : this._tweenTimeTracker + dt;
let time = this._tweenTimeTracker;
let property;
if (time < this._startTime) {
return true;
}
if (this._onStartCallbackFired === false) {
if (this._onStartCallback !== null) {
this._onStartCallback.call(this._object);
}
this._onStartCallbackFired = true;
}
let elapsed = (time - this._startTime) / this._duration;
elapsed = elapsed > 1 ? 1 : elapsed;
let value = this._easingFunction(elapsed);
for (property in this._valuesEnd) {
let start = this._valuesStart[ property ] || 0;
let end = this._valuesEnd[ property ];
if (end instanceof Array) {
this._object[ property ] = this._interpolationFunction(end, value);
} else {
// Parses relative end values with start as base (e.g.: +10, -3)
if (typeof(end) === "string") {
end = start + parseFloat(end);
}
// protect against non numeric properties.
if (typeof(end) === "number") {
this._object[ property ] = start + (end - start) * value;
}
}
}
if (this._onUpdateCallback !== null) {
this._onUpdateCallback.call(this._object, value);
}
if (elapsed === 1) {
if (this._repeat > 0) {
if (isFinite(this._repeat)) {
this._repeat--;
}
// reassign starting values, restart by making startTime = now
for (property in this._valuesStartRepeat) {
if (typeof(this._valuesEnd[ property ]) === "string") {
this._valuesStartRepeat[ property ] = this._valuesStartRepeat[ property ] + parseFloat(this._valuesEnd[ property ]);
}
if (this._yoyo) {
let tmp = this._valuesStartRepeat[ property ];
this._valuesStartRepeat[ property ] = this._valuesEnd[ property ];
this._valuesEnd[ property ] = tmp;
}
this._valuesStart[ property ] = this._valuesStartRepeat[ property ];
}
if (this._yoyo) {
this._reversed = !this._reversed;
}
this._startTime = time + this._delayTime;
return true;
} else {
// remove the tween from the world container
game.world.removeChildNow(this);
if (this._onCompleteCallback !== null) {
this._onCompleteCallback.call(this._object);
}
for (let i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i ++) {
this._chainedTweens[ i ].start(time);
}
return false;
}
}
return true;
}
// export easing function as static class property
static get Easing() { return Easing; }
static get Interpolation() { return Interpolation; }
}