飞机大战>主角出场

话说上回游戏背景和音效成功的动起来了,接下来就是在背景上添加更多的模块来让游戏感体现出来,期待主角上场吧。。。

1.新建父类Role角色管理模块
class Role extends egret.DisplayObjectContainer{
    /**
     * 屏幕高宽
     */
    private mStageW:number=0;
    private mStageH:number=0;
    /**
     * 角色的血量
     */
    private mBlood:number=0;

    public constructor() {
        super();
        this.addEventListener(egret.Event.ADDED_TO_STAGE,this.createAirplane,this);
    }
    /**
     * 创建角色
     */
    public createAirplane():void{
        this.mStageW = this.stage.stageWidth;
        this.mStageH = this.stage.stageHeight;
    }
    /**
     * 检测敌机之间碰撞
     */
    public checkCollosion(x:number,y:number,obj:egret.DisplayObjectContainer):boolean{
        return false;
    }
    /**
     * 更新角色的血量
     */
    public updateBlood():void{

    }
    public setBlood(blood:number){
        if(blood<=0){
            blood = 0;
        }
        this.mBlood = blood;
    }
    public getBlood():number{
        return this.mBlood
    }
    /**
     * 获取屏幕高宽
     */
    public getStageW() : number{
        return this.mStageW;
    }

    public getStageH() : number{
        return this.mStageH;
    }
    /**
     * 获取角色位置
     */
    public getX():number{
        return 0;
    }
    public getY():number{
        return 0;
    }
    /**
     * 角色高宽
     */
    public getWidth():number{
        return 0;
    }
    public getHeight():number{
        return 0;
    }
    
}

角色基本信息,比如位置x,y;角色的高宽;血量等信息;每种角色的血量肯定都不一样的。

2.新建主角类Lead继承Role。
class Lead extends Role{
    /**
     * 角色
     */
    private mLead: egret.Bitmap; 
    /**
     * 血量,主角血量默认为100
     */
    private mBloodShape:egret.Shape;
    /**
     * 主角分数
     */
    private mScore:egret.TextField;
    private mScoreNumber:number=0;
    /**
     * 主角控制器
     */
    private mCollect: egret.Bitmap;
    private mTouchStatus: boolean = false;
    private mDistance:egret.Point = new egret.Point();
    /**
     * 尾部喷气
     */
    private mPlayblow : egret.Bitmap;
    private mPlayblowH : number;
    private mSpeedAngle : number;
    /**
     * 主角出场完成
     */
    private mTweenComplete: Function;
    private mLevel:Level;

