【CSON原創(chuàng)】HTML5游戲框架cnGameJS開發(fā)實錄(游戲場景對象)
1.什么時候需要場景對象?
場景對象有區(qū)別于上一篇介紹的地圖對象,它們分別應用于不同類型的游戲。之前的地圖對象應用于格子類的游戲,例如推箱子,坦克大戰(zhàn)。而本節(jié)介紹的場景對象,則適用于擁有特定場景的游戲,例如超級瑪麗,恐龍快打等。這類游戲通常在2d場景內控制一個玩家對象,隨著玩家的移動,場景跟著移動。
2.場景示例:
效果:(左右鍵控制超級瑪麗的移動)
代碼:
<body>
<div><canvas id="gameCanvas">請使用支持canvas的瀏覽器查看</canvas></div>
</body>
<script src="cnGame_v1.0.js"></script>
<script>
var Src="http://images.cnblogs.com/cnblogs_com/Cson/290336/o_player.png";
var background="background.png";
/* 初始化 */
cnGame.init('gameCanvas',{width:500,height:400});
var floorY=cnGame.height-40;
var gameObj=(function(){
/* 玩家對象 */
var player=function(options){
this.init(options);
this.speedX=0;
this.moveDir;
this.isJump=false;
}
cnGame.core.inherit(player,cnGame.Sprite);
player.prototype.initialize=function(){
this.addAnimation(new cnGame.SpriteSheet("playerRight",Src,{frameSize:[50,60],loop:true,width:150,height:60}));
this.addAnimation(new cnGame.SpriteSheet("playerLeft",Src,{frameSize:[50,60],loop:true,width:150,height:120,beginY:60}));
}
player.prototype.moveRight=function(){
if(cnGame.core.isUndefined(this.moveDir)||this.moveDir!="right"){
this.moveDir="right";
this.speedX<0&&(this.speedX=0);
this.setMovement({aX:10,maxSpeedX:15});
this.setCurrentAnimation("playerRight");
}
}
player.prototype.moveLeft=function(){
if(cnGame.core.isUndefined(this.moveDir)||this.moveDir!="left"){
this.moveDir="left";
this.speedX>0&&(this.speedX=0);
this.setMovement({aX:-10,maxSpeedX:15});
this.setCurrentAnimation("playerLeft");
}
}
player.prototype.stopMove=function(){
if(this.speedX<0){
this.setCurrentImage(Src,0,60);
}
else if(this.speedX>0){
this.setCurrentImage(Src);
}
this.moveDir=undefined;
this.resetMovement();
}
player.prototype.update=function(){
player.prototype.parent.prototype.update.call(this);//調用父類update
if(cnGame.input.isPressed("right")){
this.moveRight();
}
else if(cnGame.input.isPressed("left")){
this.moveLeft();
}
else{
this.stopMove();
}
}
return {
initialize:function(){
cnGame.input.preventDefault(["left","right","up","down"]);
this.player=new player({src:Src,width:50,height:60,x:0,y:floorY-60});
this.player.initialize();
this.background=new cnGame.View({src:background,player:this.player,imgWidth:2301});
this.background.centerPlayer(true);
this.background.insideView(this.player,"x");
},
update:function(){
this.player.update();
this.background.update([this.player]);
},
draw:function(){
this.background.draw();
this.player.draw();
}
};
})();
cnGame.loader.start([Src,background],gameObj);
</script>
3.代碼實現(xiàn):
要構造一個場景,首先需要一張足夠寬的背景圖片,當player向右移動時,使player始終處于背景中點,player的速度轉換為背景向相反方向移動的速度。首先看初始化函數(shù):
/**
*初始化
**/
init:function(options){
/**
*默認對象
**/
var defaultObj={
width:cg.width,
height:cg.height,
imgWidth:cg.width,
imgHeight:cg.height,
x:0,
y:0
}
options=options||{};
options=cg.core.extend(defaultObj,options);
this.player=options.player;
this.width=options.width;
this.height=options.height;
this.imgWidth=options.imgWidth;
this.imgHeight=options.imgHeight;
this.centerX=this.width/2;
this.src=options.src;
this.x=options.x;
this.y=options.y;
this.insideArr=[];
this.isLoop=false;;
this.isCenterPlayer=false;
this.onEnd=options.onEnd;
},
用戶傳入的參數(shù)除了xy以及尺寸外,另外還有三個參數(shù),一個參數(shù)是設置是否把玩家對象置于中心,只移動背景而不移動玩家。如果要實現(xiàn)上面的背景移動效果,該參數(shù)要設置為true。另一個參數(shù)是設置是否循環(huán)。如果設置為循環(huán),在背景移動到極點后,會重新回到初始位置。最后一個參數(shù)是onEnd,如果設置為非循環(huán),那么背景移動到極點后,會觸發(fā)該回調函數(shù)。
場景對象的重點在于update方法:
/**
*背景移動時的更新
**/
update:function(spritelist){//傳入所有sprite的數(shù)組
if(this.isCenterPlayer){
if(this.player.x>this.centerX){
if(this.x<this.imgWidth-this.width){
var marginX=this.player.x-this.centerX;
this.x+=marginX;
if(spritelist){
for(var i=0,len=spritelist.length;i<len;i++){
if(spritelist[i]==this.player){
spritelist[i].x=this.centerX;
}
else{
spritelist[i].x-=marginX;
}
}
}
}
else if(this.isLoop){
if(spritelist){
for(var i=0,len=spritelist.length;i<len;i++){
if(spritelist[i]!=this.player){
spritelist[i].move(this.imgWidth-this.width);
}
}
}
this.x=0;
}
else{
this.onEnd&&this.onEnd();
}
}
}
for(var i=0,len=this.insideArr.length;i<len;i++){
inside.call(this,this.insideArr[i]);
}
},
該方法首先判斷player對象是否已經超過場景中心,如果已經超過,則計算超出的距離,并且把player固定在場景中心,超出的距離設置為背景向相反方向移動的距離與除了player外其他sprite向相反方向移動的距離,這樣的話就只有背景移動和其他sprite對象移動,player固定。如果是循環(huán)的話,則在超出移動范圍后重置背景和其他sprite的x坐標。如果非循環(huán),則在移動結束后調用onEnd回調函數(shù)。另外如果需要限制player始終在顯示區(qū)域內,還可以調用insideView方法。
附上場景對象所有代碼:
/**
*
*場景
*
**/
cnGame.register("cnGame",function(cg){
/**
*使指定對象在可視區(qū)域view內
**/
var inside=function(sprite){
var dir=sprite.insideDir;
if(dir!="y"){
if(sprite.x<0){
sprite.x=0;
}
else if(sprite.x>this.width-sprite.width){
sprite.x=this.width-sprite.width;
}
}
if(dir!="x"){
if(sprite.y<0){
sprite.y=0;
}
else if(sprite.y>this.height-sprite.height){
sprite.y=this.height-sprite.height;
}
}
}
var view=function(options){
this.init(options);
}
view.prototype={
/**
*初始化
**/
init:function(options){
/**
*默認對象
**/
var defaultObj={
width:cg.width,
height:cg.height,
imgWidth:cg.width,
imgHeight:cg.height,
x:0,
y:0
}
options=options||{};
options=cg.core.extend(defaultObj,options);
this.player=options.player;
this.width=options.width;
this.height=options.height;
this.imgWidth=options.imgWidth;
this.imgHeight=options.imgHeight;
this.centerX=this.width/2;
this.src=options.src;
this.x=options.x;
this.y=options.y;
this.insideArr=[];
this.isLoop=false;;
this.isCenterPlayer=false;
this.onEnd=options.onEnd;
},
/**
*使player的位置保持在場景中點之前的移動背景
**/
centerPlayer:function(isLoop){
isLoop=isLoop||false;
this.isLoop=isLoop;
this.isCenterPlayer=true;
},
/**
*使對象的位置保持在場景內
**/
insideView:function(sprite,dir){//dir為限定哪個方向在view內,值為x或y,不傳則兩個方向皆限定
if(cg.core.isArray(sprite)){
for(var i=0,len=sprite.length;i<len;i++){
arguments.callee.call(this,sprite[i],dir);
}
}
else{
sprite.insideDir=dir;
this.insideArr.push(sprite);
}
},
/**
*背景移動時的更新
**/
update:function(spritelist){//傳入所有sprite的數(shù)組
if(this.isCenterPlayer){
if(this.player.x>this.centerX){
if(this.x<this.imgWidth-this.width){
var marginX=this.player.x-this.centerX;
this.x+=marginX;
if(spritelist){
for(var i=0,len=spritelist.length;i<len;i++){
if(spritelist[i]==this.player){
spritelist[i].x=this.centerX;
}
else{
spritelist[i].x-=marginX;
}
}
}
}
else if(this.isLoop){
if(spritelist){
for(var i=0,len=spritelist.length;i<len;i++){
if(spritelist[i]!=this.player){
spritelist[i].move(this.imgWidth-this.width);
}
}
}
this.x=0;
}
else{
this.onEnd&&this.onEnd();
}
}
}
for(var i=0,len=this.insideArr.length;i<len;i++){
inside.call(this,this.insideArr[i]);
}
},
/**
*繪制場景
**/
draw:function(){
cg.context.drawImage(cg.loader.loadedImgs[this.src],this.x,this.y,this.width,this.height,0,0,this.width,this.height);
}
}
this.View=view;
});
浙公網安備 33010602011771號