欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > java >内容正文

java

老Java程序员花一天时间写了个飞机大战,很舒服!

发布时间:2023/12/10 java 51 豆豆
生活随笔 收集整理的这篇文章主要介绍了 老Java程序员花一天时间写了个飞机大战,很舒服! 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

老Java程序员花1天时间做了个飞机大战



热门专栏推荐

【1】Java小游戏(俄罗斯方块、飞机大战、植物大战僵尸等)
【2】JavaWeb项目实战(图书管理、在线考试、宿舍管理等)
【3】JavaScript精彩实例(飞机大战、贪吃蛇、验证码等)
【4】Java小白入门200例
【5】从零学Java、趣学Java
【6】Idea从零到精通

系列目录

1. Java俄罗斯方块
2. 老Java程序员花2天写了个连连看
3. 老Java程序员花一天时间写了个飞机大战
4. Java五子棋人机版
5. Java植物大战僵尸
6. Java消消乐(天天爱消除)
7. Java贪吃蛇小游戏
8. Java扫雷小游戏
9. Java坦克大战

引言:

前两天我发现CSDN上有两篇飞机大战的文章异常火爆,各种指标都很高(阅读、点赞、评论、收藏等),但都是python写的,竟然不是我大Java,说实话作为老java选手,我心里是有那么一些失落的,难道我大java打飞机不行?就算大java打飞机不行,那我用单身30年的打飞机手速,我肯定行(反正我的代码我做主,就是玩!),于是我决定一展伸手,用java写了一个飞机大战。我就问你们我打飞机行不行,我媳妇都说行,你们呢?欢迎我亲爱的大Java选手们 点赞+评论+收藏!给我冲、冲、冲。。。

代码实现

创建窗口

首先创建一个游戏窗体类GameFrame,继承至JFrame,用来显示在屏幕上(window的对象),每个游戏都有一个窗口,设置好窗口标题、尺寸、布局等就可以。