    public constructor(tweenComplete:Function,level:Level) {
        super();
        this.mTweenComplete = tweenComplete;
        this.mLevel = level;
    }
    public createAirplane():void{
        super.createAirplane();
        this.setBlood(100);
        this.mSpeedAngle = 5;
        var stageW = this.getStageW();
        var stageH = this.getStageH();
        //主角
        this.mLead = ImageResUtils.createBitmapByName("lead_png");
        this.addChild(this.mLead);
        this.mLead.width = 68;
        this.mLead.height = 68;
        this.mLead.x = (stageW) / 2;
        this.mLead.y = stageH+this.mLead.height*2;
        //尾部火焰
        this.mPlayblow = ImageResUtils.createBitmapByName("playblow_png");
        this.addChildAt(this.mPlayblow,0);
        this.mPlayblowH = 65;
        this.mPlayblow.width = 68;
        this.mPlayblow.height =this.mPlayblowH;
        this.mPlayblow.x = this.mLead.x;
        this.mPlayblow.y = this.mLead.y + this.mLead.height / 1.5;
        var timer = new egret.Timer(5,0);
        timer.addEventListener(egret.TimerEvent.TIMER,this.startBlowAnimation,this);
        timer.start();
        //手指触摸位置控制器
        this.mCollect = ImageResUtils.createBitmapByName("playerunmatched_png");
        this.addChild(this.mCollect);
        this.mCollect.width = 68;
        this.mCollect.height = 68;
        this.mCollect.anchorOffsetX = this.mCollect.width / 2;
        this.mCollect.anchorOffsetY = this.mCollect.height / 2
        this.mCollect.x = this.mLead.x + this.mCollect.width/2;
        this.mCollect.y = this.mPlayblow.y+this.mPlayblow.height * 1.2;
        this.addEventListener(egret.Event.ENTER_FRAME,(evt:egret.Event)=>{
            this.mCollect.rotation+=10;
        },this);
        //进场动画
        var leadY = stageH - this.mLead.height * 3;
        egret.Tween.get(this.mLead).to({y:leadY},2500,egret.Ease.backInOut).call(this.mTweenComplete,this.mLevel);
        var playblowY = leadY + this.mLead.height / 1.5;
        egret.Tween.get(this.mPlayblow).to({y:playblowY},2500,egret.Ease.backInOut);
        egret.Tween.get(this.mCollect).to({y:playblowY+this.mPlayblow.height * 1.2},2500,egret.Ease.backInOut);
        //移动主角
        this.mCollect.touchEnabled = true;
        this.mCollect.addEventListener(egret.TouchEvent.TOUCH_BEGIN,this.mouseDown,this);
        this.mCollect.addEventListener(egret.TouchEvent.TOUCH_END,this.mouseUp,this);
        //初始化血量
        this.mBloodShape = new egret.Shape();
        this.addChild(this.mBloodShape);
        this.updateBlood();
        //分数
        this.mScore = new egret.TextField();
        this.mScore.textColor = 0xfffffff;
        this.mScore.width = 200;
        this.mScore.height = 100;
        this.mScore.textAlign = "center";
        this.mScore.x = 0;
        this.mScore.y = 30;
        this.addChild(this.mScore);
        this.updateScore();
    }
    /**
     * 刷新主角血量
     */
    public updateBlood():void{
        this.mBloodShape.graphics.clear();
        var blood:number = this.getBlood();
        if(blood==0){
            Level.GAME_STATE = Level.GAME_END;
        }
        if(blood>100){
            blood=100;
        }
        if(blood<=20){
            this.mBloodShape.graphics.beginFill(0xdc143c);
        }else{
            this.mBloodShape.graphics.beginFill(0xfffffff);
        }
        this.mBloodShape.graphics.drawRect(240,40,blood * 4,10);
        this.mBloodShape.graphics.endFill();
    }
    /**
     * 刷新分数
     */
    private updateScore():void{
        this.mScore.text = this.mScoreNumber.toString();
    }
    /**
     * 按下
     */
    private mouseDown(event: egret.TouchEvent) : void{
        this.mTouchStatus = true;
        this.mDistance.x = event.stageX - this.mLead.x;
        this.mDistance.y = event.stageY - this.mLead.y;
        this.stage.addEventListener(egret.TouchEvent.TOUCH_MOVE,this.mouseMove,this);
    };
    /**
     * 移动
     */
    private mouseMove(event: egret.TouchEvent) : void{
        if(this.mTouchStatus && this.getBlood()>0){
            var leadX:number = event.stageX - this.mDistance.x;
            var leadY:number = event.stageY - this.mDistance.y;
            leadX = leadX<0?0:leadX;
            leadX = leadX>this.getStageW()-this.mLead.width?this.getStageW()-this.mLead.width:leadX;
            leadY = leadY<0?0:leadY;
            leadY = leadY>this.getStageH()-this.mLead.height-this.mCollect.height?this.getStageH()-this.mLead.height-this.mCollect.height:leadY;
            this.mLead.x = leadX;
            this.mLead.y = leadY;
            //尾气火焰移动
            this.mPlayblow.x = this.mLead.x;
            this.mPlayblow.y = this.mLead.y + this.mLead.height / 1.5;
            //控制器
            this.mCollect.x = this.mLead.x + this.mCollect.width/2;
            this.mCollect.y = this.mPlayblow.y+this.mPlayblow.height * 1.2;
            this.mCollect.alpha = 0;
        }
    }
    /**
     * 松开
     */
    private mouseUp(event: egret.TouchEvent){
        this.mTouchStatus = false;
        this.stage.removeEventListener(egret.TouchEvent.TOUCH_MOVE,this.mouseMove,this);
        this.mCollect.alpha = 1;
    }
    /**
     * 火焰喷射动画
     */
    private startBlowAnimation() : void{
        this.mPlayblowH += this.mSpeedAngle;
        if(this.mPlayblowH>=75 || this.mPlayblowH<55){
            this.mSpeedAngle = -this.mSpeedAngle;
        }
        this.mPlayblow.height = this.mPlayblowH; 
    }
    public getX():number{
        return this.mLead.x;
    }
    public getY():number{
        return this.mLead.y;
    }
    public getWidth():number{
        return this.mLead.width;
    }
    public getHeight():number{
        return this.mLead.height;
    }
}

