美文网首页程序员
飞机大战>主角出场

飞机大战>主角出场

作者: Galaxy北爱 | 来源:发表于2018-08-21 12:05 被阅读0次

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

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;
    }

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

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

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

源码地址

相关文章

  • 飞机大战>主角出场

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

  • 飞机大战-敌机出场

    目标 使用 定时器 添加敌机 设计 Enemy 类 01. 使用定时器添加敌机 游戏启动后,每隔 1 秒 会 出现...

  • Python打飞机(飞机大战)

    敌机和主机 发子弹 连发子弹 飞机大战(加音乐代码) 飞机大战代码: 精灵组 飞机大战敌机 飞机大战背景 上下左右...

  • 主角出场方式

    当前剧情简介:被纳入警察队伍,从而名正言顺完成父亲的遗愿 当前困境说明:周正父亲生前有过节的同事刘楠,阻挠周正加入...

  • 飞机大战

    飞机大战 导入模块的三种方式 import pygamefrom 模块名 import *(代表所有)from 模...

  • 飞机大战

    import pygame import time pygame.init() #1. 创建窗口 screen =...

  • 飞机大战

    这次呢,让我们重温一下儿时的乐趣,用Python做一个飞机大战的小游戏。接下来,让我们一起走进“飞机大战”。一.确...

  • 飞机大战

    飞机大战 导入模块的三种方式 import pygamefrom 模块名 import *(代表所有)from 模...

  • 飞机大战

    一款世界大战空战主题怀旧版经典飞机大战! 还记得小时候街机电玩城的打飞机游戏吗? 不久的未来,大量的外星飞船突袭地...

  • 飞机大战

网友评论

    本文标题:飞机大战>主角出场

    本文链接:https://www.haomeiwen.com/subject/rfediftx.html