Java Swing 经典小游戏《飞机大战》———— (三)敌机 敌机发射 与 种类生成

(一)效果展示

在这里插入图片描述
这里因为作者提前做好了前面的部分,左上角的得分暂且忽略

(二)代码实现

1.添加敌机

老套路,先加载敌机的造型

Utils.java

import java.awt.*;public class Utils {public static Image BgSky = Toolkit.getDefaultToolkit().getImage("src/Images/Bg_sky.png");public static Image[] Plane = {Toolkit.getDefaultToolkit().getImage("src/Images/Plane/1.png"),Toolkit.getDefaultToolkit().getImage("src/Images/Plane/2.png"),Toolkit.getDefaultToolkit().getImage("src/Images/Plane/3.png"),};public static Image[] Bullet = {Toolkit.getDefaultToolkit().getImage("src/Images/Bullet/1.png"),Toolkit.getDefaultToolkit().getImage("src/Images/Bullet/2.png")};public static Image[]  Enamy = {Toolkit.getDefaultToolkit().getImage("src/Images/Enamy/1.png"),Toolkit.getDefaultToolkit().getImage("src/Images/Enamy/2.png"),Toolkit.getDefaultToolkit().getImage("src/Images/Enamy/3.png")};
}

然后还记得上篇文章我们创建的Plan类吗?创建Enamy类继承它
跟子弹同样的道理,直接加上移动功能
这里为了不让敌机一排一排像板刷一样的出现,我们加上一个随机小范围调整速度让机群错落有致

Enamy.java

