Cocos2d-JS连载之打飞机游戏学习基础概念

打飞机这个游戏并不是我原创,只是拿来学习使用。望原作者见谅。刚刚开始是强烈建议可以上传源代码的,但是后来一想,已经有了github了可以直接链接过去,都不用浪费资源了。哈哈哈哈。我讲要分析的项目上传到了我的github仓库:github AirBarons

游戏玩耍地址:http://112.126.90.18/airbarons/
  先看一下AirBarons目录结构。

Cocos2d-JS连载之打飞机游戏学习基础概念_第1张图片
AirBarons目录结构

  • project.json 项目的一些配置信息
"project_type": "javascript",
    "debugMode" : 1,
    "showFPS" : true,
    "frameRate" : 60,
    "id" : "gameCanvas",
    "renderMode" : 0,
    "engineDir":"frameworks/cocos2d-html5",
    "modules" : ["cocos2d"],

这些前一篇已经说过了。
看下AirBarons项目用到了哪些js文件

"jsList" : [
        "src/resource.js",
        
        "src/config/GameConfig.js",
        "src/config/EnemyType.js",
        "src/config/Level.js",

        "src/mainMenu/scene/MainMenu.js",
        "src/mainMenu/layer/MMBackgroundLayer.js",
        "src/mainMenu/layer/MMMainMenuLayer.js",
        "src/mainMenu/layer/MMTouchLayer.js",

        "src/setting/scene/Setting.js",
        "src/setting/layer/STBackgroundLayer.js",
        "src/setting/layer/STTouchLayer.js",

        "src/about/scene/About.js",
        "src/about/layer/ABBackgroundLayer.js",
        "src/about/layer/ABTouchLayer.js",

        "src/gamePlay/classes/LevelManager.js",
        "src/gamePlay/scene/GamePlay.js",
        "src/gamePlay/layer/GPBackgroundLayer.js",
        "src/gamePlay/layer/GPTouchLayer.js",
        "src/gamePlay/sprite/ShipSprite.js",
        "src/gamePlay/sprite/BulletSprite.js",
        "src/gamePlay/sprite/EnemySprite.js",
        "src/gamePlay/sprite/ExplosionSprite.js",
        "src/gamePlay/sprite/SparkEffectSprite.js",

        "src/gameOver/scene/GameOver.js",
        "src/gameOver/layer/GOBackgroundLayer.js",
        "src/gameOver/layer/GOTouchLayer.js"

    ]

基本概念之resource
看到加载的第一个文件就是 "src/resource.js",典型的js文件。定义了res对象,里面存储的是图片和声音的地址对象,最后将res对象的属性都放到了全局g_resources数组中了

var res = {
    HelloWorld_png : "res/HelloWorld.png",
    CloseNormal_png : "res/CloseNormal.png",
    CloseSelected_png : "res/CloseSelected.png",


//    shared
    sh_arial_14_fnt : 'res/shared/arial-14.fnt',
    sh_arial_14_png : 'res/shared/arial-14.png',

//    mainMenu
    TextureTransparentPack_plist : "res/mainMenu/textureTransparentPack.plist",
    TextureTransparentPack_png : "res/mainMenu/textureTransparentPack.png",
    mm_bg_png   : "res/mainMenu/bg.png",
    mm_logo_png : "res/mainMenu/logo.png",
    mm_mune_png : "res/mainMenu/menu.png",
    mm_flare_jpg : "res/mainMenu/flare.jpg",
    mm_btnEffect : "res/sound/effect/buttonEffect.mp3",
    mm_bgMusic_mp3 : "res/sound/music/mainMainMusic.mp3",

//    gamePlay
    gp_TextureOpaquePack_plist : "res/gamePlay/textureOpaquePack.plist",
    gp_TextureOpaquePack_png : "res/gamePlay/textureOpaquePack.png",
    gp_b01_plist : "res/gamePlay/b01.plist",
    gp_b01_png : "res/gamePlay/b01.png",
    gp_Explosion_plist : "res/gamePlay/explosion.plist",
    gp_Explosion_png : "res/gamePlay/explosion.png",
    gp_explodeEffect_mp3 : 'res/sound/effect/explodeEffect.mp3',
    gp_bgMusic_mp3 : "res/sound/music/bgMusic.mp3",
    gp_shipDestroyEffect_mp3 : 'res/sound/effect/shipDestroyEffect.mp3',

//    setting
    st_menuTitle_png : "res/setting/menuTitle.png",

//    gameOver
    go_gameOver_png : "res/gameOver/gameOver.png",
    go_cocos2d_html5_png : "res/gameOver/cocos2d-html5.png"

};

