I am making a game that has a time limit.
In order to achieve that I made these services.js file:
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
};
});
And I have made these controllers on file 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();
}
});
The problem now is that On my App there is a PAUSE button so when I click on it it pauses the timer. The prob is when I get Back from main menu even though the timeout continues to countdown it is like the $scope get never updated.
What I actualy do is:
Note: The value of the timer is updated with angular's $interval() function.
You can see more details here: Problem Image
Also there is the full code here: https://github.com/pc-magas/faster
After a bit of debugging I found a solution to your problem. View wasn't updated since $scope inside timerUpdate callback was different than the one in Game controller. Actually, Angular should update scope automatically when timer's value is changed in the interval. You shouldn't use callback to achieve that. I present my solution below.
Game factory
1) Instead of saving seconds value in timer directly, save it as property of an object:
game.timer = {
value: time
}
2) Remove code which executes timerUpdate callback from startTimer function. You won't need it.
if(typeof game.callbacks === 'object' && typeof game.callbacks['timerUpdate'] === 'function')
{
game.callbacks['timerUpdate'](game.timer);
}
3) Remove all controller scope references from your Game factory. Services should have no idea of controllers' scope existence.
Game controller
1) Remove timerUpdate function from callbacks. You won't need it anymore.
2) Instead of assigning new timer value to scope inside callback, create a scope property after game initialization:
init_game();
$scope.timer = Game.current_game.timer;
Now, $scope.timer contains a reference to your timer object. Once the timer's value gets updated, scope will register that and make proper changes to the view.
Game view
Last change you need to do is substitute {{timer}}
with {{timer.value}}
in the Game view.
Two hints at the end
1) Angular has many built-in functions, which make life easier. One of them is angular.isFunction() which checks if object is a function. You don't need a code like this:
typeof game.callbacks === 'object' && typeof game.callbacks['afterInit'] === 'function'
2) To check if object is null or undefined, you also don't need a code like the one you used:
if(typeof Game.current_game === 'undefined' || Game.current_game === null)
You can simply write:
if(!Game.current_game)