今天是开发飞行射击游戏第五天,玩家多类型子弹及状态和关卡模式。

简介

实现玩家特殊子弹,激光,追踪导弹。
玩家多状态 下方飞出 正常游戏 胜利等待 胜利飞出 以及
玩家保护 和 关卡切换

实现效果

本来想录视频转GIF的,但是gif文件过大,超过5M又上传不了,而且压缩后失帧严重,仅截取了一部分转为gif, 请大家原谅。

一.激光

ZD类中
正常的子弹按照自己的轨迹运动,激光每次跟着玩家运动。激光的轨迹不是沿着自己的轨迹,而是在玩家移动的基础上有一个偏移坐标。即子弹跟着玩家移动。
需要一个属性:dx,dy

public dx:number;
public dy:number;           //玩家坐标基础上的偏移值
public static fi:number = 0 ;  //激光的动画帧

//激光类型

case 10://用动画帧构造图片this.im = Main.createBitmapByName("pzd4"+ZD.fi+"_png");//每发射一颗子弹 就加一张ZD.fi++;     if(ZD.fi >= 10) ZD.fi = 0;this.addChild(this.im);//每次主循环发射一颗,每颗间距离是80this.vy = -80;  //-80为向上this.vx = 0 ;this.dx = this.dy = 0 ;this.n = 0;this.gj = 10;break;

更新update():
//特殊的更新需要放在前面,进去直接更新,更新完return跳出结束更新

if(this.id == 10){//移动的是它和飞机之间的差值this.dx +=this.vx;this.dy +=this.vy;//偏移值:基础值+偏移//激光的坐标是在玩家坐标基础上加上改变值,移动的是改变值。这样就实现激光跟随玩家移动this.x = this.game.player.x + this.dx;this.y = this.game.player.y + this.dy;//出屏检测 if(this.y < -100 ){this.vis = false;}return;
}

什么叫偏移?
对激光来说移动的不是自己的坐标,而是移动和飞机之间的距离,是偏移值,而不是实际坐标

二.跟踪子弹的实现

实现效果

跟朝向型子弹不同。朝向子弹是NPC发的,发射时已经算好了子弹位置和玩家的位置,直接朝向玩家发射,子弹是直线型。

跟踪子弹是玩家发射的,找到NPC,根据NPC角度和坐标和自身的角度算出一个玩家该朝向的角度,而算出角度后,根据目前的角度和该朝向角度的差值进行移动。比如玩家是90度,实际要0度才能达到,并不是直接从90度变为0度,而是90.80,70,。。一个弧形,依次递减到需要朝向的角度。

1)NPC的选取:
需要选择屏幕当中的一个NPC,如果有就跟踪,如果没有就是竖直向上.

在NPCManager中

 //获取NPC
public getNPC():NPC{//仓库长度>0说明有NPC,如果没有跳出if(this.nm.length > 0 ){//有npc 随机取一个npc。let npc = this.nm[Math.floor(Math.random()* this.nm.length)]//判断npc是否在屏幕内,满足条件在屏幕内if(npc.x > 0 && npc.x < 480 && npc.y > 0 && npc.y < 800){return npc;}}//没找到 为空return null;
}

2)计算打到NPC的角度
3)更新角度的改变打到NPC

申请
public npc:NPC; //追踪的目标

//跟踪导弹case 20:this.im = Main.createBitmapByName("pzd1_3_png");this.npc = null;   break;

更新update()

//特殊的更新需要放在前面,进去直接更新,更新完return跳出结束更新

if(this.id == 20){let bn = 0 ;        //目标角度 向上if(this.npc == null){this.npc = this.game.nm.getNPC();}else{bn = Math.atan2(this.npc.x -this.x,this.y-this.npc.y);//这个角度是弧度制,转换成角度值bn = bn * 180/ Math.PI;}

//N角度限制在 -180°~180°

while(this.n <= -180)this.n += 360;
while(this.n > 180)this.n -= 360;
//若角度差值小于5度,两个角度变为等值
if(Math.abs(this.n - bn) < ZD.VN){this.n = bn;}else{//if(this.n < bn){if(this.n < bn - 180)this.n -= ZD.VN;elsethis.n += ZD.VN;}else{if(this.n > bn + 180)this.n += ZD.VN;else this.n -= ZD.VN;}
}
//sin用的是弧度制 n是角度制,所以 n* Math.PI / 180 转换为弧度制。
//重新计算速度与角度
this.vx = this.v * Math.sin(this.n * Math.PI / 180);
this.vy= -this.v * Math.cos(this.n * Math.PI / 180);
this.im.rotation = this.n;this.x +=this.vx;
this.y +=this.vy;

//出屏检测

if(this.x < -100 || this.x > 580 || this.y < -100 || this.y > 900){this.vis = false;
}
return;
}