var g_resources = [];
for (var i in res) {
    g_resources.push(res[i]);
}
  • 接着是游戏js中用到的配置相关参数js的引入
"src/config/GameConfig.js",
"src/config/EnemyType.js",
"src/config/Level.js",
  • 接着是到了游戏各个分类的相关js文件的引入,该游戏有 设置关于游戏游戏结束后四个模块。下面看看这四个模块都用到了Cocos2d 的哪些基础概念。

首先说一下js的地址是:api-ref/js/V3.12/
看main.js

cc.game.onStart = function(){
    cc.view.adjustViewPort(true);
    cc.view.setDesignResolutionSize(320, 480,                 cc.ResolutionPolicy.SHOW_ALL);
    cc.view.resizeWithBrowserSize(true);
    cc.LoaderScene.preload(g_resources, function () {
        cc.director.runScene(new MainMenuScene());
    }, this);
};
cc.game.run();
  1. cc.game
    这个是An object to boot the game.(启动游戏的对象)其中有 end(游戏停止)、isPaused(检查游戏是否停止)、pause(停止游戏)、prepare(游戏前准备)、restart(游戏重新启动)
    resume(继续游戏)、run(启动游戏) setFrameRate(设置帧率)、step(一帧一帧运行游戏)这些方法。还有很多属性onStart就是其中的一个属性,这里将onStart定义成了一个function,在scripts引擎加载完毕后就会回调。
  2. cc.view
    在onStart回调的方法中设置了cc.view的相关属性,cc.view是个代表了游戏窗口的单例的对象
    这里使用setDesignResolutionSize(width, height, resolutionPolicy)设置了游戏窗口的大小和屏幕适配的策略。屏幕大小自适应的涉及到cc.ResolutionPolicy,其中有六种方式

EXACT_FIT会拉伸游戏,充满整个屏幕,最简单最粗暴
SHOW_ALL保持游戏原比例,让一边占满屏幕,另外一侧黑边
NO_BORDER跟SHOW_ALL类似,但让短边占满屏幕,另外一侧超出屏幕,不显示黑边,一部分画面在屏幕外,无法显示
FIXED_HEIGHTFIXED_WIDTH都是NO_BORDER的升级版,指定那一侧充满屏幕,另外一侧超出屏幕,
UNKNOWN 六种方案。该游戏选择的是SHOW_ALL
接着使用resizeWithBrowserSize(enabled)
这个方法只在web中起作用,canvas 跟着浏览器得大小变动而自适应。

  1. cc.LoaderScenecc.director
Cocos2d-JS连载之打飞机游戏学习基础概念_第2张图片
Node子类的结构图

这里涉及到Node、Scence、Director。即节点、导演和场景 ,其实还有Layer(层)、Sprite(精灵)。节点是Node是上层的对象。在Cocos2d-x-3.x引擎中,采用节点树形结构来管理游戏对象,一个游戏可以划分为不同的场景,一个场景又可以分为不同的层,一个层又可以拥有任意个可见的游戏节点(即对象,游戏中基本上所有的类都派生于节点类Node)。可以执行Action来修改游戏节点的属性,使其移动、旋转、放大、缩小等等。
看下官网给出的图即可明白


Cocos2d-JS连载之打飞机游戏学习基础概念_第3张图片
官网给出的关系图

到眼控制着场景,层属于场景中的一个场景。然后精灵有事属于场景中的一个东东。精灵的移动,旋转,缩放,执行动画,并接受其他转换构成层的东西,各个层之间顺序执行然后构成一个场景。场景之间的切换最终构成了一个游戏,执行者就是导演。
cc.LoaderScene.preload了g_resources后传入回调函数
function () {
cc.director.runScene(new MainMenuScene());
}回调函数是导演执行了第一个场景。
再传入当前的对象 this);
好了看new出的第一个场景 MainMenuScene 看一下场景定义的规范

