Egret社区
感谢 guoshaorui会员热心的为大家编写这套Egret入门教程,经过 guoshaorui 的同意转载这套教程。
该教程原始地址:点击访问
guoshaorui 的微博: http://www.weibo.com/guoshaorui



这里我们用Egret框架来实现一个打飞机的游戏(请忽略作者简陋的美术设计,游戏的诸多细节也存在缺失,不过基本可以体现出Egret的一些特性了)。
游戏界面截图:
fighter_01.jpg
下面是制作过程:
创建项目:
使用Egret命令行,创建一个新项目"Fighter":
  1. cd {workspace}
  2. egret create Fighter
复制代码

Egret会根据内置模板创建项目的基本目录结构,我们要编写的代码将放置在src下面,而素材将放置在resource下面。要运行和测试项目,需要打开launcher目录下的index.html,不过绝对不能双击打开,需要用一个HTTP服务器(您自配的或者Egret自带的)来运行。目前我们还未对项目进行修改,运行项目会看到默认的Egret界面。
准备素材:
千里之行,始于足下,写这个游戏我们先从整理素材做起。或许正规的流程应该是先策划,然后是UI设计,然后是反复论证...不过我们这里就省略了,我们的重点是学习Egret,做到这一点就足够了。本教程所用的素材是从网上搜集,如有侵权,请告知,将及时删除。
fighter_02.jpg
您可以从本教程配套的源码目录中,resource目录下找到这些素材。
将这些素材放到resource/assets目录下面,然后修改resource.json文件,将素材配置好,方便在代码中引用:
  1. {
  2. "resources":
  3.     [
  4.         {"name":"bgImage","type":"image","url":"assets/bg.jpg"},
  5.         {"name":"btnStart","type":"image","url":"assets/btn_start.png"},
  6.         {"name":"f1","type":"image","url":"assets/f1.png"},
  7.         {"name":"f2","type":"image","url":"assets/f2.png"},
  8.         {"name":"b1","type":"image","url":"assets/b1.png"},
  9.         {"name":"b2","type":"image","url":"assets/b2.png"}
  10.     ],

  11. "groups":
  12.     [
  13.         {"name":"preload","keys":"bgImage,btnStart,f1,f2,b1,b2"}
  14.     ]
  15. }
复制代码

开始按钮:
在GameApp.ts中,已经包含了模板预置的一些方法,主要是资源加载和loading显示,您可以选择在这个类中继续实现游戏逻辑,但为了便于展示,我们来创建一个新的类:GameContainer.ts,这样就可以将游戏的逻辑集中到自己的类中。
  1. module fighter
  2. {
  3.      /**
  4.      * 主游戏容器
  5.      */
  6.     export class GameContainer extends egret.DisplayObjectContainer
  7.     {
  8.         public constructor() {
  9.             super();
  10.             this.addEventListener(egret.Event.ADDED_TO_STAGE,this.onAddToStage,this);
  11.         }
  12.         /**初始化*/
  13.         private onAddToStage(event:egret.Event){
  14.             this.removeEventListener(egret.Event.ADDED_TO_STAGE,this.onAddToStage,this);
  15.             this.createGameScene();
  16.         }
  17.         /**创建游戏场景*/
  18.         private createGameScene():void{}
  19.     }
  20. }
复制代码
然后在GameApp.ts的onResourceLoadComplete方法中,创建GameContainer的实例:
  1. //游戏的主类开始实例化
  2. var gameContainer:fighter.GameContainer = new fighter.GameContainer();
  3. this.addChild(gameContainer);
  4. //下面的代码用于显示FPS等信息,可选
  5. egret.Profiler.getInstance().run();
复制代码

