PHP前端开发

HTML5游戏框架cnGameJS开发实录-游戏场景对象

百变鹏仔 2个月前 (10-18) #H5教程
文章标签 游戏

1.什么时候需要场景对象?

场景对象有区别于上一篇介绍的地图对象,它们分别应用于不同类型的游戏。之前的地图对象应用于格子类的游戏,例如推箱子,坦克大战。而本节介绍的场景对象,则适用于拥有特定场景的游戏,例如超级玛丽,恐龙快打等。这类游戏通常在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(&#39;gameCanvas&#39;,{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);//调用父类updateif(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.代码实现:
要构造一个场景,首先需要一张足够宽的背景图片,当player向右移动时,使player始终处于背景中点,player的速度转换为背景向相反方向移动的速度。首先看初始化函数:

/**         *初始化        **/        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;                    },

用户传入的参数除了xy以及尺寸外,另外还有三个参数,一个参数是设置是否把玩家对象置于中心,只移动背景而不移动玩家。如果要实现上面的背景移动效果,该参数要设置为true。另一个参数是设置是否循环。如果设置为循环,在背景移动到极点后,会重新回到初始位置。最后一个参数是onEnd,如果设置为非循环,那么背景移动到极点后,会触发该回调函数。

场景对象的重点在于update方法:

/**         *背景移动时的更新        **/        update:function(spritelist){//传入所有sprite的数组            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固定。如果是循环的话,则在超出移动范围后重置背景和其他sprite的x坐标。如果非循环,则在移动结束后调用onEnd回调函数。另外如果需要限制player始终在显示区域内,还可以调用insideView方法。

附上场景对象所有代码:

/** * *场景 ***/cnGame.register("cnGame",function(cg){        /**     *使指定对象在可视区域view内    **/    var inside=function(sprite){        var dir=sprite.insideDir;        if(dir!="y"){            if(sprite.xthis.width-sprite.width){                sprite.x=this.width-sprite.width;            }        }        if(dir!="x"){            if(sprite.ythis.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