注意:反三角函数求出的角度是 -180°180°,不是0°360°

将n角度从0°~360°转换为 -180°~ 180°

while(this.n <= -180)this.n += 360;
while(this.n > 180)this.n -=360;

在Player类中 fire方法
//追踪导弹

this.t++;
if(this.t >= 10){this.game.zm.create(20,this.x,this.y,15,135,this.game);this.game.zm.create(20,this.x,this.y,15,-135,this.game);this.game.zm.create(20,this.x,this.y,15,45,this.game);this.game.zm.create(20,this.x,this.y,15,-45,this.game);this.t = 0 ;
}

53

三.玩家多状态

0 下方飞出
1 正常游戏
10 胜利等待
11 胜利飞出
在Player的更新update方法中

switch(this.m){case 0 :this.y -=this.v;if(this.y <= 400){this.m =1;this.t = 0 ;}break;case 1 :this.fire();this.movePlayer();break;case 10:this.t++;if(this.t >= 20){this.t = 0;this.m = 11;}break;case 11:this.y -=this.vy;this.vy +=3;if(this.y < -200){//游戏胜利的切换}break;}

整合movePlayer方法
将update方法中这段代码变为movePlayer方法

public movePlayer(){if(this.isDown == true ){let a = this.ny - this.oy;let b = this.nx - this.ox;let c = Math.sqrt(a*a + b*b);if( c > this.v){this.vx = this.v*b/c;this.vy = this.v*a/c;this.ox += this.vx;this.oy += this.vy;}else{this.vx = b;this.vy = a;this.ox = this.nx;this.oy = this.ny;}//飞机跟着速度一起移动this.x +=this.vx ;this.y +=this.vy ;//边界检测if(this.x < 0)this.x = 0;else if(this.x > 480)this.x = 480;if(this.y < 0)this.y = 0;else if(this.y > 800)this.y = 800;}else{this.vx = 0;}if(this.vx < 0 ){//向左飞:if(this.fi > -2)this.fi --;}else if(this.vx > 0){if(this.fi < 2)this.fi++;}else{this.fi = 0 ;}this.resetFI();}

在update方法中增加状态机

四.玩家的死亡处理

玩家中增加public isHit(x:number , y:number):boolean{}

public isHit(x:number , y:number):boolean{// this.x this.y是圆心, 60是半径  勾股定理 ,进入圆算碰撞。//两点间距离公式。横坐标差的平方+纵坐标差的平方再开方 if(this.bhT > 0 ){if((this.x -x )*(this.x -x ) + (this.y -y )*(this.y - y ) < 60*60){return true;}return false;}if(this.m !=1)return false;if(Math.abs(this.x - x) < 20 && Math.abs(this.y -y )<20){//玩家死亡return true;  }return false;
}

增加

public dead(){for(let i = 0 ; i < 10 ; i++){       //环数let dn =Math.random()*Math.PI * 2;for(let j = 0 ; j < 15 ; j ++)         //每个环爆炸个数   {this.game.tm.create(0,this.x + (i+1)*30* Math.sin(dn+Math.PI*2*j/15),this.y + (i+1)*30* Math.cos(dn+Math.PI*2*j/15),i,Math.random() * 10 +5,this.game);}}this.x = 240;this.y = 1000;this.m = 0 ;this.t = 0;      }

五.增加玩家保护

申请public bh:egret.Bitmap; // 保护罩图片
public bhT:number; //保护罩倒计时 持续3秒
构造 this.bh.anchorOffsetX = this.bh.width/2;
this.bh.anchorOffsetY =this.bh.height/2;
this.addChild(this.bh);
this.bh.scaleX = this.bh.scaleY = 0.5;
this.bhT = 60; //60次主循环是3秒

更新;
//保护罩时间>0。减到0 消失,图片可见性为false

if(this.bhT > 0 ){this.bhT--;if(this.bhT <=0){this.bh.visible = false;}
}

在NZDManager类中的更新方法中修改

if(this.game.player.isHit(one.x , one.y) ==true ){one.vis = false;if(this.game.player.m == 1 && this.game.player.bhT <= 0 ){this.game.player.dead();} }

在玩家死亡方法最后添加
this.bhT = 60;
this.bh.visible = true;

六.玩家过关 与 关卡切换

BOSS0中添加死亡爆炸方法

public dead(){for(let i = 0 ; i < 10 ; i++){       //环数let dn =Math.random()*Math.PI * 2;for(let j = 0 ; j < 15 ; j ++)         //每个环爆炸个数   {this.nm.game.tm.create(0,this.x + (i+1)*30* Math.sin(dn+Math.PI*2*j/15),this.y + (i+1)*30* Math.cos(dn+Math.PI*2*j/15),i,Math.random() * 10 +5,this.nm.game);}} this.nm.game.player.win();}

在Player中添加win方法
//通过关卡

public win(){this.t = 0 ; this.m = 10;     //胜利 玩家飞出屏幕
}

2)关卡切换
Maingame中申请 public level:number; //判断当前关卡序号
构造:this.level = 0;

NPCManager中,不同的关卡生成不同的阵列。
对生成的switch进行状态机嵌套

在Maingame中添加
reset方法

public reset(level:number){this.level = level;this.player.reset();this.bg.reset();this.nm.reset();}

BG类中

public reset(){switch(this.game.level){case 0:for(let i = 0 ; i < 2; i ++){this.bg[i].texture = RES.getRes("bg11_jpg");}break;case 1:for(let i = 0 ; i < 2; i ++){this.bg[i].texture = RES.getRes("bg31_jpg");}break;}
}

NPCManager类中

//仓库中所有东西 移除

public reset(){//整个仓库长度 ,利用循环可以循环出所有子弹for(let i = 0 ; i < this.nm.length ; i++){//找到每颗子弹let one = this.nm[i];this.removeChild(one);this.nm.splice(i ,1);i--;}this.t =0;this.cID = 0;}

Player类中

public dead(){for(let i = 0 ; i < 10 ; i++){       //环数let dn =Math.random()*Math.PI * 2;for(let j = 0 ; j < 15 ; j ++)         //每个环爆炸个数   {this.game.tm.create(0,this.x + (i+1)*30* Math.sin(dn+Math.PI*2*j/15),this.y + (i+1)*30* Math.cos(dn+Math.PI*2*j/15),i,Math.random() * 10 +5,this.game);}}this.x = 240;this.y = 700;this.m = 0 ;this.t = 0;       this.bhT = 60;this.bh.visible = true;}
public reset(){this.isDown = false;this.x = 240;this.y = 1000;this.m = this.t = 0;this.bhT = 60;           //60次主循环是3秒}

至此,第五天的开发笔记已经完成,学习需要坚持,坚持到最后一定会有结果,每天写下笔记来记录自己的学习内容, 以后有需要也可以查看,大家可以一起学习。

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

Egret实战开发笔记,飞行射击游戏(六)相关推荐

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

    简介 Egret实战开发,记录每天的学习进度,欢迎和我一起学习交流~ 目录 简介 实现目标 一.实现子弹类 二.工厂设计模式 三.子弹管理类ZDManager 实现目标 今天是开发飞行射击游戏第二天, ...

  2. html5 画飞机,飞行射击游戏像素画开发教程:怎么画飞机?

    作者:Slynyrd 编译 | 三二 (转载请注明出处) 关注网易号:教你画像素画 想开发一个飞行射击游戏,怎么画飞机呢?飞行射击游戏大多有历史背景,我们选择德国在第一次世界大战中投入的飞机Fokke ...

  3. [air for ios] 三小时开发一个iOS飞行射击游戏

    [air for ios] 三小时开发一个iOS飞行射击游戏 http://www.badyoo.com/index.php/2012/07/04/158/index.html 2012-07-04 ...

  4. 手把手教你开发一款IOS飞行射击游戏(完)

    下面我们开始最后一篇文章,完成我们的飞行射击游戏. 有了前面的基础,相信现在你对Cocos2d的基本元素和编写技巧有了一定的了解,这回我们要接触的是场景切换,我们这回只列出部分代码,说明原理,给读者一 ...

  5. Android游戏开发之飞行射击类游戏原理实现(二十)

    Android游戏开发之飞行射击类游戏原理实现 雨松MOMO原创文章如转载,请注明:转载至我的独立域名博客雨松MOMO程序研究院,原文地址:http://www.xuanyusong.com/arch ...

  6. 用javascript实现的纵版飞行射击游戏—《天机》

    花了一个半月的时间用javascript完成了这款web版飞行射击游戏,游戏效果接近一般的客户端游戏,不过对机器的要求稍微高点点,主要是CPU,最好在1.5GHZ以上,不然可能会比较卡,支持IE.FF ...

  7. 飞行射击游戏的C++实现:一次课程作业

    目录 目录 程序简介 程序亮点 程序结构 逻辑层fsObjecth 自定义数据类型 fsPoint Class 一些枚举类型 异常类型 fsInvalidInitializePointValExcep ...

  8. Android开发笔记(八十六)几个特殊的类

    接口interface interface是一些功能的集合,但它只定义了对象必须实现的成员,而不包含成员的实现代码,成员的具体代码由实现接口的类提供.Android对接口的使用场景主要有三类:事件监听 ...

  9. 太空射击unity工程素材文件 飞机大战 飞行射击游戏源码(C#,Unity2019.2.4f1)素材+源码 最新写的,demo简单版本

    飞机大战素材 太空大战unity工程文件 飞行射击游戏源码(C#,Unity2019.2.4f1)素材+源码 最新写的,demo简单版本 希望能对初学者提供帮助,代码根据教材以及out了的代码更新了, ...

最新文章

  1. 当老板说要把公司当家时,他在说...
  2. OpenCV学习(19) 细化算法(7)
  3. 查看源代码不方便?我有利器
  4. Codeforces Beta Round #12 (Div 2 Only)【未完结】
  5. 怎么在idea中找实现类
  6. 洛谷P4463:calc(dp、拉格朗日插值)
  7. 为什么Facebook的API以一个循环作为开头?
  8. 大学计算机规划教材数据与计算,大学计算机应用基础教程高等院校计算机科学与技术规划教材.ppt...
  9. wechat-app-mall — 微信小程序商城,微信小程序微店
  10. linux 自动运行.out,linux系统定时自动重启springboot项目
  11. 松下抛却Jungle掌机研发项目
  12. vue.js的学习中的简单案例
  13. 吴恩达深度学习笔记(十一)—— dropout正则化
  14. LFS6.3安装全过程(一)
  15. 如何用微观数据分析玩家流失
  16. 《应用时间序列分析:R软件陪同》——1.4 本书的内容
  17. PHP课程设计《PHP网上购物系统的设计与实现》
  18. Ocr答题辅助神器 OcrAnswerer4.x,通过百度OCR识别手机文字,支持屏幕窗口截图和ADB安卓截图,支持四十个直播App,可保存题库...
  19. 高三数学辅导:不等式、推理与证明
  20. 深度学习头像定位头像分割

热门文章

  1. WIN电脑,固定到任务栏的快捷方式 实际存储在电脑的位置
  2. 字体设计的概念、意义与原则
  3. 推荐软件7 taskbar numberer,结果get了WIN相关的快捷键
  4. 最强 OSERDES IP核使用详解;FPGA 结构分析 —— IO 并串转换资源 OSERDES
  5. 魔百和M401A刷入Armbian系统EMMC开启wifi
  6. data类型的Url格式:把小数据直接嵌入到Url中
  7. 2011考研数学二第(9)题——求极限
  8. 四大“瓶颈”制约石油石化电子商务
  9. 欢迎hua@XUST加入XU安全组!
  10. 数字 IC 技能拓展(26)浅谈可编程逻辑器件