一般游戏都要从“开始按钮”开始,用户点击这个按钮,确定进入游戏。这里我们偷个懒,就用静态图片了,实际游戏中您可以根据设计方案,使用Egret的MovieClip实现一些动画等等。我们来修改GameContainer类:
  1. /**开始按钮*/
  2. private btnStart:egret.Bitmap;
  3. /**创建游戏场景*/
  4. private createGameScene():void{
  5.     this.stageW = this.stage.stageWidth;
  6.     this.stageH = this.stage.stageHeight;
  7.     //开始按钮
  8.     this.btnStart = fighter.createBitmapByName("btnStart");//开始按钮
  9.     this.btnStart.x = (this.stageW-this.btnStart.width)/2;//居中定位
  10.     this.btnStart.y = (this.stageH-this.btnStart.height)/2;//居中定位
  11.     this.btnStart.touchEnabled = true;//开启触碰
  12.     this.btnStart.addEventListener(egret.TouchEvent.TOUCH_TAP,this.gameStart,this);//点击按钮开始游戏
  13.     this.addChild(this.btnStart);
  14. }
复制代码

运行项目,如果看到了这个按钮,表明我们这一步成功了。
滚动背景:
通过观察同类型的游戏,当飞机"行动"的时候,实际上是将下面的背景反向运动,形成视觉差,让我们感觉是飞机在运动。但我们又不可能真的做一个无限高的背景图片,让背景滚动永无边际,实际做法是用“首尾相接”的技巧,通过在有限的屏幕内,计算需要显示的图片数量,让这些图片首尾相接来运动,这样就可以实现“无缝”的过渡,让背景看起来永远在滚动。
观察我们素材目录中的bg.jpg,是用Photoshop做了特殊处理,顶部和底部是可以连接起来的。
素材已经满足需求,然后来看代码中如何实现。我们来创建一个类:BgMap.ts,它的实现如下:
  1. module fighter
  2. {
  3.     /**
  4.      * 可滚动的底图
  5.      */
  6.     export class BgMap extends egret.DisplayObjectContainer
  7.     {
  8.         /**图片引用*/
  9.         private bmpArr:egret.Bitmap[];
  10.         /**图片数量*/
  11.         private rowCount:number;
  12.         /**stage宽*/
  13.         private stageW:number;
  14.         /**stage高*/
  15.         private stageH:number;
  16.         /**纹理本身的高度*/
  17.         private textureHeight:number;
  18.         /**控制滚动速度*/
  19.         private speed:number = 2;

  20.         public constructor() {
  21.             super();
  22.             this.addEventListener(egret.Event.ADDED_TO_STAGE,this.onAddToStage,this);
  23.         }
  24.         /**初始化*/
  25.         private onAddToStage(event:egret.Event){
  26.             this.removeEventListener(egret.Event.ADDED_TO_STAGE,this.onAddToStage,this);
  27.             this.stageW = this.stage.stageWidth;
  28.             this.stageH = this.stage.stageHeight;
  29.             var texture:egret.Texture = RES.getRes("bgImage");
  30.             this.textureHeight = texture.textureHeight;//保留原始纹理的高度,用于后续的计算
  31.             this.rowCount = Math.ceil(this.stageH/this.textureHeight)+1;//计算在当前屏幕中,需要的图片数量
  32.             this.bmpArr = [];
  33.             //创建这些图片,并设置y坐标,让它们连接起来
  34.             for(var i:number=0;i<this.rowCount;i++)
  35.             {
  36.                 var bgBmp:egret.Bitmap = fighter.createBitmapByName("bgImage");
  37.                 bgBmp.y = this.textureHeight*i-(this.textureHeight*this.rowCount-this.stageH);
  38.                 this.bmpArr.push(bgBmp);
  39.                 this.addChild(bgBmp);
  40.             }
  41.         }
  42.         /**开始滚动*/
  43.         public start():void {
  44.             this.removeEventListener(egret.Event.ENTER_FRAME,this.enterFrameHandler,this);
  45.             this.addEventListener(egret.Event.ENTER_FRAME,this.enterFrameHandler,this);
  46.         }
  47.         /**逐帧运动*/
  48.         private enterFrameHandler(event:egret.Event):void {
  49.             for(var i:number=0;i<this.rowCount;i++)
  50.             {
  51.                 var bgBmp:egret.Bitmap = this.bmpArr[i];
  52.                 bgBmp.y+=this.speed;
  53.                 //判断超出屏幕后,回到队首,这样来实现循环反复
  54.                 if(bgBmp.y > this.stageH) {
  55.                     bgBmp.y = this.bmpArr[0].y-this.textureHeight;
  56.                     this.bmpArr.pop();
  57.                     this.bmpArr.unshift(bgBmp);
  58.                 }
  59.             }
  60.         }
  61.         /**暂停滚动*/
  62.         public pause():void {
  63.             this.removeEventListener(egret.Event.ENTER_FRAME,this.enterFrameHandler,this);
  64.         }
  65.     }

  66. }
