java实现飞机大战小游戏(源码+注释)

谁借莪1个温暖的怀抱¢ 2021-09-07 11:50 570阅读 0赞

整体的思路和博主其他博文java实现贪吃蛇小游戏(源码+注释)和java实现2048小游戏(源码+注释)是一样的,都是利用Frame创建窗体,利用Panel添加组件,提前规划好布局,调用鼠标和键盘监听,引用图片元素。
此处的思路在于不断的刷新敌机集合和子弹集合来实现动态效果。

文章目录

      • 一.工程文件
      • 二.Main.java
      • 三.GameFrame.java
      • 四.GamePanel.java
      • 五.FlyObject.java
      • 六.Hero.java
      • 七.Ep.java
      • 八.Fire.java
      • 九.App.java
      • 十.效果演示

一.工程文件

在这里插入图片描述

二.Main.java

主函数,实现类

  1. package ui;
  2. //主函数实现
  3. public class Main {
  4. public static void main(String[] args) {
  5. //创建窗体
  6. GameFrame frame = new GameFrame();
  7. //创建面板
  8. GamePanel panel = new GamePanel(frame);
  9. //调用开始游戏的方法启动游戏
  10. panel.action();
  11. //将面板加入到窗体中
  12. frame.add(panel);
  13. //设置窗体可见
  14. frame.setVisible(true);
  15. }
  16. }

三.GameFrame.java

窗体类,绘制窗体

  1. package ui;
  2. import javax.swing.*;
  3. //创建窗体
  4. public class GameFrame extends JFrame {
  5. //构造方法,初始化窗体属性
  6. public GameFrame(){
  7. //设置标题,来源于JFrame
  8. setTitle("飞机大战");
  9. //设置大小
  10. setSize(512,768);
  11. //设置居中
  12. setLocationRelativeTo(null);
  13. //设置窗体可见
  14. //setVisible(true);
  15. //不允许玩家修改界面大小
  16. setResizable(false);
  17. //设置默认的关闭选项
  18. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  19. }
  20. }

四.GamePanel.java

