• 【CSON原创】HTML5游戏框架cnGameJS开发实录(游戏场景对象)


    返回目录

    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(
    'gameCanvas',{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,150,height:60}));
    this.addAnimation(new cnGame.SpriteSheet("playerLeft",Src,{frameSize:[50,60],loop:true,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,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={
    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.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={
    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的数组
    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;
    });
  • 相关阅读:
    vue获取当前v-for里当前点击元素
    js利用正则替换图片路径问题
    undefined null 各种值比较(面试题)
    SSE两个页面的相互通信
    微信小程序导航栏,下面内容滑动,上册导航栏跟着滑动,内容随着导航栏滑动
    微信小程序缓存滑动距离,当页面浏览到一定位置,滑动其他页面后返回该页面记录之前的滑动距离
    ajax拖拽上传文件
    Java 面向对象(四)
    关于Scanner调用 sc.nextInt() 异常try后不能二次输入导致死循环问题
    Java 面向对象(三)
  • 原文地址:https://www.cnblogs.com/Cson/p/2350081.html
Copyright © 2020-2023  润新知