复制代码
然后修改GameContainer的createGameScene方法,将背景加入:
  1. this.bg = new fighter.BgMap();//创建可滚动的背景
  2. this.addChild(this.bg);
复制代码

然后在btnStart的事件侦听函数中,增加bg.start调用:
  1. /**游戏开始*/
  2. private gameStart():void{
  3.     this.bg.start();
  4. }
复制代码

运行项目,点击按钮,是否看到滚动的背景了?恭喜,这一步您也完成了。
创建飞机:
然后来分析一下如何创建飞机。飞机分两种:我的飞机和敌人的飞机,但基本属性是一致的,只是纹理和运动轨迹等方面有区别。我们来飞机创建一个类:Airplane.ts。
  1. module fighter
  2. {

  3.     export class Airplane extends egret.DisplayObjectContainer
  4.     {
  5.         /**飞机位图*/
  6.         private bmp:egret.Bitmap;
  7.         /**创建子弹的时间间隔*/
  8.         private fireDelay:number;
  9.         /**定时射*/
  10.         private fireTimer:egret.Timer;
  11.         /**飞机生命值*/
  12.         public blood:number = 10;

  13.         public constructor(texture:egret.Texture,fireDelay:number) {
  14.             super();
  15.             this.fireDelay = fireDelay;
  16.             this.bmp = new egret.Bitmap(texture);
  17.             this.addChild(this.bmp);
  18.             this.fireTimer = new egret.Timer(fireDelay);
  19.             this.fireTimer.addEventListener(egret.TimerEvent.TIMER,this.createBullet,this);
  20.         }
  21.         /**开火*/
  22.         public fire():void {
  23.             this.fireTimer.start();
  24.         }
  25.         /**停火*/
  26.         public stopFire():void {
  27.             this.fireTimer.stop();
  28.         }
  29.         /**创建子弹*/
  30.         private createBullet(evt:egret.TimerEvent):void {
  31.             this.dispatchEventWith("createBullet");
  32.         }
  33.     }
  34. }
复制代码
注意上面的代码中,外部调用开火方法,即.fire()后,飞机实例将根据Timer的间隔来不断创建子弹,但创建子弹以及控制子弹运动等具体工作并不由飞机实现,飞机只是派发事件给外面的容器,由容器统一管理。
另外分析游戏,通过游戏的不断运行,不断有新的飞机被创建,以及被子弹击中的飞机需删除。为了有效控制对象数量,我们需要为飞机类加入工厂方法和对象池机制,做法如下:
  1. private static cacheDict:Object = {};
  2. /**生产*/
  3. public static produce(textureName:string,fireDelay:number):fighter.Airplane
  4. {
  5.     if(fighter.Airplane.cacheDict[textureName]==null)
  6.         fighter.Airplane.cacheDict[textureName] = [];
  7.     var dict:fighter.Airplane[] = fighter.Airplane.cacheDict[textureName];
  8.     var theFighter:fighter.Airplane;
  9.     if(dict.length>0) {
  10.         theFighter = dict.pop();
  11.     } else {
  12.         theFighter = new fighter.Airplane(RES.getRes(textureName),fireDelay);
  13.     }
  14.     theFighter.blood = 10;
  15.     return theFighter;
  16. }
  17. /**回收*/
  18. public static reclaim(theFighter:fighter.Airplane,textureName:string):void
  19. {
  20.     if(fighter.Airplane.cacheDict[textureName]==null)
  21.         fighter.Airplane.cacheDict[textureName] = [];
  22.     var dict:fighter.Airplane[] = fighter.Airplane.cacheDict[textureName];
  23.     if(dict.indexOf(theFighter)==-1)
  24.         dict.push(theFighter);
  25. }