var MainMenuScene  = cc.Scene.extend({
 //this._super();重写后这个方法一定要记得写上,要不然导致后续不会执行
//这里是场景的各个函数的重写 场景是是继承自node的所以node中方法也可以被重写,其中这里有onEnter方法,这个方法是不需要主动调用的。
官方给出的解释Event callback that is invoked every time when CCNode enters the 'stage'. 可以看出 这个方法会每次都被调用 当进入到stage后.
var layer = new MainMenuLayer();
  this.addChild(layer);这个场景只有一个层,最后将这个层假如到这个场景,由于只有一个层所以都不需要指定执行的顺序。
})

下面看MainMenuLayer,层的规范定义是

var MainMenuLayer = cc.Layer.extend({
//    这里可以声明属性
    _backgroundLayer : null,
    _touchLayer      : null,
ctor方法相当于是构造方法,你在new这个层的时候就会被调用。
构造方法中又可以调用其他的方法
这里是调用了addBackgroundLayer和addTouchLayer可以看出是加了两个子层到该层中,这个是按加入的顺序执行的。
})

看一下假如的MMBackgroundLayer和MMTouchLayer层,
MMBackgroundLayer是创建了一个背景层,这个和上一个所讲的层基本一致。里面涉及到了精灵的创建

 this._sptBg = new cc.Sprite(res.mm_bg_png);
        this._sptBg.attr({
            anchorX : 0.5,
            anchorY : 0.5,
            x: GC.w_2,
            y: GC.h_2
        });

可以看出精灵的创建方式 可以指定属性一个其中有anchorPoint 锚点坐标,默认是 (0.5, 0.5) 这就说明这个精灵位于层的中央。x,y是宽和高的概念。
这里涉及到cocos2d的坐标概念
总之openGL的坐标和UI的坐标是不一致的,按openGL坐标来就可以了

Cocos2d-JS连载之打飞机游戏学习基础概念_第4张图片
ui坐标

Cocos2d-JS连载之打飞机游戏学习基础概念_第5张图片
openGL坐标

坐标中还有模型坐标和世界坐标的概念 其实就是精灵相对的坐标概念

![Upload Paste_Image.png failed. Please try again.]
在游戏场景中有两个Node对象,其中Node1的坐标是(400, 500),大小是300 x 100像素。Node2是放置在Node1中的,它对于Node1的模型坐标是(0, 0),大小是150 x 50像素。

好了继续到MMTouchLayer了,在该层中 用到了cc.audioEngine去播放音乐。

/        播放背景音乐,true代表循环无限次播放,false表示只播放一次。
        if (GC.SOUND_ON){
            if (cc.audioEngine.isMusicPlaying()){
                return;
            }
            cc.audioEngine.playMusic(res.mm_bgMusic_mp3, true);
        }

然后又去加载了cc.Menu

//        菜单。 对应三者关系:菜单里面有菜单项,菜单项中绑定要执行的方法,并且需要图片去显示。图片就是精灵
        var menu = new cc.Menu(newGame, gameSettings, about);
        menu.alignItemsVerticallyWithPadding(10);
        menu.x = GC.w_2;
        menu.y = GC.h_2 - 80;
        this.addChild(menu, 1, 2);

构造方法传入的是cc.MenuItemSprite 看其中的一个MenuItemSprite 定义

var newGame = new cc.MenuItemSprite(
            newGameNormal,
            newGameSelected,
            newGameDisabled,
            function(){
                this.onButtonEffect();
                this.flareEffect(flare, this, this.onNewGame);
            }.bind(this)
        );

里面构造方法传入的也是各个精灵,精灵的创建中用到了cc.rect,看其中的一个。

//        根据rect区域去创建一个精灵,作为下面menuItemSprite显示的图片。
//        因为menuItem有Normal、Selected、Disabled三个状态,所以一个菜单项需要三张纹理图片
        var newGameNormal = new cc.Sprite(res.mm_mune_png, cc.rect(0, 0, 126, 33));

cc.rect(0, 0, 126, 33));是指定cc.Rect(x, y, width, height)。
这样的话就渲染出来了两个层,一个背景层,一个菜单层。在菜单切换的过程中还涉及到了 动作 ,函数的回调 、按顺序执行一组动作、 同时执行一组动作

//        定义动作
        var opacityAnim = cc.fadeIn(0.5, 255);
        var opacDim = cc.fadeIn(1, 0);

