diff --git a/src/js/actions/GlobalStateActions.js b/src/js/actions/GlobalStateActions.js index 58f3f121..f04a747e 100644 --- a/src/js/actions/GlobalStateActions.js +++ b/src/js/actions/GlobalStateActions.js @@ -14,6 +14,12 @@ var GlobalStateActions = { }); }, + levelSolved: function() { + AppDispatcher.handleViewAction({ + type: ActionTypes.LEVEL_SOLVED, + }); + }, + changeFlipTreeY: function(flipTreeY) { AppDispatcher.handleViewAction({ type: ActionTypes.CHANGE_FLIP_TREE_Y, diff --git a/src/js/constants/AppConstants.js b/src/js/constants/AppConstants.js index 393dc556..b738fbfa 100644 --- a/src/js/constants/AppConstants.js +++ b/src/js/constants/AppConstants.js @@ -25,7 +25,13 @@ module.exports = { CHANGE_FLIP_TREE_Y: null, SUBMIT_COMMAND: null, CHANGE_LOCALE: null, - CHANGE_LOCALE_FROM_HEADER: null + CHANGE_LOCALE_FROM_HEADER: null, + /** + * only dispatched when you actually + * solve the level, not ask for solution + * or solve it again. + */ + SOLVE_LEVEL: null }), PayloadSources: keyMirror({ diff --git a/src/js/level/index.js b/src/js/level/index.js index 2682e2ce..9a5a057d 100644 --- a/src/js/level/index.js +++ b/src/js/level/index.js @@ -10,6 +10,7 @@ var React = require('react'); var Errors = require('../util/errors'); var Sandbox = require('../sandbox/').Sandbox; var GlobalStateActions = require('../actions/GlobalStateActions'); +var GlobalStateStore = require('../stores/GlobalStateStore'); var LevelActions = require('../actions/LevelActions'); var LevelStore = require('../stores/LevelStore'); var Visualization = require('../visuals/visualization').Visualization; @@ -446,6 +447,32 @@ var Level = Sandbox.extend({ this.wasResetAfterSolved; var skipFinishAnimation = this.wasResetAfterSolved; + if (!skipFinishAnimation) { + GlobalStateActions.levelSolved(); + } + + /** + * Speed up the animation each time we see it. + */ + var speed = 1.0; + switch (GlobalStateStore.getNumLevelsSolved()) { + case 2: + speed = 1.5; + break; + case 3: + speed = 1.8; + break; + case 4: + speed = 2.1; + break; + case 5: + speed = 2.4; + break; + } + if (GlobalStateStore.getNumLevelsSolved() > 5) { + speed = 2.5; + } + var finishAnimationChain = null; if (skipFinishAnimation) { var deferred = Q.defer(); @@ -457,10 +484,10 @@ var Level = Sandbox.extend({ ); } else { GlobalStateActions.changeIsAnimating(true); - finishAnimationChain = this.mainVis.gitVisuals.finishAnimation(); + finishAnimationChain = this.mainVis.gitVisuals.finishAnimation(speed); if (this.mainVis.originVis) { finishAnimationChain = finishAnimationChain.then( - this.mainVis.originVis.gitVisuals.finishAnimation() + this.mainVis.originVis.gitVisuals.finishAnimation(speed) ); } } diff --git a/src/js/stores/GlobalStateStore.js b/src/js/stores/GlobalStateStore.js index 03215072..35897d2d 100644 --- a/src/js/stores/GlobalStateStore.js +++ b/src/js/stores/GlobalStateStore.js @@ -10,6 +10,7 @@ var ActionTypes = AppConstants.ActionTypes; var _isAnimating = false; var _flipTreeY = false; +var _numLevelsSolved = 0; var GlobalStateStore = assign( {}, @@ -24,6 +25,10 @@ AppConstants.StoreSubscribePrototype, return _flipTreeY; }, + getNumLevelsSolved: function() { + return _numLevelsSolved; + }, + dispatchToken: AppDispatcher.register(function(payload) { var action = payload.action; var shouldInform = false; @@ -37,6 +42,10 @@ AppConstants.StoreSubscribePrototype, _flipTreeY = action.flipTreeY; shouldInform = true; break; + case ActionTypes.LEVEL_SOLVED: + _numLevelsSolved++; + shouldInform = true; + break; } if (shouldInform) { diff --git a/src/js/util/debug.js b/src/js/util/debug.js index f70b6dfb..a9359f1d 100644 --- a/src/js/util/debug.js +++ b/src/js/util/debug.js @@ -9,6 +9,8 @@ var toGlobalize = { LevelActions: require('../actions/LevelActions'), LevelStore: require('../stores/LevelStore'), LocaleActions: require('../actions/LocaleActions'), + GlobalStateActions: require('../actions/GlobalStateActions'), + GlobalStateStore: require('../stores/GlobalStateStore'), LocaleStore: require('../stores/LocaleStore'), Levels: require('../graph/treeCompare'), Constants: require('../util/constants'), diff --git a/src/js/visuals/index.js b/src/js/visuals/index.js index 5ade50f6..3897fbd9 100644 --- a/src/js/visuals/index.js +++ b/src/js/visuals/index.js @@ -208,7 +208,12 @@ GitVisuals.prototype.animateAllAttrKeys = function(keys, attr, speed, easing) { return deferred.promise; }; -GitVisuals.prototype.finishAnimation = function() { +GitVisuals.prototype.finishAnimation = function(speed) { + speed = speed || 1.0; + if (!speed) { + throw new Error('need speed by time i finish animation' + speed); + } + var _this = this; var deferred = Q.defer(); var animationDone = Q.defer(); @@ -247,7 +252,7 @@ GitVisuals.prototype.finishAnimation = function() { return this.animateAllAttrKeys( { exclude: ['circle'] }, { opacity: 0 }, - defaultTime * 1.1 + defaultTime * 1.1 / speed ); }.bind(this)) // then make circle radii bigger @@ -255,7 +260,7 @@ GitVisuals.prototype.finishAnimation = function() { return this.animateAllAttrKeys( { exclude: ['arrow', 'rect', 'path', 'text'] }, { r: nodeRadius * 2 }, - defaultTime * 1.5 + defaultTime * 1.5 / speed ); }.bind(this)) // then shrink em super fast @@ -263,16 +268,16 @@ GitVisuals.prototype.finishAnimation = function() { return this.animateAllAttrKeys( { exclude: ['arrow', 'rect', 'path', 'text'] }, { r: nodeRadius * 0.75 }, - defaultTime * 0.5 + defaultTime * 0.5 / speed ); }.bind(this)) // then explode them and display text .then(function() { makeText(); - return this.explodeNodes(); + return this.explodeNodes(speed); }.bind(this)) .then(function() { - return this.explodeNodes(); + return this.explodeNodes(speed); }.bind(this)) // then fade circles (aka everything) in and back .then(function() { @@ -305,11 +310,11 @@ GitVisuals.prototype.finishAnimation = function() { return animationDone.promise; }; -GitVisuals.prototype.explodeNodes = function() { +GitVisuals.prototype.explodeNodes = function(speed) { var deferred = Q.defer(); var funcs = []; _.each(this.visNodeMap, function(visNode) { - funcs.push(visNode.getExplodeStepFunc()); + funcs.push(visNode.getExplodeStepFunc(speed)); }); var interval = setInterval(function() { diff --git a/src/js/visuals/visNode.js b/src/js/visuals/visNode.js index ca87f30a..1cb08d86 100644 --- a/src/js/visuals/visNode.js +++ b/src/js/visuals/visNode.js @@ -376,15 +376,18 @@ var VisNode = VisBase.extend({ }, this); }, - getExplodeStepFunc: function() { + getExplodeStepFunc: function(speed) { + if (!speed) { + throw new Error('need speed by now'); + } var circle = this.get('circle'); // decide on a speed - var speedMag = 20; + var speedMag = 20 / speed; // aim upwards var angle = Math.PI + Math.random() * 1 * Math.PI; - var gravity = 1 / 5; - var drag = 1 / 100; + var gravity = (1 / 5) * speed; + var drag = (1 / 100) * speed; var vx = speedMag * Math.cos(angle); var vy = speedMag * Math.sin(angle); @@ -393,7 +396,7 @@ var VisNode = VisBase.extend({ var maxWidth = this.gitVisuals.paper.width; var maxHeight = this.gitVisuals.paper.height; - var elasticity = 0.8; + var elasticity = 0.8 / speed; var dt = 1.0; var stepFunc = function() { @@ -417,7 +420,7 @@ var VisNode = VisBase.extend({ cy: y }); // continuation calculation - if ((vx * vx + vy * vy) < 0.01 && Math.abs(y - maxHeight) === 0) { + if ((vx * vx + vy * vy) < 0.1 && Math.abs(y - maxHeight) <= 0.1) { // dont need to animate anymore, we are on ground return false; }