复制代码

需要创建飞机的时候,调用produce方法,不需要的飞机实例通过reclaim方法回收,这样可以保持对象数量在一个稳定的水平。
回到GameContainer类,来创建飞机实例:
  1. /**我的飞机*/
  2. private myFighter:fighter.Airplane;
  3. /**敌人的飞机*/
  4. private enemyFighters:fighter.Airplane[] = [];
  5. /**触发创建敌机的间隔*/
  6. private enemyFightersTimer:egret.Timer = new egret.Timer(1000);
复制代码
我的飞机就1个,所以是一个实例,但敌机是N个,我们创建数组来包含敌机;Timer用于控制创建敌机的时间间隔,间隔越小,敌机越多。
修改createGameScene方法,增加创建我的飞机的代码:
  1. //我的飞机
  2. this.myFighter = new fighter.Airplane(RES.getRes("f1"),100);
  3. this.myFighter.y = this.stageH-this.myFighter.height-50;
  4. this.addChild(this.myFighter);
复制代码

然后在gameStart方法中,增加创建敌机的机制:
  1. this.myFighter.fire();//我的飞机开火
  2. this.enemyFightersTimer.addEventListener(egret.TimerEvent.TIMER,this.createEnemyFighter,this);
  3. this.enemyFightersTimer.start();
复制代码

创建敌机的方法是createEnemyFighter:
  1. /**创建敌机*/
  2. private createEnemyFighter(evt:egret.TimerEvent):void{
  3.     var enemyFighter:fighter.Airplane = fighter.Airplane.produce("f2",1000);
  4.     enemyFighter.x = Math.random()*(this.stageW-enemyFighter.width);//随机坐标
  5.     enemyFighter.y = -enemyFighter.height-Math.random()*300;//随机坐标
  6.     enemyFighter.fire();
  7.     this.addChildAt(enemyFighter,this.numChildren-1);
  8.     this.enemyFighters.push(enemyFighter);
  9. }
复制代码

创建子弹:
首先创建子弹类Bullet.ts,同飞机类似,也采用对象池机制:
  1. module fighter
  2. {

  3.     export class Bullet extends egret.Bitmap
  4.     {
  5.         private static cacheDict:Object = {};
  6.         /**生产*/
  7.         public static produce(textureName:string):fighter.Bullet
  8.         {
  9.             if(fighter.Bullet.cacheDict[textureName]==null)
  10.                 fighter.Bullet.cacheDict[textureName] = [];
  11.             var dict:fighter.Bullet[] = fighter.Bullet.cacheDict[textureName];
  12.             var bullet:fighter.Bullet;
  13.             if(dict.length>0) {
  14.                 bullet = dict.pop();
  15.             } else {
  16.                 bullet = new fighter.Bullet(RES.getRes(textureName));
  17.             }
  18.             bullet.textureName = textureName;
  19.             return bullet;
  20.         }
  21.         /**回收*/
  22.         public static reclaim(bullet:fighter.Bullet,textureName:string):void
  23.         {
  24.             if(fighter.Bullet.cacheDict[textureName]==null)
  25.                 fighter.Bullet.cacheDict[textureName] = [];
  26.             var dict:fighter.Bullet[] = fighter.Bullet.cacheDict[textureName];
  27.             if(dict.indexOf(bullet)==-1)
  28.                 dict.push(bullet);
  29.         }

  30.         public textureName:string;

  31.         public constructor(texture:egret.Texture) {
  32.             super(texture);
  33.         }
  34.     }
  35. }
复制代码

子弹的创建是由侦听"createBullet"事件来驱动的,所以为我的飞机以及敌机都添加事件侦听:
  1. this.myFighter.addEventListener("createBullet",this.createBulletHandler,this);
  2. enemyFighter.addEventListener("createBullet",this.createBulletHandler,this);//在createEnemyFighter方法中修改