import java.awt.*;
import java.util.List;public class Enamy extends Plane{int hp;/*boss 飞机是横向移动的 所以区分 x,y speed 更加方便*/int speedx,speedy; /*跟子弹同理*/boolean delete = false;Enamy(int x,int y,int level) {this.rect = new Rectangle(x,y,64,64);this.img = Utils.Enamy[level];this.state = level + 10; // 标记是敌机的某种型号 + 10if (level == 0 || level == 1) {this.hp = (level + 1) * 2; // 根据等级确定血量this.speedy = (level + 1) * (3 + (int)Math.round(Math.random() * (1 - 0)) + 0);this.speedx = 0;} else {this.lstFire = -15;this.hp = 30;this.rect.setLocation(x,30);this.speedy = 0;this.speedx = 5;}}void paintSelf(Graphics g) {if (this.rect.y >= 700 || this.hp <= 0) this.delete = true; else {if (this.rect.x <= 20 || this.rect.x >= 450) this.speedx *= -1;this.rect.translate(this.speedx,this.speedy);}super.paintSelf(g);}
}

后来发现hpEnamyPlayer共有的应该放进Plane中大家可以自行修改一下。
敌机移动的代码就实现了,接下来还要实例化它,也就是基因有了,还要把他生出来。

GameWin.java

在游戏主循环中生成敌机
这里 小怪 经常出现,boss 极少出现且间隔超过15秒,所以我们给游戏加上一条时间线(实际上就是一个计数变量TimeStamp)
另外用Math.random()控制敌机种类的出现概率

import java.awt.*;import javax.swing.*;
import javax.swing.event.MouseInputAdapter;import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;public class GameWin extends JFrame {int width = 500;int height = 700;Image offScreenImage;Bg bg = new Bg();Player player = new Player(this);List<Bullet> bullets = new ArrayList<>();// 同子弹List<Enamy> enamies = new ArrayList<>();int TimeStamp = 0,lstBoss = -100,Bossnum = 0,lstFire = -15;void launch() {this.setVisible(true);this.setSize(width,height);this.setLocationRelativeTo(null);this.setTitle("飞机大战");setDefaultCloseOperation(EXIT_ON_CLOSE);this.addKeyListener(new MyKeyListener());this.addMouseListener(new MouseInputAdapter() {@Overridepublic void mouseClicked(java.awt.event.MouseEvent e) {// TODO Auto-generated method stubif (GameState == 0) {GameState = 1;}super.mouseClicked(e);}});;while (true) {TimeStamp ++; // 时间线// 个人习惯 用 {} 包裹一个整体 增强模块化逻辑{int num;if (enamies.size() < 10 && enamies.size() >= 3) {num = (int)(Math.random() * ((10 - enamies.size()) - 1)) + 1;} else if(enamies.size() < 3) {num = (int)(Math.random() * ((10 - enamies.size()) - 3)) + 3;} else {num = 0;}for(int i = 1;i <= num;i ++) {double rd = Math.random();int level;if (rd <= 0.7) level = 0;else if(rd <= 0.95 || (TimeStamp - lstBoss) <= 1500 || Bossnum != 0) level = 1;else {level = 2;lstBoss = TimeStamp;Bossnum ++;}this.enamies.add(new Enamy((int)(Math.random() * (450 - 20)) + 20,(int)(Math.random() * (25 - 0)) + 0,level));}}repaint();try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}class MyKeyListener implements KeyListener {@Overridepublic void keyPressed(KeyEvent e) {// TODO Auto-generated method stubif (e.getKeyCode() == KeyEvent.VK_LEFT) {player.movedir = -1;} else if(e.getKeyCode() == KeyEvent.VK_RIGHT) {player.movedir = 1;} else if(e.getKeyCode() == KeyEvent.VK_SPACE) {player.Fire();}}@Overridepublic void keyTyped(KeyEvent e) {// TODO Auto-generated method stub}@Overridepublic void keyReleased(KeyEvent e) {// TODO Auto-generated method stubif (e.getKeyCode() == KeyEvent.VK_LEFT) player.movedir = 0;else if(e.getKeyCode() == KeyEvent.VK_RIGHT) player.movedir = 0;}}@Overridepublic void paint(Graphics g) {// TODO Auto-generated method stuboffScreenImage = this.createImage(width,height);Graphics gImage = offScreenImage.getGraphics();bg.paintSelf(gImage);player.paintSelf(gImage);for(Iterator<Bullet> it = bullets.iterator();it.hasNext();) {Bullet bl = it.next();if (bl.delete) it.remove();else bl.paintSelf(gImage);}for(Iterator<Enamy> it = enamies.iterator();it.hasNext();) {Enamy en = it.next();if (en.delete) {if (en.state == 12) Bossnum --; // 控制最多有一个boss出现it.remove();}else en.paintSelf(gImage);}gImage.setFont(new Font("黑体",Font.BOLD,25));gImage.setColor(Color.red);g.drawImage(offScreenImage,0,0,null);}public static void main(String[] args) throws Exception {GameWin gameWin = new GameWin();gameWin.launch();}
}

敌机的问题就解决了

2.Boss升级

稍等,Boss还没有发射子弹,问题还没有结束
类似Player设置Fire,但是我们还需要将GameWin直接传参进去吗?
个人理解,这样做法不够好,占用更多的空间, 那么我们需要的其实只是bullets列表
这里炮弹的形态,以及等级可以自选

void Fire(List<Bullet> bl) {bl.add(new Bullet(rect.x,rect.y,1, 1));bl.add(new Bullet(rect.x + rect.width - 5,rect.y,1, 1));}

接下来就是发射了,许多小伙伴可能觉得按空格键和方向键不太方便,于是和Boss的子弹发射一起,我们做一个AutoFireE键启动

class MyKeyListener implements KeyListener {@Overridepublic void keyPressed(KeyEvent e) {// TODO Auto-generated method stubif (e.getKeyCode() == KeyEvent.VK_LEFT) {player.movedir = -1;} else if(e.getKeyCode() == KeyEvent.VK_RIGHT) {player.movedir = 1;} else if(e.getKeyCode() == KeyEvent.VK_SPACE) {player.Fire();} else if(e.getKeyCode() == KeyEvent.VK_E) {autofire = !autofire; // 设置自动开火模式}}@Overridepublic void keyTyped(KeyEvent e) {// TODO Auto-generated method stub}@Overridepublic void keyReleased(KeyEvent e) {// TODO Auto-generated method stubif (e.getKeyCode() == KeyEvent.VK_LEFT) player.movedir = 0;else if(e.getKeyCode() == KeyEvent.VK_RIGHT) player.movedir = 0;}}

然后在主循环中按TimeStamp与上一次lstFire的间隔频率发射,添加

{if (this.autofire && this.TimeStamp - this.lstFire >= 15){ // 150ms 一发this.lstFire = this.TimeStamp;player.Fire();}for(Enamy en: enamies) {if (en.state == 12 && this.TimeStamp - en.lstFire >= 15){en.lstFire = this.TimeStamp;en.Fire(bullets);}}
}

运行,发现Boss可以开火了,今天的任务也就完成了

  • 实现了添加敌机飞机
  • 实现了不同种类的敌机错落有致
  • 实现了Boss子弹发射
  • 实现了游戏时间线
  • 子弹碰撞检测 (由于结构变化,下期更新)

下期预告
子弹碰撞检测
游戏得分统计与玩家升级
游戏状态(输赢)
最后 撰写不易,做人,一定要善良; 点赞,好人,有好福
关注我,收藏 点赞 评论文章 更新速度更快哦


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部