/** 游戏窗体类*/ public class GameFrame extends JFrame {public GameFrame() {setTitle("飞机大战");//设置标题setSize(526, 685);//设定尺寸setLayout(new BorderLayout());setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点击关闭按钮是关闭程序setLocationRelativeTo(null); //设置居中setResizable(false); //不允许修改界面大小} }

创建面板容器GamePanel继承至JPanel

package main;import java.awt.Graphics; import javax.swing.JFrame; import javax.swing.JPanel; /** 画布类*/ public class GamePanel extends JPanel{GamePanel gamePanel=this;private JFrame mainFrame=null;//构造里面初始化相关参数public GamePanel(JFrame frame){this.setLayout(null);mainFrame = frame;mainFrame.setVisible(true);}@Overridepublic void paint(Graphics g) {} }

再创建一个Main类,来启动这个窗口,用来启动。

package main; public class Main {//主类public static void main(String[] args) {GameFrame frame = new GameFrame();GamePanel panel = new GamePanel(frame);frame.add(panel);frame.setVisible(true);//设定显示} }

右键执行这个Main类,窗口建出来了
​​

创建菜单及菜单选项

创建菜单

private void initMenu(){// 创建菜单及菜单选项jmb = new JMenuBar();JMenu jm1 = new JMenu("游戏");jm1.setFont(new Font("微软雅黑", Font.BOLD, 15));// 设置菜单显示的字体JMenu jm2 = new JMenu("帮助");jm2.setFont(new Font("微软雅黑", Font.BOLD, 15));// 设置菜单显示的字体JMenuItem jmi1 = new JMenuItem("开始新游戏");JMenuItem jmi2 = new JMenuItem("退出");jmi1.setFont(new Font("微软雅黑", Font.BOLD, 15));jmi2.setFont(new Font("微软雅黑", Font.BOLD, 15));JMenuItem jmi3 = new JMenuItem("操作说明");jmi3.setFont(new Font("微软雅黑", Font.BOLD, 15));JMenuItem jmi4 = new JMenuItem("胜利条件");jmi4.setFont(new Font("微软雅黑", Font.BOLD, 15));jm1.add(jmi1);jm1.add(jmi2);jm2.add(jmi3);jm2.add(jmi4);jmb.add(jm1);jmb.add(jm2);mainFrame.setJMenuBar(jmb);// 菜单Bar放到JFrame上jmi1.addActionListener(this);jmi1.setActionCommand("Restart");jmi2.addActionListener(this);jmi2.setActionCommand("Exit");jmi3.addActionListener(this);jmi3.setActionCommand("help");jmi4.addActionListener(this);jmi4.setActionCommand("win"); }

实现ActionListener并重写方法actionPerformed

actionPerformed方法的实现

@Override public void actionPerformed(ActionEvent e) {String command = e.getActionCommand();UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("宋体", Font.ITALIC, 18)));UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("宋体", Font.ITALIC, 18)));if ("Exit".equals(command)) {Object[] options = { "确定", "取消" };int response = JOptionPane.showOptionDialog(this, "您确认要退出吗", "",JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,options, options[0]);if (response == 0) {System.exit(0);} }else if("Restart".equals(command)){if(startFlag){Object[] options = { "确定", "取消" };int response = JOptionPane.showOptionDialog(this, "游戏中,您确认要重新开始吗", "",JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,options, options[0]);if (response == 0) {//需要先结束游戏realGameEnd(1);restart();} }else{restart();}}else if("help".equals(command)){JOptionPane.showMessageDialog(null, "游戏开始后,要先动鼠标到飞机处,触发移动效果,然后飞机就会跟随鼠标移动!","提示!", JOptionPane.INFORMATION_MESSAGE);}else if("win".equals(command)){JOptionPane.showMessageDialog(null, "得分1000,获得胜利!","提示!", JOptionPane.INFORMATION_MESSAGE);} }

创建背景

在GamePanel类中重写paint方法,绘制背景图即可

//绘图方法 @Override public void paint(Graphics g) {gameHeight = this.getHeight();gameWidth = this.getWidth();//绘制背景g.drawImage((BufferedImage)imageMap.get("bg"), 0, -150, null); }

开启主线程

主线程,用来重绘页面,重绘全部交给主线程,主线程调用 repaint方法就行,要产生动画就要靠这个repaint。

//刷新线程,用来重新绘制页面 private class RefreshThread implements Runnable {@Overridepublic void run() {while (startFlag) {repaint();try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}} }

在GamePanel的构造里面启动这个主线程

有了这个主线程刷新,待会我们更新飞机的位置,飞机就会移动,不需要另外的代码去调用repaint方法了(这是我的做法,仅供参考)。

创建我方飞机

创建MyPlane类,属性有坐标x、y,宽高、图片、是否存活、是否可以移动等;方法主要有绘制、移动、射击等。

public class MyPlane {private int x = 0;private int y = 0;private int width = 0;private int height = 0;private BufferedImage image = null;private GamePanel panel=null;private HashMap imageMap=null;private boolean alive=true;private boolean canMove=false;private int key=1;private HashMap boomImageMap=null;private boolean hitFlag=false;//正在碰撞public MyPlane(int x,int y,int width,int height,GamePanel panel) {this.x=x;this.y=y;this.width=width;this.height=height;this.panel=panel;this.imageMap=panel.imageMap;this.image=(BufferedImage)imageMap.get("myplane1");this.boomImageMap=panel.mypalneBoomImageMap;}//绘制public void draw(Graphics g) {g.drawImage(image, x, y, width,height, null);} }

创建(这里只是创建好了飞机对象,需要绘制)

//创建自己飞机 private void initMyPlane() {myPlane = new MyPlane(200, 530, 132, 86, this); }

在paint方法中绘制

//绘图方法 @Override public void paint(Graphics g) {gameHeight = this.getHeight();gameWidth = this.getWidth();//绘制背景g.drawImage((BufferedImage)imageMap.get("bg"), 0, -150, null);//绘制飞机if(myPlane!=null){myPlane.draw(g);} }

鼠标事件监听

加入监听是为了让飞机跟随鼠标移动,我这里定的规则是第一次鼠标必须移动到飞机上,然后飞机才会跟随。

代码里面用一个属性canMove来控制,默认是false,只有鼠标第一次移入到飞机上时,这个属性设置为true,然后就可以跟随鼠标移动了。

//鼠标事件的创建 private void createMouseListener() {MouseAdapter mouseAdapter = new MouseAdapter() {@Overridepublic void mouseMoved(MouseEvent e) {int x = e.getX();int y = e.getY();if(myPlane==null) return ;//飞机第一次是不允许移动的,只有飞机的canMove为true才去跟随if(myPlane.isCanMove()){myPlane.move(x,y);return;}//判断鼠标的移入,如果移动到飞机上则canMove设置为trueif(myPlane.isPoint(x,y)){myPlane.setCanMove(true);}}};addMouseMotionListener(mouseAdapter);addMouseListener(mouseAdapter); }

来实现一下MyPlane的move方法,这里处理了边界,保证飞机不出界,同时保证鼠标在飞机的中间位置

//飞机跟随鼠标移动 public void move(int x,int y) {//判断范围,当横向移动在窗口范围内if(x-width/2>=0 && x<=panel.getWidth()-width/2){this.x=x-width/2;}//判断范围,当纵向移动在窗口范围内if(y-height/2>=0 && y<=panel.getHeight()-height/2){this.y=y-height/2;} }

创建子弹类

属性也就是坐标、宽高这些,给子弹加入移动方法

//移动 void move(){new Thread(new Runnable() {@Overridepublic void run() {while(alive){y-=speed;if(y<=0){clear();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}}).start(); }

飞机类加入射击方法,200毫秒创建一发子弹

//射击 void shoot() {new Thread(new Runnable() {@Overridepublic void run() {while(alive){//创建子弹createBullet();try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}}private void createBullet() {Bullet bullet = new Bullet(x+width/2-10, y, 20, 30, panel);panel.bulletList.add(bullet);new MusicPlayer("/music/shoot.wav").play();}}).start(); }

别忘记在paint方法里面绘制子弹出来

//绘制子弹 Bullet bullet=null; for (int i = 0; i < bulletList.size(); i++) {bullet = (Bullet)bulletList.get(i);bullet.draw(g); }

创建敌机

创建抽象类Plane

package main;import java.awt.Graphics;public abstract class Plane {public abstract void move();public abstract void draw(Graphics g);public abstract void boom();public abstract void clear();abstract int getX();abstract int getY();abstract int getWidth();abstract int getHeight(); }

创建敌机子类

有个特殊一点的地方: 因为有4种敌机,这里随机1、2、3、4这4个数字作为属性index,然后根据这个index来展现不同的飞机图片,当然也可以通过这个index来设置敌机不同的移动速度,但是我为了偷懒,就全部一样的移动速度,嘿嘿。
移动就是开启线程让y坐标增加,没什么好讲的,这里加一个飞机碰撞,就是当敌机跟我方飞机如何判断碰撞的问题。

撞机分析(敌机与我机的撞机)



从上面几个图可看出什么?因为图片是方形的,他们的4个顶点一定至少有一个在对方的范围内。再看一下从左边撞击的图:



从上图看到也是这样,其他两个方向的也是一样的道理,为了稳点我还加了一种情况:

1.判断敌机的4个点是否在飞机范围内,如果有则表示碰撞了。
2.如果1不成立,则反过来,判断我机的4个点是否在敌机的范围内,如果是表示碰撞了。

//判断飞机与子弹是否碰撞 private boolean isPoint(MyPlane plane) {/** * 两种情况* 1.需要判断敌机的4个点是否在飞机范围内,如果有则表示碰撞了* 2.如果步骤1不成立,则反过来,判断我机的4个点是否在敌机的范围内,如果是标志碰撞了*///方式1//左上角int x1 = x;int y1 = y;//右上角int x2 = x+width;int y2 = y;//右下角int x3 = x+width;int y3 = y+height;//左下角int x4 = x;int y4 = y+height;//只要有一个点在范围内,则判断为碰撞if(comparePointMyPlane(x1,y1,plane)|| comparePointMyPlane(x2,y2,plane)||comparePointMyPlane(x3,y3,plane)||comparePointMyPlane(x4,y4,plane) ){return true;}//方式1没成立则用方式2判断//方式2x1 = plane.getX();y1 = plane.getY();//右上角x2 = plane.getX()+plane.getWidth();y2 = plane.getY();//右下角x3 = plane.getX()+plane.getWidth();y3 =plane.getY()+plane.getHeight();//左下角x4 = plane.getX();y4 = plane.getY()+plane.getHeight();if(comparePoint(x1,y1)|| comparePoint(x2,y2)||comparePoint(x3,y3)||comparePoint(x4,y4) ){return true;}return false; } //用敌机的坐标来判断 private boolean comparePointMyPlane(int x,int y,MyPlane plane){//大于左上角,小于右下角的坐标则肯定在范围内if(x>plane.getX() && y >plane.getY()&& x<plane.getX()+plane.getWidth() && y <plane.getY()+plane.getHeight() ){return true;}return false; } //用我机的坐标来判断 private boolean comparePoint(int x,int y){//大于左上角,小于右下角的坐标则肯定在范围内if(x>this.x && y >this.y&& x<this.x+this.width && y <this.y+this.height){return true;}return false; }

测试一下效果

忘记说击中敌机的了(原理跟刚才差不多,代码直接放了)

//判断击中敌机 protected void hitEnemy() {EnemyPlane enemyPlane=null;List enemys = panel.enemyList;for (int i = 0; i < enemys.size(); i++) {try {enemyPlane = (EnemyPlane)enemys.get(i);} catch (Exception e) {}if(enemyPlane==null) continue;if(this.isPoint(enemyPlane)){panel.curCount+=enemyPlane.getCount();//删除当前子弹clear();//飞机爆炸enemyPlane.boom();if(panel.curCount>=panel.totalCount){panel.myPlane.setCanMove(false);panel.gameWin();}}} }//判断飞机与子弹是否碰撞 private boolean isPoint(EnemyPlane plane) {//因为子弹比飞机小,所以只需要判断子弹的4个点是否在飞机范围内,如果有则表示碰撞了//左上角int x1 = x;int y1 = y;//右上角int x2 = x+width;int y2 = y;//右下角int x3 = x+width;int y3 = y+height;//左下角int x4 = x;int y4 = y+height;//只要有一个点在范围内,则判断为碰撞if(comparePoint(x1,y1,plane)|| comparePoint(x2,y2,plane)||comparePoint(x3,y3,plane)||comparePoint(x4,y4,plane) ){return true;}return false; }private boolean comparePoint(int x,int y,EnemyPlane plane){//大于左上角,小于右下角的坐标则肯定在范围内if(x>plane.getX() && y >plane.getY()&& x<plane.getX()+plane.getWidth() && y <plane.getY()+plane.getHeight() ){return true;}return false; }

最后加上计分的、胜利、失败等提示就完成了!

看到这里的大佬,动动发财的小手 点赞 + 回复 + 收藏,能【 关注 】一波就更好了。

代码获取方式
订阅我的专栏《Java游戏大全》后,可以查看专栏内所有的文章,并且联系博主免费获取其中1-3份你心仪的源代码,专栏的文章都是上过csdn热榜的,值得信赖!专栏内目前有[13]篇实例,未来2个月内专栏会更新到15篇以上,一般2周一更,了解一下我的专栏。

热门专栏推荐

【1】Java小游戏(俄罗斯方块、飞机大战、植物大战僵尸等)
【2】JavaWeb项目实战(图书管理、在线考试、宿舍管理等)
【3】JavaScript精彩实例(飞机大战、贪吃蛇、验证码等)
【4】Java小白入门200例
【5】从零学Java、趣学Java
【6】Idea从零到精通

★ 更多精彩

1. Java俄罗斯方块
2. 老Java程序员花2天写了个连连看
3. 老Java程序员花一天时间写了个飞机大战
4. Java五子棋人机版
5. Java植物大战僵尸
6. Java消消乐(天天爱消除)
7. Java贪吃蛇小游戏
8. Java扫雷小游戏
9. Java坦克大战

总结

以上是生活随笔为你收集整理的老Java程序员花一天时间写了个飞机大战,很舒服!的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。