复制代码

创建的子弹分两种,即我的子弹和敌人的子弹,放在两个数组中:
  1. /**我的子弹*/
  2. private myBullets:fighter.Bullet[] = [];
  3. /**敌人的子弹*/
  4. private enemyBullets:fighter.Bullet[] = [];
复制代码

在方法createBulletHandler中实现创建子弹的过程:
  1. /**创建子弹(包括我的子弹和敌机的子弹)*/
  2. private createBulletHandler(evt:egret.Event):void{
  3.     var bullet:fighter.Bullet;
  4.     if(evt.target==this.myFighter) {
  5.         for(var i:number=0;i<2;i++) {
  6.             bullet = fighter.Bullet.produce("b1");
  7.             bullet.x = i==0?(this.myFighter.x+10):(this.myFighter.x+this.myFighter.width-22);
  8.             bullet.y = this.myFighter.y+30;
  9.             this.addChildAt(bullet,this.numChildren-1-this.enemyFighters.length);
  10.             this.myBullets.push(bullet);
  11.         }
  12.     } else {
  13.         var theFighter:fighter.Airplane = evt.target;
  14.         bullet = fighter.Bullet.produce("b2");
  15.         bullet.x = theFighter.x+28;
  16.         bullet.y = theFighter.y+10;
  17.         this.addChildAt(bullet,this.numChildren-1-this.enemyFighters.length);
  18.         this.enemyBullets.push(bullet);
  19.     }
  20. }
复制代码

让飞机和子弹运动起来:
到目前为止,飞机和子弹都可以创建了,但还无法运动,我们侦听enterFrame事件,集中处理对象的运动。在gameStart方法中增加:
  1. this.addEventListener(egret.Event.ENTER_FRAME,this.gameViewUpdate,this);
复制代码
gameViewUpdate方法,负责处理飞机和子弹的运动:
  1. /**游戏画面更新*/
  2. private gameViewUpdate(evt:egret.Event):void{
  3.     //为了防止FPS下降造成回收慢,生成快,进而导致DRAW数量失控,需要计算一个系数,当FPS下降的时候,让运动速度加快
  4.     var nowTime:number = egret.getTimer();
  5.     var fps:number = 1000/(nowTime-this._lastTime);
  6.     this._lastTime = nowTime;
  7.     var speedOffset:number = 60/fps;
  8.     //我的子弹运动
  9.     var i:number = 0;
  10.     var bullet:fighter.Bullet;
  11.     var myBulletsCount:number = this.myBullets.length;
  12.     var delArr:any[] = [];
  13.     for(;i<myBulletsCount;i++) {
  14.         bullet = this.myBullets[i];
  15.         bullet.y -= 12*speedOffset;
  16.         if(bullet.y<-bullet.height)
  17.             delArr.push(bullet);
  18.     }
  19.     for(i=0;i<delArr.length;i++) {//回收不显示的子弹
  20.         bullet = delArr[i];
  21.         this.removeChild(bullet);
  22.         fighter.Bullet.reclaim(bullet,"b1");
  23.         this.myBullets.splice(this.myBullets.indexOf(bullet),1);
  24.     }
  25.     delArr = [];
  26.     //敌人飞机运动
  27.     var theFighter:fighter.Airplane;
  28.     var enemyFighterCount:number = this.enemyFighters.length;
  29.     for(i=0;i<enemyFighterCount;i++) {
  30.         theFighter = this.enemyFighters[i];
  31.         theFighter.y += 4*speedOffset;
  32.         if(theFighter.y>this.stageH)
  33.             delArr.push(theFighter);
  34.     }
  35.     for(i=0;i<delArr.length;i++) {//回收不显示的飞机
  36.         theFighter = delArr[i];
  37.         this.removeChild(theFighter);
  38.         fighter.Airplane.reclaim(theFighter,"f2");
  39.         theFighter.removeEventListener("createBullet",this.createBulletHandler,this);
  40.         theFighter.stopFire();
  41.         this.enemyFighters.splice(this.enemyFighters.indexOf(theFighter),1);
  42.     }
  43.     delArr = [];
  44.     //敌人子弹运动
  45.     var enemyBulletsCount:number = this.enemyBullets.length;
  46.     for(i=0;i<enemyBulletsCount;i++) {
  47.         bullet = this.enemyBullets[i];
  48.         bullet.y += 8*speedOffset;
  49.         if(bullet.y>this.stageH)
  50.             delArr.push(bullet);
  51.     }
  52.     for(i=0;i<delArr.length;i++) {//回收不显示的子弹
  53.         bullet = delArr[i];
  54.         this.removeChild(bullet);
  55.         fighter.Bullet.reclaim(bullet,"b2");
  56.         this.enemyBullets.splice(this.enemyBullets.indexOf(bullet),1);
  57.     }
  58. }
