暂停时离子框架倒计时

Ionic Framework countdown when Pause

我正在制作一个有时间限制的游戏。

为了实现这一点,我制作了这些 services.js 文件:

var module=angular.module('starter.services', ['ionic', 'ui.router']);
module.factory('Game', function($interval)
{
      /**
      *Class we need for the game
      *@param items {Array} with the items the game consisted of
      *@param time {Int} How many seconds tis the duration of game
      *@param grid_width How many Items each row will have
      *@param grid_height How many items the grid will have vertically
      */
      function Game(items,time,grid_width,grid_height,callbacks,scope)
      {
        var game=this;

        //The total Items The game is consisted of
        game.items=items;

        //The grid of the items that will be swapped
        game.grid=[];

        game.callbacks=callbacks;

        game.scope=scope;

        /**
        *Function that performs the logic
        *and does the comparisons between Items
        */
        game.swap=function()
        {

        };

        /**
        *Method that Initialises and starts the game
        *Why I used this function and not game.start()
        *is because this way the code for initializing the grid is saparate from the code that initialises the clock
        */
        game.init=function()
        {
          game.timer=time;
          if(typeof game.callbacks === 'object' && typeof game.callbacks['afterInit'] === 'function') game.callbacks['afterInit'](game);
          game.play();
        }

        /*####################### Starting apausing and overing the game #############*/
        /**
        *The Game has the Foillowing Status
        *'uninitialised': When the game has Not Been Started yet
        *'play': When gameplay is on progress
        *'paused': When the game is paused
        *'over': When Game Over
        */
        game.status='uninitialised';


        game.timer=time;

        /**
        *Function that starts the timer
        */
        var startTimer=function()
        {
          if(game.timer>0)
          {
            //Better to Use Angular's Interval
            interval=$interval(function()
            {
              if(game.status==='play')
              {
                game.timer--;
                if(game.timer==0) game.over();

                if(typeof game.callbacks === 'object' && typeof game.callbacks['timerUpdate'] === 'function')
                {
                  game.callbacks['timerUpdate'](game.timer,game.scope);
                }
              }
            },1000);
          }
        }

        /**
        *Function that stops the timer
        */
        var stopTimer=function()
        {
          if(interval!==null) $interval.cancel(interval);
        }


        /**
        *The Interval of the setInterval();
        */
        var interval=null;

        /**
        *Method that Pauses the game
        *Enter here code that tell what will be executed when the game is paused
        */
        game.pause=function()
        {
          game.status='paused';
          if(typeof game.callbacks === 'object' && typeof game.callbacks['pause'] === 'function') game.callbacks['pause'](game.timer);
          //stopTimer();
        }


        /**
        *Method that starts the game
        *Enter code here to be executer when the game is started
        */
        game.play=function()
        {
          console.log("Game Started");
          game.status='play';

          //Start the counter
          startTimer();
        }

        /**
        *Method that ends the game
        *Enter code here to be executer when the game is ended
        */
        game.over=function()
        {
          game.status='over';
          if(interval!==null) $interval.cancel(interval);
        }

        game.isOver=function()
        {
          return game.status==='over';
        }

        game.isPaused=function()
        {
          return game.status==='paused';
        }

        game.isNotPausedOrOver=function()
        {
          return game.status==='play';
        }
        /*##############################################################################*/

        /*######################### For Scoring system #######################*/
        game.points=0;

        game.addScore=function(points)
        {
          game.points+=points;
        }

        game.removeScore=function(points)
        {
          game.points-=points;
        }
        /*#####################################################################*/

        /*########### Functions for Game Saving and Loading ###################*/
        game.save=function()
        {
          console.log("Game Saving");
          //Code for game saving
        }

        game.load=function()
        {
          //Code for game loading
        }
        /*########### End of Functions ddor Game saving and Loading ###########*/

      };//End Of Game Class

      /**
      *Function we need for the Game Item
      *@param icon {String} Normal Icon For the Item (it can be either html or image path)
      *@param icon_destroyed {String} Icon when The Game is Destroyed (it can be either html or image path)
      *@param icon_marked {String}
      */
      function GameItem(icon,icon_destroyed,icon_marked,name)
      {
        var item=this;

        item.icon=icon;//Icon for the normal situations
        item.icon_destroyed=icon_destroyed;//Icon if the item is Destroyed
        item.icon_marked=icon_marked;//Icon when the item is selected

        /*
        *A Characteristic name of the itemYourFactory
        *It can Be used for comparisons ;)
        */
        item.name=name;

        /**
        *For now takes 2 values:
        *start if the Item is not destroyed
        *destroyed if the item in destroyed
        *whatever dtatus you want
        */
        item.status="start";

        /**
        *The position of the Item
        *Check if you need it
        */
        item.posistion={x:0,y:0};

        /**
        *Check if this item is equal with another one
        */
        item.equals=function(other)
        {
          return other.name===item.name;
        };

        /**
        *Gets The icon regarding the status of the Item is
        */
        item.getIcon=function()
        {
          var icon="";
          //Add here the status of the
          switch(item.status)
          {
            case 'destroyed':
              icon=item.icon_destroyed;
            break;

            case 'start':
              icon=item.icon;
            break;

            default:
              icon=item.icon;
          }
          return icon;
        }
      };//End of Item Class

      return {
              game:Game,
              item:GameItem,
              current_game:null
             };
});