主角类的每一个地方我都写了注释,很明确,主要说一下主角组成部分和在容器体现出的地方:

  • 容器顶部多了一个数字和一个矩形条,分别代表的是游戏的分数以及血量。
    1.分数核心代码:
//分数
this.mScore = new egret.TextField();
this.mScore.textColor = 0xfffffff;
this.mScore.width = 200;
this.mScore.height = 100;
this.mScore.textAlign = "center";
this.mScore.x = 0;
this.mScore.y = 30;
this.addChild(this.mScore);
this.updateScore();
/**
* 刷新分数
 */
private updateScore():void{
    this.mScore.text = this.mScoreNumber.toString();
}

2.血量核心代码:

//设置血量为100
this.setBlood(100);
this.mBloodShape = new egret.Shape();
this.addChild(this.mBloodShape);
this.updateBlood();
/**
 * 刷新主角血量
 */
public updateBlood():void{
    this.mBloodShape.graphics.clear();
    var blood:number = this.getBlood();
    if(blood==0){
        Level.GAME_STATE = Level.GAME_END;
    }
    if(blood>100){
        blood=100;
    }
    if(blood<=20){
        this.mBloodShape.graphics.beginFill(0xdc143c);
    }else{
        this.mBloodShape.graphics.beginFill(0xfffffff);
    }
    this.mBloodShape.graphics.drawRect(240,40,blood * 4,10);
    this.mBloodShape.graphics.endFill();
}

这里出现了一个新的东西egret.Shape,可以做很多事情,类似于AndroidCanvas可以绘制各种各样的形状,做游戏必学的。传送门

  • 战机由三个部分组成:
    1.飞机主体
//主角
this.mLead = ImageResUtils.createBitmapByName("lead_png");
this.addChild(this.mLead);
this.mLead.width = 68;
this.mLead.height = 68;
this.mLead.x = (stageW) / 2;
this.mLead.y = stageH+this.mLead.height*2;

2.主体尾部喷气式火焰

//尾部火焰
this.mPlayblow = ImageResUtils.createBitmapByName("playblow_png");
this.addChildAt(this.mPlayblow,0);
this.mPlayblowH = 65;
this.mPlayblow.width = 68;
this.mPlayblow.height =this.mPlayblowH;
this.mPlayblow.x = this.mLead.x;
this.mPlayblow.y = this.mLead.y + this.mLead.heisght / 1.5;

注意:引擎是不支持GIF的,所以动效你要么帧动画,要么自己代码实现。我这里是把火焰图片高度做不停的改变来实现喷射式效果。利用Timer定时器

var timer = new egret.Timer(5,0);
timer.addEventListener(egret.TimerEvent.TIMER,this.startBlowAnimation,this);
timer.start();

意思是每隔5秒执行一次回调方法startBlowAnimation;在回调函数来不停的改变火焰高度

/**
 * 火焰喷射动画
*/
private startBlowAnimation() : void{
    this.mPlayblowH += this.mSpeedAngle;
    if(this.mPlayblowH>=75 || this.mPlayblowH<55){
        this.mSpeedAngle = -this.mSpeedAngle;
    }
    this.mPlayblow.height = this.mPlayblowH; 
}

3.看见主角战机下有一个在旋转的按钮没有?没错,那就是让玩家来触摸控制主角的地方,为什么需要这个设计呢?这就是体验问题,自己思考一下吧。

//手指触摸位置控制器
this.mCollect = ImageResUtils.createBitmapByName("playerunmatched_png");
this.addChild(this.mCollect);
this.mCollect.width = 68;
this.mCollect.height = 68;
this.mCollect.anchorOffsetX = this.mCollect.width / 2;
this.mCollect.anchorOffsetY = this.mCollect.height / 2
this.mCollect.x = this.mLead.x + this.mCollect.width/2;
this.mCollect.y = this.mPlayblow.y+this.mPlayblow.height * 1.2;
this.addEventListener(egret.Event.ENTER_FRAME,(evt:egret.Event)=>{
    this.mCollect.rotation+=10;
},this);

这里一定要写上anchorOffsetX ,anchorOffsetY 的参数赋值,这样才能让控制器围绕自己中心点旋转。
通过addEventListener监听帧动画来维持持续旋转。

  • 主角组合完成,怎么在容器中自由移动呢?
    1.通过按住旋转控制器来上下左右移动主角,
