【CSON原創(chuàng)】HTML5游戲框架cnGameJS開發(fā)實錄(游戲循環(huán)篇)
由于整個游戲都在一個游戲循環(huán)中進(jìn)行,所以游戲循環(huán)可以說是游戲的核心部分。每次循環(huán)時,更新游戲?qū)ο蟮膶傩裕约袄L制游戲元素。
在之前的資源加載篇已經(jīng)提到過,在資源加載完成后,啟動游戲的同時會啟動一個游戲循環(huán),現(xiàn)在再來回顧這部分代碼:
/**
*圖像加載完畢的處理程序
**/
var imgLoad=function(self){
return function(){
self.loadedCount+=1;
self.loadedImgs[this.srcPath]=this;
this.onLoad=null; //保證圖片的onLoad執(zhí)行一次后銷毀
self.loadedPercent=Math.floor(self.loadedCount/self.sum*100);
self.onLoad&&self.onLoad(self.loadedPercent);
if(self.loadedPercent===100){
self.loadedCount=0;
self.loadedPercent=0;
loadingImgs={};
if(self.gameObj&&self.gameObj.initialize){
self.gameObj.initialize();
if(cg.loop&&!cg.loop.stop){//結(jié)束上一個循環(huán)
cg.loop.end();
}
cg.loop=new cg.GameLoop(self.gameObj);//開始新游戲循環(huán)
cg.loop.start();
}
}
}
}
圖像資源加載完畢后,調(diào)用游戲?qū)ο蟮膇nitialize方法,并且判斷游戲循環(huán)對象是否存在,如果存在,則結(jié)束上一個循環(huán)(這種情況一般在切換關(guān)卡,傳入新的游戲?qū)ο髸r出現(xiàn)),否則建立并開始游戲循環(huán)。
好了,現(xiàn)在正式來看看游戲循環(huán)的實現(xiàn)代碼:
var gameLoop=function(gameObj,options){
if(!(this instanceof arguments.callee)){
return new arguments.callee(gameObj,options);
}
this.init(gameObj,options);
}
首先游戲循環(huán)函數(shù)也必須保證是以構(gòu)造函數(shù)的形式調(diào)用,在調(diào)用之后,為對象初始化:
/**
*初始化
**/
init:function(gameObj,options){
/**
*默認(rèn)對象
**/
var defaultObj={
fps:30
};
options=options||{};
options=cg.core.extend(defaultObj,options);
this.gameObj=gameObj;
this.fps=options.fps;
interval=1000/this.fps;
this.pause=false;
this.stop=true;
},
用戶需要設(shè)置的參數(shù)只有一個,就是fps(frame per second),該參數(shù)是每秒鐘執(zhí)行的幀的次數(shù),根據(jù)該參數(shù),我們可以計算出多少毫秒執(zhí)行一次游戲循環(huán)(interval參數(shù))。另外循環(huán)支持暫停和停止兩種模式。
/**
*開始循環(huán)
**/
start:function(){
if(this.stop){ //如果是結(jié)束狀態(tài)則可以開始
this.stop=false;
this.now=new Date().getTime();
this.startTime=new Date().getTime();
this.duration=0;
loop.call(this)();
}
},
當(dāng)循環(huán)開始,我們可以保存開始的時間,這樣就可以不斷更新循環(huán)所經(jīng)歷的時間(duration)。之后調(diào)用loop這個似有函數(shù),實現(xiàn)循環(huán)。
var timeId;
var interval;
/**
*循環(huán)方法
**/
var loop=function(){
var self=this;
return function(){
if(!self.pause&&!self.stop){
self.now=new Date().getTime();
self.duration=self.startTime-self.now;
if(self.gameObj.update){
self.gameObj.update();
}
if(self.gameObj.draw){
cg.context.clearRect(0,0,cg.width,cg.height);
self.gameObj.draw();
}
}
timeId=window.setTimeout(arguments.callee,interval);
}
}
如果不是暫停或停止,則調(diào)用游戲?qū)ο蟮膗pdate和draw(注意游戲?qū)ο蟮膗pdate負(fù)責(zé)調(diào)用該關(guān)卡所有元素的update,draw也一樣)。之后調(diào)用setTimeout遞歸調(diào)用自己,實現(xiàn)循環(huán)。
游戲循環(huán)所有源碼:
/**
*
*游戲循環(huán)
*
**/
cnGame.register("cnGame",function(cg){
var timeId;
var interval;
/**
*循環(huán)方法
**/
var loop=function(){
var self=this;
return function(){
if(!self.pause&&!self.stop){
self.now=new Date().getTime();
self.duration=self.startTime-self.now;
if(self.gameObj.update){
self.gameObj.update();
}
if(self.gameObj.draw){
cg.context.clearRect(0,0,cg.width,cg.height);
self.gameObj.draw();
}
}
timeId=window.setTimeout(arguments.callee,interval);
}
}
var gameLoop=function(gameObj,options){
if(!(this instanceof arguments.callee)){
return new arguments.callee(gameObj,options);
}
this.init(gameObj,options);
}
gameLoop.prototype={
/**
*初始化
**/
init:function(gameObj,options){
/**
*默認(rèn)對象
**/
var defaultObj={
fps:30
};
options=options||{};
options=cg.core.extend(defaultObj,options);
this.gameObj=gameObj;
this.fps=options.fps;
interval=1000/this.fps;
this.pause=false;
this.stop=true;
},
/**
*開始循環(huán)
**/
start:function(){
if(this.stop){ //如果是結(jié)束狀態(tài)則可以開始
this.stop=false;
this.now=new Date().getTime();
this.startTime=new Date().getTime();
this.duration=0;
loop.call(this)();
}
},
/**
*繼續(xù)循環(huán)
**/
run:function(){
this.pause=false;
},
/**
*暫停循環(huán)
**/
pause:function(){
this.pause=true;
},
/**
*停止循環(huán)
**/
end:function(){
this.stop=true;
window.clearTimeout(timeId);
}
}
this.GameLoop=gameLoop;
});
浙公網(wǎng)安備 33010602011771號