//        为动作加上easing效果,具体参考tests里面的示例
        var biggerEase = cc.scaleBy(0.7, 1.2, 1.2).easing(cc.easeSineOut());
        var easeMove = cc.moveBy(0.5, cc.p(328, 0)).easing(cc.easeSineOut());
        var rotateEase = cc.rotateBy(2.5, 90).easing(cc.easeExponentialOut());
        var bigger = cc.scaleTo(0.5, 1);

//        函数回调动作
        var onComplete = cc.callFunc(callback, target);
        var killflare = cc.callFunc(function () {
            this.getParent().removeChild(this,true);
        }, flare);

//        按顺序执行一组动作
        var seqAction = cc.sequence(opacityAnim, biggerEase, opacDim, killflare, onComplete);

//        同时执行一组动作
        var action = cc.spawn(seqAction, easeMove, rotateEase, bigger);
        flare.runAction(action);
    }

动作比较简单的。 就是精灵的旋转放大缩小等。
cc.callFunc是去执行一个函数,这里有this.getParent().removeChild方法,其实就是去移除创建的层。
cc.sequence是按顺序执行一组动作,传给 cc.spawn 是组合一组动作,然后精灵去执行 flare.runAction(action);
主要看一下GamePlayScene 游戏玩耍这个层,这个层里面涉及到了基础概念cc.spriteFrameCache缓存

 cc.spriteFrameCache.addSpriteFrames(res.gp_TextureOpaquePack_plist);

直接这样调用就可以了。这个层假如了两个层GPTouchLayer和GPBackgroundLayer
GPBackgroundLayer比较简单就是放了一张背景图片而已。主要的碰撞动作在GPTouchLayer中
这个里面涉及到比较多和重要的几个概念。scheduleUpdate和schedule
scheduleUpdate相当于是调用层的update方法

//    游戏时时刷新
    update:function (dt) {
        if (this._state == STATE_PLAYING) {

//            UI在这边更新
            this.updateUI();

//            敌人在这里面产生,以及界面上
            this.moveActiveUnit(dt);

//            碰撞检测
            this.checkIsCollide();

//            检测我们的飞船重生
            this.checkIsReborn();

//            这个部分被我直接干掉了。。。因为,重复代码,没什么内容
//            this._movingBackground(dt);
        }
    },

schedule是一致去执行一个方法这里一直在执行分数计数方法。

//    分数在这里面加
    scoreCounter:function () {
        if (this._state == STATE_PLAYING) {
            this._time++;
            this._levelManager.loadLevelResource(this._time);
        }
    },

存放分数信息的是cc.LabelBMFont

this._lbScore = new cc.LabelBMFont("Score: 0", res.sh_arial_14_fnt);
        this._lbScore.attr({
            anchorX: 1,
            anchorY: 0,
            x: GC.w - 5,
            y: GC.h - 30
        });

这个里面还有一个比较重要的就是碰撞检测
利用坐标是否落在区域去检测
看代码

//   碰撞坚持
    collide:function (a, b) {
        var ax = a.x;
        var ay = a.y;
        var bx = b.x;
        var by = b.y;
        if (Math.abs(ax - bx) > MAX_CONTAINT_WIDTH || Math.abs(ay - by) > MAX_CONTAINT_HEIGHT)
            return false;

        var aRect = a.collideRect(ax, ay);
        var bRect = b.collideRect(bx, by);
        return cc.rectIntersectsRect(aRect, bRect);
    },

这里面分了不同种类的精灵BulletSprite、EnemySprite、ExplosionSprite、ShipSprite、SparkEffectSprite看名字就可以看出来各个代表什么精灵,既然有碰撞检测那么坐标移动在哪里呢,其实就是在各个精灵中自己定义的action
看BulletSprite这个精灵吧,

update:function (dt) {

//        cc.log("这里。。。");
        var y = this.y;
        this.y = y - this.yVelocity * dt; //不断的移动坐标去达到移动的目的
        if (y < 0 || y > GC.h + 10 || this.HP <= 0) {
            this.destroy();
        }
    },

其中还有一些别的方法 死亡啊,新产生啊之类的,这个就是碰撞检测后的逻辑代码,不涉及到基础知识了,这里就过了。

真不容易写完了。这里贴出来试玩地址
http://112.126.90.18/airbarons/
算了还是放顶部吧
go home。

你可能感兴趣的:(Cocos2d-JS连载之打飞机游戏学习基础概念)