复制代码

敌人的飞机的位置,是系统确定的,但我的飞机的位置,则是您手指的位置确定的,所以需要侦听touch事件,及时更新我的飞机的坐标。
  1. this.touchEnabled=true;
  2. this.addEventListener(egret.TouchEvent.TOUCH_MOVE,this.touchHandler,this);
  3. /**响应Touch*/
  4. private touchHandler(evt:egret.TouchEvent):void{
  5.     if(evt.type==egret.TouchEvent.TOUCH_MOVE)
  6.     {
  7.         var tx:number = evt.localX;
  8.         tx = Math.max(0,tx);
  9.         tx = Math.min(this.stageW-this.myFighter.width,tx);
  10.         this.myFighter.x = tx;
  11.     }
  12. }
复制代码
现在运行项目,可以看见满天飞的飞机和子弹了,是不是有点小激动了?但现在您的子弹对敌机是视而不见的,下面我们来增加碰撞检测的代码:
检测碰撞:
我们创建一个方法gameHitTest,来集中处理各个对象的碰撞。这个方法在gameViewUpdate中调用,以便实时地检测到碰撞:
  1. /**游戏碰撞检测*/
  2. private gameHitTest():void {
  3.     var i:number,j:number;
  4.     var bullet:fighter.Bullet;
  5.     var theFighter:fighter.Airplane;
  6.     var myBulletsCount:number = this.myBullets.length;
  7.     var enemyFighterCount:number = this.enemyFighters.length;
  8.     var enemyBulletsCount:number = this.enemyBullets.length;
  9.     //将需消失的子弹和飞机记录
  10.     var delBullets:fighter.Bullet[] = [];
  11.     var delFighters:fighter.Airplane[] = [];
  12.     //我的子弹可以消灭敌机
  13.     for(i=0;i<myBulletsCount;i++) {
  14.         bullet = this.myBullets[i];
  15.         for(j=0;j<enemyFighterCount;j++) {
  16.             theFighter = this.enemyFighters[j];
  17.             if(fighter.GameUtil.hitTest(theFighter,bullet)) {
  18.                 theFighter.blood -= 2;
  19.                 if(delBullets.indexOf(bullet)==-1)
  20.                     delBullets.push(bullet);
  21.                 if(theFighter.blood<=0 && delFighters.indexOf(theFighter)==-1)
  22.                     delFighters.push(theFighter);
  23.             }
  24.         }
  25.     }
  26.     //敌人的子弹可以减我血
  27.     for(i=0;i<enemyBulletsCount;i++) {
  28.         bullet = this.enemyBullets[i];
  29.         if(fighter.GameUtil.hitTest(this.myFighter,bullet)) {
  30.             this.myFighter.blood -= 1;
  31.             if(delBullets.indexOf(bullet)==-1)
  32.                 delBullets.push(bullet);
  33.         }
  34.     }
  35.     //敌机的撞击可以消灭我
  36.     for(i=0;i<enemyFighterCount;i++) {
  37.         theFighter = this.enemyFighters[i];
  38.         if(fighter.GameUtil.hitTest(this.myFighter,theFighter)) {
  39.             this.myFighter.blood -= 10;
  40.         }
  41.     }
  42.     if(this.myFighter.blood<=0) {
  43.         this.gameStop();
  44.     } else {
  45.         while(delBullets.length>0) {
  46.             bullet = delBullets.pop();
  47.             this.removeChild(bullet);
  48.             if(bullet.textureName=="b1")
  49.                 this.myBullets.splice(this.myBullets.indexOf(bullet),1);
  50.             else
  51.                 this.enemyBullets.splice(this.enemyBullets.indexOf(bullet),1);
  52.             fighter.Bullet.reclaim(bullet,bullet.textureName);
  53.         }
  54.         this.myScore += delFighters.length;
  55.         while(delFighters.length>0) {
  56.             theFighter = delFighters.pop();
  57.             theFighter.stopFire();
  58.             theFighter.removeEventListener("createBullet",this.createBulletHandler,this);
  59.             this.removeChild(theFighter);
  60.             this.enemyFighters.splice(this.enemyFighters.indexOf(theFighter),1);
  61.             fighter.Airplane.reclaim(theFighter,"f2");
  62.         }
  63.     }
  64. }
