Egret实战开发笔记,飞行射击游戏(五)

Stella981
• 阅读 465

今天是开发飞行射击游戏第五天,爆炸特效体系与NPC子弹弹幕。

简介

实现爆炸特效体系与NPC子弹弹幕。

飞机爆炸也是一个类,爆炸也是个数可变的,也需要特效管理者类。

实现效果

本来想路视频转GIF的,但是gif文件过大,超过5M又上传不了,而且压缩后失帧严重,仅截取了一部分转为gif, 请大家原谅。
Egret实战开发笔记,飞行射击游戏(五)

Egret实战开发笔记,飞行射击游戏(五)
Egret实战开发笔记,飞行射击游戏(五)
代码及过程

一、特效体系:爆炸

爆炸是一个动画帧,播放完就可以,因为比较简单, 用一个类+id 种类索引通过状态机的形式区分多种不同的爆炸。
创建特效类TX和特效管理者类TXManager类
1)TX类

    public id:number;        //代表种类
    public vis:boolean;        //被工厂管理的都需要vis
    public fi:number;        //代表动画帧播放第几帧
    public t:number;        //延时计时器 记录延时如:3次主循环出现,
    public m:number;        //状态
    public l:number;        //特效播放的总时长
    public tm:TXManager;    //上级指针

构造:

update(){}

动画延时播放:当create时,它可能不存在,如果有延时,比如延时5,visible可见性是false,但是vis是true。
如果t是0,就不用延时,一种是倒计时状态,没有出现。另一种是播放状态
m 0是倒计时 1是播放。

在构造最后

if(this.t > 0){
            //虽然在仓库,但是看不到
            //0 是倒计时, 1是播放
            this.visible = false;
            this.m = 0;
        }else{
            this.visible = true;
            this.m = 1 ;
        }

TX类

