选项卡处于非活动状态时,Javascript动画出错

时间:2017-01-11 13:27:50

标签: javascript animation setinterval requestanimationframe tweenmax

样品: http://codepen.io/anon/pen/xgZMVd/

html文件:

<div class="game-page">
</div>

css文件:

.game-page {
    width: 1024px;
    height: 768px;
    position: absolute;
    background-color: grey;
}

.stick {
    position: absolute;
    left: 50%;
    margin-left: -94px;
    top: -60px;
    width: 188px;
    height: 50px;
    background-color: black;
}

js file:

$(document).ready(function() {
  init();
});

var CSS_CLASS = { STICK: "stick" },
    changeSpeedTime = 1000, //in milliseconds
    gameTime = 60, //in seconds
    timer = 1, //in seconds
    windowWidth = 1024,
    windowHeight = 768,
    stickTop = -60,
    restStickTime = 0, //in milliseconds
    initialStickInterval = 1000, //in milliseconds
    stickInterval = null, //in milliseconds
    initialStickDuration = 7, //in seconds
    stickDuration = null, //in seconds
    stickTweensArray = [],
    changeSpeedInterval = null,
    countdownTimerInterval = null,
    generateSticksInterval = null,
    generateSticksTimeout = null,
    $gamePage = null;

function init() {
  initVariables();
  initGamePage();
}

function changingSpeedFunction(x){
  var y = Math.pow(2, (x / 20));
  return y;
}

function initVariables() {
  $gamePage = $(".game-page");
  stickDuration = initialStickDuration;
  stickInterval = initialStickInterval;
}

function initGamePage() {
  TweenMax.ticker.useRAF(false);
  TweenMax.lagSmoothing(0);
  initGamePageAnimation();
}

function initGamePageAnimation () {
  generateSticks();

  changeSpeedInterval = setInterval(function () {
    changeSpeed();
  }, changeSpeedTime);

  countdownTimerInterval = setInterval(function () {
    updateCountdown();
  }, 1000);
}

function changeSpeed () {
  var x = timer;
  var y = changingSpeedFunction(x);  //change speed function
  stickDuration = initialStickDuration / y;
  stickInterval = initialStickInterval / y;

  changeCurrentSticksSpeed();
  generateSticks();
}

function changeCurrentSticksSpeed () {
  stickTweensArray.forEach(function(item, i, arr) {
    var tween = item.tween;
    var $stick = item.$stick;

    var oldTime = tween._time;
    var oldDuration = tween._duration;
    var newDuration = stickDuration;
    var oldPosition = stickTop;
    var newPosition = $stick.position().top;
    var oldStartTime = tween._startTime;

    var distance = newPosition - oldPosition;
    var oldSpeed = distance / oldTime;
    var newSpeed = oldSpeed * oldDuration / newDuration;
    var newTime = distance / newSpeed;
    var currentTime = oldStartTime + oldTime;
    var newStartTime = currentTime - newTime;

    item.tween._duration = newDuration;
    item.tween._startTime = newStartTime;
  });
}

function generateSticks () {
  if (restStickTime >= changeSpeedTime) {
    restStickTime -= changeSpeedTime;
    restStickTime = Math.abs(restStickTime);
  } else {
    generateSticksTimeout = setTimeout(function () {
      generateSticksInterval = setInterval(function () {
        generateStick();
        restStickTime -= stickInterval;
        if (restStickTime <= 0) {
          clearInterval(generateSticksInterval);
          restStickTime = Math.abs(restStickTime);
        }
      }, stickInterval);
      generateStick();
      restStickTime = changeSpeedTime - Math.abs(restStickTime) - stickInterval;
      if (restStickTime <= 0) {
        clearInterval(generateSticksInterval);
        restStickTime = Math.abs(restStickTime);
      }
    }, restStickTime);
  }
}

function generateStick () {
  var $stick = $("<div class='" + CSS_CLASS.STICK + "'></div>").appendTo($gamePage);

  animateStick($stick);
}

function animateStick ($stick) {
  var translateYValue = windowHeight + -stickTop;

  var tween = new TweenMax($stick, stickDuration, {
    y: translateYValue, ease: Power0.easeNone, onComplete: function () {
      $stick.remove();
      stickTweensArray.shift();
    }
  });

  stickTweensArray.push({tween:tween, $stick:$stick});
}

function updateCountdown () {
  timer++;

  if (timer >= gameTime) {
    onGameEnd();
    clearInterval(changeSpeedInterval);
    clearInterval(countdownTimerInterval);
    clearInterval(generateSticksInterval);
    clearTimeout(generateSticksTimeout);
  }
}

function onGameEnd () {
  var $sticks = $gamePage.find(".stick");
  TweenMax.killTweensOf($sticks);
}

所以,正如我研究的那样,我有下一个情况:

  1. 当标签处于非活动状态时,TweenMax(因为它使用requestAnimationFrame)会冻结。
  2. 当标签处于非活动状态时,setInterval继续运行(当标签处于非活动状态时,它的延迟可能会发生变化,具体取决于浏览器)
  3. 当标签处于非活动状态时,是否还有其他任何javascript功能会发生变化?
  4. 然后我有两个解决方案:

    1. 当标签处于非活动状态时冻结整个游戏。
    2. 当标签处于非活动状态时继续运行。
    3. 使用第一个解决方案我有下一个问题:由于TweenMax使用requestAnimationFrame,它根据此解决方案正常工作(冻结动画),但是当tab处于非活动状态然后恢复间隔和超时时,如何冻结间隔和超时?

      使用第二个解决方案,我可以使用TweenMax.lagSmoothing(0)和TweenMax.ticker.useRAF(false)来制作动画,但它可以工作,但无论如何,间隔和/或超时都会出错。我预计动画会出现错误,因为当标签处于非活动状态时,间隔延迟会改变为1000+ ms(根据http://stackoverflow...w-is-not-active),但我禁用了加速并将延迟设置为2000毫秒而且没有帮助。

      请至少帮我解决一个问题。两者都更好,有一些变化。

1 个答案:

答案 0 :(得分:0)

解决了第一个解决方案的问题:冻结整个游戏。刚刚使用TweenMax.delayedCall()函数而不是setTimeout和setInterval,整个动画同步得很好。