并且我已经将这些控制器存档 controllers.js

angular.module('starter.controllers', ['ionic','ui.router'])

/**
*Controller that does all the Dirty Job for the Game
*/
.controller('Game',function($scope,$timeout,$state,Game,MenuItem)
{

  /*################### Controller Initialization ####################*/
  var GameItem=Game.item;
  var GameClass=Game.game;
  /*##################### End Controller Initialization ##############*/

  /**
  *Function That does all the dirty job for initialization
  */
  var init_game=function()
  {
    console.log(Game.current_game);
    if(typeof Game.current_game === 'undefined' || Game.current_game === null)
    {
      /**
      *Items for the Game
      */
      var items=[
                  new GameItem('./img/icon1.png','./img/icon1.png','./img/icon1.png','trolley'),
                  new GameItem('./img/icon2.png','./img/icon2.png','./img/icon2.png','metro'),
                  new GameItem('./img/icon3.png','./img/icon3.png','./img/icon3.png','bus'),
                  new GameItem('./img/icon4.png','./img/icon4.png','./img/icon4.png','tram'),
                ];

      /**
      *Callbacks for Game
      */
      var callbacks={
                      'timerUpdate':function(time,scope)
                      {
                        $timeout(function()
                        {
                          $scope.time=time;
                          console.log($scope.time);
                        });
                      },
                      'pause':function(time)
                      {
                        console.log("Game Paused");
                        $state.go('menu');
                      },
                      'afterInit':function(game)
                      {
                        MenuItem.items.play.name_="Continue Game";
                        MenuItem.items.play.clickFunction=function()
                        {
                          console.log("clicked");
                          $state.go('game');
                          Game.current_game.play();//Do not comment unlsess game will not resume
                        };

                        /*Making An Option For saving*/
                        var saveItem=new MenuItem.MenuItem("Save Game",'regular-btn',"",false,function()
                        {
                          game.save();
                        });
                        //Add on the top an Option to save the game
                        MenuItem.items.others.unshift(saveItem);
                        console.log(MenuItem.items.others);
                      }
                    };

      Game.current_game=new GameClass(items,60,5,10,callbacks,$scope);
      Game.current_game.init();
    }
    else // We may need to go to another page and return Therefore we must need a way to resume
    {
      console.log("Here resuming the game");
      Game.current_game.play();
    }
  };


  init_game();

  $scope.pause=function()
  {
    console.log("Pausing Game");
    Game.current_game.pause();
  }
});

现在的问题是在我的应用程序上有一个暂停按钮,所以当我点击它时它会暂停计时器。问题是当我从主菜单返回时,即使超时继续倒计时,它就像 $scope 从未更新过。

我实际做的是:

  1. 从主菜单进入游戏页面。 (在这一步显示定时器 正确)
  2. 点击暂停返回主菜单。
  3. 从主菜单返回游戏页面。 (即使计时器倒计时,正如我在 console.log 中看到的那样,我在示波器上看不到)。

注意:定时器的值是用angular的$interval()函数更新的。

您可以在此处查看更多详细信息: Problem Image

这里还有完整的代码:https://github.com/pc-magas/faster

经过一些调试,我找到了解决您的问题的方法。视图未更新,因为 $scope 内的 timerUpdate 回调与游戏控制器中的回调不同。实际上,Angular 应该在间隔内定时器的值发生变化时自动更新作用域。你不应该使用回调来实现这一点。我在下面介绍我的解决方案。

游戏工厂

1) 不要直接将秒值保存在timer中,而是将其保存为对象的属性:

game.timer = {
    value: time
}

2) 从 startTimer 函数中删除执行 timerUpdate 回调的代码。你不需要它。

if(typeof game.callbacks === 'object' && typeof game.callbacks['timerUpdate'] === 'function')
{
     game.callbacks['timerUpdate'](game.timer);          
}

3) 从您的游戏工厂中删除所有控制器作用域引用。服务应该不知道控制器范围的存在。

游戏控制器

1) 从回调中删除 timerUpdate 函数。你将不再需要它了。

2) 在游戏初始化后创建一个范围 属性,而不是将新的计时器值分配给回调内的范围:

init_game();
$scope.timer = Game.current_game.timer;

现在,$scope.timer 包含对您的 timer 对象的引用。一旦计时器的 得到更新,范围将注册它并对视图进行适当的更改。

游戏视角

您需要做的最后一个更改是在游戏视图中将 {{timer}} 替换为 {{timer.value}}


结尾有两个提示

1) Angular有很多built-in功能,让生活更轻松。其中之一是 angular.isFunction() ,它检查对象是否是一个函数。您不需要这样的代码:

typeof game.callbacks === 'object' && typeof game.callbacks['afterInit'] === 'function'

2) 要检查对象是否为 nullundefined,您也不需要像您使用的那样的代码:

if(typeof Game.current_game === 'undefined' || Game.current_game === null)

你可以简单地写:

if(!Game.current_game)