画布类,用于勾勒元素

  1. package ui;
  2. import javax.swing.*;
  3. import java.awt.*;
  4. import java.awt.event.KeyEvent;
  5. import java.awt.event.KeyListener;
  6. import java.awt.event.MouseAdapter;
  7. import java.awt.event.MouseEvent;
  8. import java.awt.image.BufferedImage;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. import java.util.Random;
  12. //自定义游戏面板(创建画布)
  13. public class GamePanel extends JPanel {
  14. //定义背景图
  15. BufferedImage bg;
  16. //构造游戏机
  17. Hero hero = new Hero();
  18. //敌机集合
  19. List<Ep> eps = new ArrayList<Ep>();
  20. //弹药集合
  21. List<Fire> fs = new ArrayList<Fire>();
  22. //定义分数
  23. int score;
  24. //设置游戏开关
  25. Boolean gameover=false;
  26. //设置火力
  27. int power = 1;
  28. //动作函数,描绘场景内飞行物的运动状态
  29. public void action(){
  30. //创建线程(基本模板)
  31. new Thread(){
  32. public void run(){
  33. //无线循环创建
  34. while (true){
  35. //判断如果游戏没有失败,则执行以下操作
  36. if(!gameover){
  37. //敌机进场
  38. epEnter();
  39. //调用敌机移动方法
  40. epMove();
  41. //发射子弹
  42. shoot();
  43. //子弹移动
  44. fireMove();
  45. //判断子弹是否击中敌机
  46. shootEp();
  47. //检测敌机是否撞到游戏机
  48. hit();
  49. }
  50. //每执行一次,线程休眠一会儿
  51. try {
  52. Thread.sleep(10);
  53. } catch (InterruptedException e) {
  54. e.printStackTrace();
  55. }
  56. //重绘界面
  57. repaint();
  58. }
  59. }
  60. }.start();//让线程开始运行
  61. }
  62. //每执行20次,释放一个敌机,创建计数器计数
  63. int index = 0;
  64. protected void epEnter(){
  65. index++;
  66. //创建敌机
  67. if(index>=20){
  68. //创建敌机
  69. Ep e = new Ep();
  70. //加入集合
  71. eps.add(e);
  72. //重置计数器
  73. index = 0;
  74. }
  75. }
  76. //让敌机移动
  77. protected void epMove(){
  78. //遍历敌机集合,依次移动
  79. for (int i = 0; i < eps.size(); i++) {
  80. //获取集合中敌机
  81. Ep e = eps.get(i);
  82. //调用敌机类中的移动方法
  83. e.move();
  84. }
  85. }
  86. //每执行20次,创建一颗子弹,创建计数器计数
  87. int findex = 0;
  88. protected void shoot(){
  89. findex++;
  90. if(findex>=20){
  91. //根据火力判断子弹行数
  92. //一排子弹
  93. if(power==1){
  94. //创建子弹
  95. Fire fire1 = new Fire(hero.x+45,hero.y,1);
  96. //将子弹存入子弹集合中
  97. fs.add(fire1);
  98. }
  99. //两排子弹
  100. else if(power==2){
  101. //创建子弹
  102. Fire fire1 = new Fire(hero.x+15,hero.y,0);
  103. //将子弹存入子弹集合中
  104. fs.add(fire1);
  105. //创建子弹
  106. Fire fire2 = new Fire(hero.x+75,hero.y,2);
  107. //将子弹存入子弹集合中
  108. fs.add(fire2);
  109. }
  110. //三排子弹
  111. else{
  112. //创建子弹
  113. Fire fire1 = new Fire(hero.x+15,hero.y,0);
  114. //将子弹存入子弹集合中
  115. fs.add(fire1);
  116. //创建子弹
  117. Fire fire2 = new Fire(hero.x+75,hero.y,2);
  118. //将子弹存入子弹集合中
  119. fs.add(fire2);
  120. //创建子弹
  121. Fire fire3 = new Fire(hero.x+45,hero.y-10,1);
  122. //将子弹存入子弹集合中
  123. fs.add(fire3);
  124. }
  125. //使计数器归0
  126. findex = 0;
  127. }
  128. }
  129. //让子弹移动
  130. protected void fireMove(){
  131. //遍历子弹集合
  132. for (int i = 0; i < fs.size(); i++) {
  133. //获取每一颗子弹位置
  134. Fire f = fs.get(i);
  135. //依次移动每一颗子弹
  136. f.move();
  137. }
  138. }
  139. //判断子弹是否击中敌机
  140. protected void shootEp(){
  141. //遍历所有子弹
  142. for (int i = 0; i < fs.size(); i++) {
  143. //获取每一颗子弹
  144. Fire f = fs.get(i);
  145. //判断一颗子弹是否击中敌机
  146. bang(f);
  147. }
  148. }
  149. //判断一颗子弹是否击中敌机
  150. protected void bang(Fire f){
  151. for (int i = 0; i < eps.size(); i++) {
  152. //取出每一张敌机
  153. Ep e = eps.get(i);
  154. //判断这个子弹是否击中敌机
  155. if(e.shootBy(f)&&e.type!=15){
  156. //判断游戏机机是否击中道具机
  157. if(e.type==12){
  158. //火力增加
  159. power++;
  160. //如果火力值大于三,增加血量
  161. if(power>3){
  162. //恢复血量
  163. if(hero.hp<3){
  164. hero.hp++;
  165. }
  166. //使游戏机血量不超过3
  167. power = 3;
  168. }
  169. }
  170. //如果敌机被子弹击中
  171. //敌机消失
  172. eps.remove(e);
  173. //删除子弹
  174. fs.remove(f);
  175. //增加分数
  176. score += 10;
  177. }
  178. }
  179. }
  180. //检测敌机是否撞到主机
  181. protected void hit() {
  182. for (int i = 0; i < eps.size(); i++) {
  183. //获取每一个敌机
  184. Ep e = eps.get(i);
  185. //调用敌机的方法判断
  186. if(e.shootBy(hero)){
  187. //删除敌机
  188. eps.remove(e);
  189. //主机血量减少
  190. hero.hp--;
  191. //火力恢复初始值
  192. power = 1;
  193. //分数增加
  194. score += 10;
  195. //当主机血量减少到0时游戏结束
  196. if(hero.hp==0){
  197. gameover = true;
  198. }
  199. }
  200. }
  201. }
  202. //构造函数
  203. public GamePanel(GameFrame frame){
  204. //设置背景
  205. bg = App.getImg("/img/bg2.jpg");
  206. //创建鼠标监听和鼠标适配器
  207. MouseAdapter adapter = new MouseAdapter() {
  208. //点击鼠标时会执行的代码
  209. @Override
  210. public void mouseClicked(MouseEvent e) {
  211. //游戏结束时候,点击屏幕时重新开始游戏
  212. if(gameover){
  213. //重新初始化主机
  214. hero = new Hero();
  215. //重置游戏开关
  216. gameover = false;
  217. //分数清0
  218. score = 0;
  219. //清空敌机集合
  220. eps.clear();
  221. //随机背景图
  222. Random random = new Random();
  223. int index = random.nextInt(5)+1;
  224. bg = App.getImg("/img/bg"+index+".jpg");
  225. //重新绘制
  226. repaint();
  227. }
  228. }
  229. //确定需要监听的事件,此处监听鼠标移动事件
  230. @Override
  231. public void mouseMoved(MouseEvent e) {
  232. //让游戏机的横纵坐标等于鼠标的移动坐标
  233. //获取鼠标的横纵坐标
  234. int mx = e.getX();
  235. int my = e.getY();
  236. //传递坐标
  237. if(!gameover){
  238. //使鼠标坐标正好位于图片中央
  239. hero.moveToMouse(mx-114/2,my-93/2);
  240. }
  241. //重新绘制界面
  242. repaint();
  243. }
  244. };
  245. //将适配器加入到监听器中
  246. addMouseListener(adapter);
  247. addMouseMotionListener(adapter);
  248. //使用键盘监听,创建键盘适配器
  249. KeyListener kd = new KeyListener() {
  250. @Override
  251. public void keyTyped(KeyEvent e) {
  252. }
  253. //当键盘被按下是触发
  254. @Override
  255. public void keyPressed(KeyEvent e) {
  256. int keyCode = e.getKeyCode();
  257. //上键
  258. if(keyCode == KeyEvent.VK_UP){
  259. hero.y-=10;
  260. }
  261. //下键
  262. else if(keyCode == KeyEvent.VK_DOWN){
  263. hero.y+=10;
  264. }
  265. //左键
  266. else if(keyCode == KeyEvent.VK_LEFT){
  267. hero.x-=10;
  268. }
  269. //右键
  270. else if(keyCode == KeyEvent.VK_RIGHT){
  271. hero.x+=10;
  272. }
  273. repaint();
  274. }
  275. @Override
  276. public void keyReleased(KeyEvent e) {
  277. }
  278. };
  279. //将适配器加入窗体的监听器中
  280. frame.addKeyListener(kd);
  281. }
  282. //画图方法
  283. @Override
  284. public void paint(Graphics g) {
  285. //调用父类中的一些渲染方法
  286. super.paint(g);
  287. //画背景
  288. g.drawImage(bg,0,0,null);
  289. //画敌机
  290. for (int i = 0; i < eps.size(); i++) {
  291. Ep ep = eps.get(i);
  292. g.drawImage(ep.img,ep.x,ep.y,null);
  293. }
  294. //画子弹
  295. for (int i = 0; i < fs.size(); i++) {
  296. Fire fire = fs.get(i);
  297. g.drawImage(fire.img,fire.x,fire.y,fire.w,fire.h,null);
  298. }
  299. //画分数
  300. g.setColor(Color.white);
  301. //设置字体型号,设置加粗,设置字体大小
  302. g.setFont(new Font("\u6977\u4F53",Font.BOLD,30));
  303. //显示分数
  304. g.drawString("分数:"+score,10,30);
  305. //画游戏机
  306. g.drawImage(hero.img,hero.x,hero.y,null);
  307. //画游戏机血量
  308. for (int i = 0; i < hero.hp; i++) {
  309. g.drawImage(hero.img,380+i*35,5,30,30,null);
  310. }
  311. //画游戏结束
  312. if(gameover){
  313. //设置字体颜色为红色
  314. g.setColor(Color.red);
  315. //设置字体型号,设置加粗,设置字体大小
  316. g.setFont(new Font("楷体",Font.BOLD,35));
  317. //显示字体
  318. g.drawString("GAMEOVER",170,300);
  319. //设置字体颜色为绿色
  320. g.setColor(Color.green);
  321. //设置字体型号,设置加粗,设置字体大小
  322. g.setFont(new Font("楷体",Font.BOLD,29));
  323. //显示字体
  324. g.drawString("yh提醒你点击屏幕任意位置重新开始",10,350);
  325. }
  326. //重新绘制界面
  327. repaint();
  328. }
  329. }