复制代码
在gameStop方法中,结束游戏:
  1. /**游戏结束*/
  2. private gameStop():void{
  3.     this.addChild(this.btnStart);
  4.     this.bg.pause();
  5.     this.removeEventListener(egret.Event.ENTER_FRAME,this.gameViewUpdate,this);
  6.     this.removeEventListener(egret.TouchEvent.TOUCH_MOVE,this.touchHandler,this);
  7.     this.myFighter.stopFire();
  8.     this.myFighter.removeEventListener("createBullet",this.createBulletHandler,this);
  9.     this.enemyFightersTimer.removeEventListener(egret.TimerEvent.TIMER,this.createEnemyFighter,this);
  10.     this.enemyFightersTimer.stop();
  11.     //清理子弹
  12.     var i:number = 0;
  13.     var bullet:fighter.Bullet;
  14.     while(this.myBullets.length>0) {
  15.         bullet = this.myBullets.pop();
  16.         this.removeChild(bullet);
  17.         fighter.Bullet.reclaim(bullet,"b1");
  18.     }
  19.     while(this.enemyBullets.length>0) {
  20.         bullet = this.enemyBullets.pop();
  21.         this.removeChild(bullet);
  22.         fighter.Bullet.reclaim(bullet,"b2");
  23.     }
  24.     //清理飞机
  25.     var theFighter:fighter.Airplane;
  26.     while(this.enemyFighters.length>0) {
  27.         theFighter = this.enemyFighters.pop();
  28.         theFighter.stopFire();
  29.         theFighter.removeEventListener("createBullet",this.createBulletHandler,this);
  30.         this.removeChild(theFighter);
  31.         fighter.Airplane.reclaim(theFighter,"f2");
  32.     }
  33. }
复制代码

这时运行项目,您就可以体验消灭敌机的乐趣了。
成绩展示:
现在我们增加成绩显示。新增类ScorePanel.ts,用文本显示成绩数值:
  1. module fighter
  2. {
  3.     /**
  4.      * 成绩显示
  5.      */
  6.     export class ScorePanel extends egret.Sprite
  7.     {
  8.         private txt:egret.TextField;

  9.         public constructor() {
  10.             super();
  11.             var g:egret.Graphics = this.graphics;
  12.             g.beginFill(0x000000,0.8);
  13.             g.drawRect(0,0,400,200);
  14.             g.endFill();
  15.             this.txt = new egret.TextField();
  16.             this.txt.width = 400;
  17.             this.txt.height = 200;
  18.             this.txt.textAlign = "center";
  19.             this.txt.textColor = 0xFFFFFF;
  20.             this.txt.size = 24;
  21.             this.txt.y = 60;
  22.             this.addChild(this.txt);
  23.         }

  24.         public showScore(value:number):void {
  25.             var msg:string = "您的成绩是:\n"+value+"\n再来一次吧";
  26.             this.txt.text = msg;
  27.         }
  28.     }
  29. }