```c
class TX extends egret.Sprite{

    public im:egret.Bitmap;
    public id:number;        //代表种类
    public vis:boolean;        //被工厂管理的都需要vis
    public fi:number;        //代表动画帧播放第几帧
    public t:number;        //延时计时器 记录延时如:3次主循环出现,
    public m:number;        //状态
    public l:number;        //特效播放的总时长

    public tm:TXManager;    //上级指针

    public constructor(id:number,x:number, y:number,
        t:number,l:number,tm:TXManager) {
    
        super();
        this.id = id;
        this.x = x ;
        this.y = y;
        this.t = t;
        this.l = l;
        this.m = 0;
        this. fi = 0 ;
        this.vis = true;    //若它是false 工厂内对象消失
        this.tm = tm;
        
        this.im = Main.createBitmapByName("tx1_1_png");
        this.anchorOffsetX = this.im.width/2;
        this.anchorOffsetY = this.im.height/2;
        this.addChild(this.im);

        if(this.t > 0){
            //虽然在仓库,但是看不到
            //0 是倒计时, 1是播放
            this.visible = false;
            this.m = 0;
        }else{
            this.visible = true;
            this.m = 1 ;
        }


    }

    public update(){
         switch(this.m ){
             //
             case 0:
                 //倒计时
                 this.t-- ;
                 if(this.t <=0 ){
                     //出现爆炸
                     this.visible = true;
                     this.m = 1;        //播放
                 }
             break;
             case 1 :
                 //动画播放
                 this.fi++;
                 //
                 if(this.fi >= this.l){
                     this.vis =false;        //工厂里对象销毁
                 }else{                        //没有播放完,动画帧切换
                     //动画切换公式    fi从0开始,到9,
                     //10是动画的张数有几张动画就*几。 fi是动画帧,l是动画长度,
                     this.im.texture = RES.getRes("tx1_"+Math.floor(this.fi*10/this.l + 1)+"_png");
                 }
         }
    }
}

``

TXManager类

class TXManager extends egret.Sprite{
    
    public tm:Array<TX>;        //Array动态数组(容器),通过添加,添加对象,移除对象。
    public game:MainGame;

    public constructor(game:MainGame) {
        super();
        this.game = game;
        this.tm = new Array();
    }
    //每create一次就new一个
    public create(id:number,x:number,y:number,t:number,l:number,game:MainGame){
        //生成子弹
        let one = new TX(id,x,y,t,l,this);
        //添加到世界
        this.addChild(one);
        //放到仓库数组最后
        this.tm.push(one);
        
    }
    //更新所有子弹,找到每一颗子弹,每颗更新
    public update(){
        //整个仓库长度 ,利用循环可 以循环出所有子弹
        for(let i = 0 ; i < this.tm.length ; i++){
            //找到每颗子弹
            let one = this.tm[i];
            one.update();
            //若子弹太多,仓库会满,所以子弹需要移除
            //子弹出屏,vis == false。移除
            if(one.vis == false){
                //先从场景移除
                this.removeChild(one);
                //仓库移除 
                this.tm.splice(i ,1);
                //移除一个对象,长度-1
                i--;
            }
        }
    }
}

在Maingame中申请public tm:TXManager
构造:this.tm = tm; this.addChild(this.tm);
更新 this.tm.update();
在ZDManager类中

if(npc.hp <= 0 ){
    for(let k = 0 ; k < 10 ; k ++){                //-50 到 +50 
        this.game.tm.create( 0, npc.x + Math.random()*100 -50 ,
                        npc.y + Math.random()*100 -50 ,
                        Math.floor(Math.random() * 5), 10,this.game);
                    }
                    npc.vis = false;
                }

实现爆炸效果 Egret实战开发笔记,飞行射击游戏(五)

在上面的设置中,所有的NPC爆炸都是一个样子,如果出现不同的NPC爆炸怎么办?
有限状态机实现多样化都是在子类中,case。
如果对象和对象当中,想出现不同的现象,需要不同的代码。
需要给每一个子类,每一个特殊的NPC写相应的爆炸,

二.爆炸效果多样性
子类实现不同的dead()方法,
在NPC父类中 添加:public abstract dead();
实现每个NPC不同的死亡效果,在每个子类中都添加。
在NPC0,1中添加

public dead(){
        for(let k = 0 ; k < 10 ; k ++){            
            this.nm.game.tm.create( 0, this.x + Math.random()*100 - 50 ,
            this.y + Math.random()*100 - 50 ,
            Math.floor(Math.random() * 5), 10,this.nm.game);
        }
    }

之后再ZDManager中调用dead方法
Egret实战开发笔记,飞行射击游戏(五)

父类当中有抽象方法,但是实际执行每个子类的代码。

三.实现NPC的特殊弹幕
boss也是NPC,也得接受NPCManager的管理
创建BOSS0类

class BOSS0 extends NPC{

    public im:egret.Bitmap;
    public m:number;
    public t:number;

    public constructor(x:number,y:number,nm:NPCManager) {

        super(nm);
        this.x = x ;this.y = y;
        this.im = Main.createBitmapByName("boss50_png");
        this.im.anchorOffsetX = this.im.width/2;
        this.im.anchorOffsetY = this.im.height/2;
        this.addChild(this.im);

        this.m = this.t = 0;
        this.hp = 1000;
    }


    public update(){

    }
    public isHit(x:number,y:number):boolean{
        return false;
    }
    public dead(){

    }
}

添加BOSS更新方法

switch(this.m){
            //boss停的位置
            case 0:
                this.y+=10;
                if(this.y >= 150){
                    this.t = 20 ;
                    this.m = 1;
                }
            break;
            //等待状态
            case 1:
                this.t--;
                if(this.t <=0){
                    this.m = 10;
                    this.t = 0 ;
                }
            break;
            //发射子弹
            case 10:
                this.t++;
                //每隔3次主循环发射一颗
                if(this.t % 3 == 0 ){
                    for(let i = 0 ; i < 5 ; i++){
                        //5串子弹
                        //160+i*10 间隔10度发一颗
                    this.nm.game.nzm.create(1, this.x, this.y, 10 ,160+i*10,this.nm.game );
                    }
                }
                if(this.t >= 20){
                    this.t = 10;
                    this.m = 1;
                }
            break;
        }

①一串子弹
Egret实战开发笔记,飞行射击游戏(五)
Egret实战开发笔记,飞行射击游戏(五)

②实现环形的子弹
//发射子弹

case 10:
    this.t++;
    //每隔3次主循环发射一颗
    if(this.t % 3 == 0 ){
        for(let i = 0 ; i < 36 ; i++){
            //5穿子弹
            //160+i*10 间隔10度发一颗
        this.nm.game.nzm.create(1, this.x, this.y, 10 ,160+i*10,this.nm.game );
        }
    }
    if(this.t >= 20){
        this.t = Math.random()* 20 + 10;
        this.m = 1;
    }
break;

③漩涡形子弹
Egret实战开发笔记,飞行射击游戏(五)

case 11:
    this.t++;
    //随着t的++,发射子弹的角度不断变化
    this.nm.game.nzm.create(1, this.x, this.y, 10 ,180+this.t*10,this.nm.game );    //逆时针转
    this.nm.game.nzm.create(1, this.x, this.y, 10 ,180 - this.t*10,this.nm.game );    //顺时针转
    //子弹发射跟t有关联    间隔10度发一颗 
    if(this.t >= 36){
        this.t = Math.random()* 20 + 10;
        this.m = 1;        
                }
break;

④矩阵型子弹
Egret实战开发笔记,飞行射击游戏(五)
Egret实战开发笔记,飞行射击游戏(五)

case 12:
    this.t++;
    //每10次主循环中15,16,17,18,19发射子弹 5颗                                        
    if(this.t % 20 > 14){
    for(let i = 0 ; i < 5 ; i++){
    //间隔20度打一排,从130度开始打5颗,
    //每十次主循环是一波,this.t/10,前十次结果为10,11,12,13结果为1,取整*20就是每波的距离
            this.nm.game.nzm.create(1,this.x,this.y,10,Math.floor(this.t/20)*20 +130+i*5,this.nm.game );
            //135度左右打5颗,
        }
    }
    if(this.t >= 100){
        this.t = Math.random() * 20 + 10;
        this.m =1 ;
    }
            break;

⑤鞭形子弹
后发先至效果
Egret实战开发笔记,飞行射击游戏(五)

//鞭形子弹

case 13:
    this.t++;
    //速度随着时间增加,产生后发先至效果
    this.nm.game.nzm.create( 1, this.x - 50, this.y, 6 + this.t *2 ,190 - this.t,this.nm.game );
    this.nm.game.nzm.create( 1, this.x+50, this.y, 6 + this.t *2 ,170 + this.t,this.nm.game );
    if(this.t >= 10){
            this.t = Math.random() * 20 + 10;
            this.m =1 ;
    }
break;

⑥朝向性子弹
Egret实战开发笔记,飞行射击游戏(五)

NPC朝向玩家发射子弹并不是跟踪形子弹

朝向性子弹由子弹发射位置和玩家位置决定

过程:
NZDManager将角度参数设为缺省值 n?:numbe。 若不赋值,值为空。

原理:
Egret实战开发笔记,飞行射击游戏(五)

0角度向上顺时针转过n角度,求角度n = arctan( px-x /y -py)
代码为:
在NZDManager中
Egret实战开发笔记,飞行射击游戏(五)

//如果n角度是空的,就是没有赋值
    if(!n){
        n = Math.atan2(this.game.player.x - x,y - this.game.player.y);
        //注意:三角函数算出的都是弧度制,还需要弧度制转换角度制
        n = n * 180/Math.PI;

    }

BOSS0中

//朝向型子弹
            case 14 :
                this.t++;
                //打5团,每10次主循环打一组,
                if(this.t % 10 > 4){
                    this.nm.game.nzm.create( 1, this.x - 50, this.y, 15);
                }
                if(this.t >= 50){
                    this.t = Math.random() * 20 + 10;
                    this.m =1 ;
                }
                
            break;

实现随机类型子弹
在等待状态case1中 this.m = Math.floor(Math.random() * 5 ) + 10; //随机类型子弹

四.不规则图形的碰撞

白鹭引擎中有像素级的碰撞检测,但是在游戏中,子弹与BOSS的碰撞,假如一颗子弹100*100像素,一颗子弹就检测了10000次,50颗子弹就是50万次,游戏会非常卡。那么不开启像素级碰撞,不规则图形的碰撞怎么解决呢?Egret实战开发笔记,飞行射击游戏(五)
图片宽 146 高 166 各中心点 73,83像素
Egret实战开发笔记,飞行射击游戏(五)

if(Math.abs(x - this.x ) < 45 &&
        Math.abs(y - this.y )< 82){
            return true;
        }    

不规则图形拆成规则图形。
Egret实战开发笔记,飞行射击游戏(五)

//宽73,高36

if(Math.abs(x - this.x) < 73 &&
        Math.abs(y -(this.y + 44)) < 36){
            return true;
        }

要用矩形中心检测,横坐标在中心,纵坐标在选框中,实际比y多44,
Egret实战开发笔记,飞行射击游戏(五)
至此,第五天的开发笔记已经完成,学习需要坚持,坚持到最后一定会有结果,每天写下笔记来记录自己的学习内容, 以后有需要也可以查看,大家可以一起学习。

想要我一起学习的可以关注我的公众号 知言不尽 找到我,交流学习,获取图片素材和源代码。

点赞
收藏
评论区
推荐文章
Stella981 Stella981
2年前
Egret学习笔记 (Egret打飞机
运行起来,虽然主角飞机和敌机都在互相发射子弹,但是子弹打中了就和没打中效果是一样的。。这一章我们就来处理子弹和飞机的碰撞问题。我们所有的操作都是基于Main这个容器来做的。所以我就把这个处理放到Main里面,监听Main的_ENTER\_FRAME_事件this.addEventListener(egret.Event.ENTER_FRA
Wesley13 Wesley13
2年前
unity仿微信飞机大战项目
开发路线:1,游戏背景(连续播放)2,添加主角3,设置游戏主角的动画4,添加两种子弹并设置子弹的运动5,添加三种子弹设置子弹的自动生成和运动6,添加两种奖励物品设置奖励物品的自动生成和运动7,设置主角的控制
Wesley13 Wesley13
2年前
Unity 2D游戏开发教程之游戏精灵的开火状态
Unity2D游戏开发教程之游戏精灵的开火状态精灵的开火状态“开火”就是发射子弹的意思,在战争类型的电影或者电视剧中,主角们就爱这么说!本节打算为精灵添加发射子弹的能力。因为本游戏在后面会引入敌人,而精灵最好具备开火的能力,否则会被敌人轻易干掉!具体的实现方法是:(1)导入一个表
绣鸾 绣鸾
6个月前
视频特效制作After Effects 2024 for Mac
是一款由Adobe公司开发的专业的视频特效和动态图形设计软件,它可以帮助用户创建各种令人惊叹的视觉效果,例如粒子系统、合成特效、绿屏抠像等。该软件支持动画制作,包括关键帧动画、形状动画、运动跟踪等工具,可以创建复杂的动态动画和运动图形。在视频合成和编辑方面
流浪剑客 流浪剑客
6个月前
Macos 红巨星粒子插件:Red Giant Trapcode Suite Mac破解版
RedGiantTrapcodeSuiteMac是一款专业的视觉特效插件集合,适用于AdobeAfterEffects和PremierePro等视频软件。这款插件集能够提供丰富的视觉特效,如火花、烟雾、爆炸、飞溅等,以及3D粒子效果。它功能强大,允许用户创
绣鸾 绣鸾
6个月前
After Effects 2024(v24.0.2) for Mac
是一款由Adobe公司开发的专业的视频特效和动态图形设计软件,它可以帮助用户创建各种令人惊叹的视觉效果,例如粒子系统、合成特效、绿屏抠像等。该软件支持动画制作,包括关键帧动画、形状动画、运动跟踪等工具,可以创建复杂的动态动画和运动图形。在视频合成和编辑方面
何婆子 何婆子
3个月前
系统玩转OpenGL+AI,实现各种酷炫视频特效|网盘高清
系统玩转OpenGLAI,实现各种酷炫视频特效|网盘高清download》chaoxingit.com/2540/玩转OpenGL与AI:创造炫目视频特效的奇妙世界引言在当今数字时代,视频特效已成为吸引观众眼球的关键之一。而通过将OpenGL与人工智能(
韦康 韦康
1个月前
系统玩转OpenGL+AI,实现各种酷炫视频特效|网盘高清
系统玩转OpenGLAI,实现各种酷炫视频特效|网盘高清download》itzcw.com/9126/系统玩转OpenGLAI:实现各种酷炫视频特效在当今数字媒体时代,视频特效已经成为了制作视频内容中不可或缺的一部分。而结合OpenGL和人工智能(A
公孙晃 公孙晃
6个月前
Macos模拟飞行驾驶游戏:X-Plane 12 for Mac
《》是由LaminarResearch开发的飞行模拟游戏,于2022年9月17日登录Steam平台。在《XPlane12》中,玩家可以体验到完全重构的天气、云朵、树木、风、光影、季节等效果,为玩家提供了无与伦比的飞行模拟体验。此外,游戏还引入了新的引擎功能
流浪剑客 流浪剑客
6个月前
Mac专业的视频特效处理工具:After Effects 2024 for Mac中文版
是一款由Adobe公司开发的专业的视频特效和动态图形设计软件,它可以帮助用户创建各种令人惊叹的视觉效果,例如粒子系统、合成特效、绿屏抠像等。该软件支持动画制作,包括关键帧动画、形状动画、运动跟踪等工具,可以创建复杂的动态动画和运动图形。在视频合成和编辑方面