五.FlyObject.java

飞行物类,设定飞行物特性

  1. package ui;
  2. import java.awt.image.BufferedImage;
  3. //飞行物具有共同特点,故抽离成父类
  4. public class FlyObject {
  5. //均采用照片素材
  6. BufferedImage img;
  7. //位置的横坐标
  8. int x;
  9. //位置的纵坐标
  10. int y;
  11. //图片元素的宽度
  12. int w;
  13. //图片元素的高度
  14. int h;
  15. }

六.Hero.java

主机类,设定游戏时候操控的飞机属性

  1. package ui;
  2. import java.awt.image.BufferedImage;
  3. //游戏机
  4. public class Hero extends FlyObject{
  5. //设置游戏机血量
  6. int hp;
  7. //构造函数
  8. public Hero(){
  9. //获取游戏机元素
  10. img = App.getImg("/img/hero.png");
  11. //确认初始位置
  12. x = 200;
  13. y = 500;
  14. //获取游戏机图片元素的宽和高
  15. w = img.getWidth();
  16. h = img.getHeight();
  17. //设置初始血量为3
  18. hp = 3;
  19. }
  20. //根据传入参数移动相应位置
  21. public void moveToMouse(int mx,int my){
  22. x = mx;
  23. y = my;
  24. }
  25. }