//移动主角
this.mCollect.touchEnabled = true;
this.mCollect.addEventListener(egret.TouchEvent.TOUCH_BEGIN,this.mouseDown,this);   
this.mCollect.addEventListener(egret.TouchEvent.TOUCH_END,this.mouseUp,this);

后面两个监听我能理解,手指按下和离开,第一行this.mCollect.touchEnabled = true;真不理解引擎为什么这样设计的,必须要给需要触摸事情的对象设置此参数,如果你不小心忽略了这一行,后面所有的触摸监听没有任何作用。

2.按下的时候除了记录位置,还需要添加监听整个屏幕的移动事件,这样才能知道手指移动的位置。

/**
* 按下
 */
private mouseDown(event: egret.TouchEvent) : void{
    this.mTouchStatus = true;
    this.mDistance.x = event.stageX - this.mLead.x;
    this.mDistance.y = event.stageY - this.mLead.y;
    this.stage.addEventListener(egret.TouchEvent.TOUCH_MOVE,this.mouseMove,this);
};

3.上面说了主角是多个部分组成,所以移动的时候组合部位需要跟着移动,不然就解体了,移动的时候做了边缘判断,保证随便怎么移动都只能在容器可见位置,并且隐藏控制器,表示主角已经受到玩家控制。

/**
     * 移动
     */
    private mouseMove(event: egret.TouchEvent) : void{
        if(this.mTouchStatus && this.getBlood()>0){
            var leadX:number = event.stageX - this.mDistance.x;
            var leadY:number = event.stageY - this.mDistance.y;
            leadX = leadX<0?0:leadX;
            leadX = leadX>this.getStageW()-this.mLead.width?this.getStageW()-this.mLead.width:leadX;
            leadY = leadY<0?0:leadY;
            leadY = leadY>this.getStageH()-this.mLead.height-this.mCollect.height?this.getStageH()-this.mLead.height-this.mCollect.height:leadY;
            this.mLead.x = leadX;
            this.mLead.y = leadY;
            //尾气火焰移动
            this.mPlayblow.x = this.mLead.x;
            this.mPlayblow.y = this.mLead.y + this.mLead.height / 1.5;
            //控制器
            this.mCollect.x = this.mLead.x + this.mCollect.width/2;
            this.mCollect.y = this.mPlayblow.y+this.mPlayblow.height * 1.2;
            this.mCollect.alpha = 0;
        }
    }

4.手指离开的时候,移除监听屏幕移动事件,显示控制器。

/**
     * 松开
     */
    private mouseUp(event: egret.TouchEvent){
        this.mTouchStatus = false;
        this.stage.removeEventListener(egret.TouchEvent.TOUCH_MOVE,this.mouseMove,this);
        this.mCollect.alpha = 1;
    }
3.回到我们的关卡类TheFirstPass修改startGame方法,添加主角类进场。
public startGame(){
        super.startGame();
        //加载背景
        this.mBgGame = new BackgroundGame();
        this.addChild(this.mBgGame);
         //主角进场
        var lead = new Lead(function(){
            this.mBgGame.startAnimationBg();
        },this);
        this.addChild(lead);
        //加载游戏音乐
        this.mBgSoundMusic = new BgSoundMusic();
        this.mBgSoundMusic.playMusic();
        //游戏结束提示
        this.mGameTextMessage = new egret.TextField();
        this.mGameTextMessage.textColor = 0xfffffff;
        this.mGameTextMessage.size = 40;
        this.mGameTextMessage.textAlign = "center"
        this.mGameTextMessage.x = 0;
        //重新开始
        this.mGameRestart = new egret.TextField();
        this.mGameRestart.textColor = 0xfffffff;
        this.mGameRestart.size = 40;
        this.mGameRestart.textAlign = egret.HorizontalAlign.CENTER;
        this.mGameRestart.verticalAlign = egret.VerticalAlign.MIDDLE;
        this.mGameRestart.backgroundColor = 0x000000; 
        this.mGameRestart.text = "再来一次"
        this.mGameRestart.touchEnabled = true;
        this.mGameRestart.stroke = 1;
        this.mGameRestart.strokeColor = 0xffffff;
    }

相比上一章修改了一下出场逻辑,等主角出场动画完成后再开始执行游戏背景动画,这样看来好像更符合逻辑。

主角已经完美出场了,是不是感觉并不是很难呢,无非就是多看官方文档和亲自试验,期待下一篇吧,给主角配上武器。

在线体验
如果是电脑端记得先把浏览器缩小后再打开地址,不然是横过来的。

源码地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容