复制代码
在gameStop方法中,增加显示成绩的代码:
  1. //显示成绩
  2. this.scorePanel.showScore(this.myScore);
  3. this.scorePanel.x = (this.stageW-this.scorePanel.width)/2;
  4. this.scorePanel.y = 100;
  5. this.addChild(this.scorePanel);
复制代码

发布和压缩:
如果只是测试,用build命令就可以,但如果发布就要用publish命令了,即:
  1. egret publish Fighter
复制代码

publish的好处是,将使用Google压缩工具,将Egret框架和您自身项目分散的js文件集中编译到一个game_min.js中,而且是做了压缩混淆的。这样一方面可以大大加快游戏启动速度,一方面让代码失去了可读性,有利于版权的保护。如果您的游戏要上线,记得使用这个命令哦。
WEBGL测试:
在Egret 1.0 RC2的版本中,已经增加了对WebGL的支持,所以我就改了一下打飞机的代码,感受一下性能方面的差异
请使用支持WebGL的浏览器观看,比如Chrome
想在您的项目中开启WebGL?
因为对WebGL的支持还处于测试阶段,所以WebGL是默认关闭的,您可以打开launcher/egret_loader.js,找到第78行
  1. //WebGL是egret的Beta特性,默认关闭
  2. if(false){// egret.WebGLUtils.checkCanUseWebGL()) {<font color="Red" size="5"><b><code style="box-sizing: border-box; font-family: Consolas,'Liberation Mono',Menlo,Courier,monospace; font-size: 12px; margin: 0px; border: 1px solid rgb(221, 221, 221); border-radius: 3px; padding: 0px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; background-color: rgb(248, 248, 248);"></code></b></font>
复制代码
改成 if(egret.WebGLUtils.checkCanUseWebGL()) { 即可 这样如果浏览器支持,就会自动开启WebGL渲染机制。


分享到 :
10 人收藏


------------------------------

77 个回复

倒序浏览
JustYY  登堂入室 | 2014-9-1 14:37:06
教程里有没写详细的地方,按步骤来有错误,容易误导新人
DEMO是没问题的
pplboy  斑竹 | 2014-8-5 17:30:37
我的妈呀,一打开WEBGL测试页吓了我一跳。。。
jimchen  登堂入室 | 2014-8-12 10:55:14
补测试页那是满屏的飞机吓尿了
所谓瓜瓜  登堂入室 | 2014-8-19 13:11:37
工厂方法和对象池机制是什么意思?上面那段关于produce和reclaim方法的代码完全看不懂,求指点@guoshaorui
所谓瓜瓜  登堂入室 | 2014-8-19 14:05:19
所谓瓜瓜 发表于 2014-8-19 13:11
工厂方法和对象池机制是什么意思?上面那段关于produce和reclaim方法的代码完全看不懂,求指点@guoshaor ...

另外貌似在更新我的飞机的坐标的时候,加入纵坐标
  1. var ty:number=evt.localY; ty = Math.max(0,ty);
  2.         ty = Math.min(this.stageW-this.myFighter.width,ty);
  3.         this.myFighter.y = ty;
复制代码

后,当鼠标移入canvas时飞机就不见了...
zhouhai  初学乍练 | 2014-8-29 18:02:58
表示真的吓尿了。
A闪  社区管理员 | 2014-8-29 18:11:59
zhouhai 发表于 2014-8-29 18:02
表示真的吓尿了。

为啥会吓尿了?
zhouhai  初学乍练 | 2014-8-29 18:35:53
A闪 发表于 2014-8-29 18:11
为啥会吓尿了?

好多好多灰机呀.
对了,闪闪。egret可以集成box2d吗
dxs111  初学乍练 | 2014-9-11 10:03:15
研究中!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|京网文[2014]0791-191号|京ICP证150115号|Egret社区 ( 京ICP备14025619号

Powered by Discuz! X3.2 © 2001-2016 Comsenz Inc.

返回顶部