七.Ep.java

敌机类

  1. package ui;
  2. import javax.swing.*;
  3. import java.awt.image.BufferedImage;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import java.util.Random;
  7. //敌机类
  8. public class Ep extends FlyObject{
  9. //设置敌机速度
  10. int sp;
  11. //设置敌机类型,不同的敌机类型有不同的属性
  12. int type;
  13. //构造函数
  14. public Ep(){
  15. //引入随机数随机调用敌机
  16. Random random = new Random();
  17. //调用[1,15]范围内的敌机
  18. int index = random.nextInt(15)+1;
  19. //保存敌机类型
  20. type = index;
  21. //如果序号小于10,则补充前导0,实质符合图片命名规律
  22. String path = "/img/ep" + (index<10?"0":"")+index+".png";
  23. //根据路径调用方法类函数获取图片io流
  24. img = App.getImg(path);
  25. //确定敌机位置
  26. //获取敌机照片元素宽度参数
  27. w = img.getWidth();
  28. //边界长减去照片宽度,防止照片越界
  29. x = random.nextInt(512-w);
  30. y = 0;
  31. //设置速度
  32. sp = 17-index;
  33. }
  34. //设置敌机移动方法
  35. public void move() {
  36. //如果敌机类型为5,则向左方倾斜移动
  37. if(type==5){
  38. x -= 5;
  39. y += sp;
  40. }
  41. //如果敌机类型为5,则向右方倾斜移动
  42. else if(type==6){
  43. x += 5;
  44. y += sp;
  45. }
  46. //如果是其他类型,则正常向下移动
  47. else {
  48. y+=sp;
  49. }
  50. }
  51. //判断敌机是否被子弹击中
  52. public boolean shootBy(Fire f) {
  53. //获取图片元素属性,确定相应的坐标算法,判断是否满足条件,满足则被击中
  54. Boolean hit = x <= f.x+f.w &&x>f.x-w&&y<=f.y+f.h&&y>f.y-h;
  55. return hit;
  56. }
  57. //判断敌机是否被玩家机击中
  58. public boolean shootBy(Hero f) {
  59. //获取图片元素属性,确定相应的坐标算法,判断是否满足条件,满足则被击中
  60. Boolean hit = x <= f.x+f.w &&x>f.x-w&&y<=f.y+f.h&&y>f.y-h;
  61. return hit;
  62. }
  63. }

八.Fire.java

子弹类

  1. package ui;
  2. public class Fire extends FlyObject{
  3. //子弹当前移动方向,0为左上角飞,1垂直飞,2右上角飞
  4. int dir;
  5. //构造方法,初始化子弹
  6. public Fire(int hx,int hy,int dir){
  7. //获取子弹的图片
  8. img = App.getImg("/img/fire.png");
  9. //确定图片的大小,此处把子弹大小缩小了4倍
  10. w = img.getWidth()/4;
  11. h = img.getHeight()/4;
  12. //根据构造函数传进来的参数设置子弹的位置以及子弹的方向
  13. x = hx;
  14. y = hy;
  15. this.dir=dir;
  16. }
  17. //子弹的移动方法
  18. public void move() {
  19. //左上角飞
  20. if(dir==0){
  21. x -= 1;
  22. y -= 10;
  23. }
  24. //垂直上飞
  25. else if(dir == 1){
  26. y -= 10;
  27. }
  28. //右上角飞
  29. else if(dir == 2){
  30. x += 1;
  31. y -= 10;
  32. }
  33. }
  34. }

九.App.java

方法类

  1. package ui;
  2. import javax.imageio.ImageIO;
  3. import javax.swing.*;
  4. import java.awt.image.BufferedImage;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. //处理图片的工具类
  8. //此处我定义了两种获取图片的方法,可以对照参考
  9. public class App {
  10. //static可以公用所有对象都共用该方法,并且可以不依赖对象实现
  11. public static BufferedImage getImg(String path){
  12. //用try方法捕获异常
  13. try {
  14. //io流,输送数据的管道
  15. BufferedImage img = ImageIO.read(App.class.getResource(path));
  16. return img;
  17. }
  18. //异常处理,打印异常
  19. catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. //没找到则返回空
  23. return null;
  24. }
  25. //此处与贪吃蛇小游戏的调用方法是一样的
  26. public static ImageIcon getImg2(String path){
  27. InputStream is;
  28. //从主类文件所在的路径寻找相应路径的图片
  29. is = App.class.getClassLoader().getResourceAsStream(path);
  30. //用try方法捕获异常
  31. try {
  32. return new ImageIcon(ImageIO.read(is));
  33. }
  34. //异常处理,打印异常
  35. catch (IOException e) {
  36. e.printStackTrace();
  37. }
  38. //没找到则返回空
  39. return null;
  40. }
  41. }

十.效果演示

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,570人围观)

还没有评论,来说两句吧...

相关阅读

    相关 飞机大战(微信游戏

    依旧是熟悉的期末作业,是微信小游戏官网的Demo来着,然后我边百度边对它做了一些改动 说起来好久没更新博客了......最近在用unity做游戏准备参加计算机设计大赛,花了好