目录
一、最终实现后,效果如下。
(1)简单介绍本游戏项目(待完善)
(2)运行效果图(具体大家自己可以试)
初始运行情况。
手动更换背景图。
通过子弹攻击敌机,累计游戏分数。由变量"score"控制。
二、各个类的代码如下
(1)启动类(主类)
(2)自定义的"窗口"类(Frame)extends"JFrame"
(3)自定义"内容面板"类(Panel)extends"JPanel"
(4)"敌机"类(EnemyPlane)
(5)"本人飞机"类(Plane)
(6)"子弹"类(Fire)
一、最终实现后,效果如下。
(1)简单介绍本游戏项目(待完善)
- 只是学校的简单的实训项目,里面还可以进行很多内容可以补充或者完善。
- 里面有一个功能,博主实现的时候,"大"的敌机左右移动时,存在"摇摇晃晃"的情况。所以这里博主把这一部分的代码注释了,只让其"y的坐标值"变化。
- "小"敌机移动速度快,"大"敌机移动速度慢。
- 游戏界面的背景图,不会随着时间而进行改变(大家可以完善)。
- "自己飞机"的键盘移动操作不是很流畅,需要完善。
- "敌机"没有血量,自己操控的飞机没有血量,没有游戏结束"game over"的触发。
- 只有子弹击中敌机的判定。当子弹的坐标与敌机坐标满足条件,就触发方法,将敌机remove()。
- 子弹与敌机的创建都用到了线程的知识。并且通过"W"(上)、"S"(下)、"A"(左)、"D"(右)或者鼠标进行操控自己的飞机,进行攻击"x坐标指定范围内"、"y坐标为0"生成的敌机。
- 基本的技术用到了Java GUI(可视化)提供的类"Panel"、"JFrame",以及其下的方法实现。
- 当运行到一定的时间,该实训项目会出现报错地方(敌机生成线程、子弹生成线程)。
(2)运行效果图(具体大家自己可以试)
初始运行情况。
手动更换背景图。
通过子弹攻击敌机,累计游戏分数。由变量"score"控制。
二、各个类的代码如下
(1)启动类(主类)
package ui; /** * @Title: Main * @Author HeYouLong * @Package ui * @Date 2024/9/12 上午8:33 * @description: */ public class Main { public static void main(String[] args) { Frame frame = new Frame(); Panel panel = new Panel(frame); frame.add(panel); panel.begin(); panel.fireBegin(); frame.setVisible(true); } }
(2)自定义的"窗口"类(Frame)extends"JFrame"
- "JFrame"类是 Java Swing 图形用户界面工具包中的一个非常重要的类,它代表了一个窗口,是顶级容器之一。在 Swing 应用程序中,几乎所有的 GUI 组件都直接或间接地包含在一个"JFrame"窗口中。
- JFrame 提供了窗口的基本功能,如标题栏、最小化/最大化按钮、关闭按钮以及可调整大小的边框。但是,JFrame 本身不包含任何可视化组件(如按钮、文本框等);这些组件必须被添加到 JFrame 的内容面板(ContentPane)中,而内容面板默认是一个 "JPanel"。
package ui; import javax.swing.*; /** * @Title: Frame * @Author HeYouLong * @Package ui * @Date 2024/9/12 上午8:32 * @description: */ public class Frame extends JFrame { public Frame(){ setTitle("设计模式课程飞机大战"); setSize(512,768); setLocationRelativeTo(null);//居中 setResizable(false);//不准随便改变窗口大小 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口——>退出进程 } }
(3)自定义"内容面板"类(Panel)extends"JPanel"
- "JPanel" 类是 Java Swing 图形用户界面工具包中的一个非常重要的类,它继承自 JComponent 并实现了 Container 接口。JPanel 是一种轻量级的容器,可以用来组织和管理其他 GUI 组件(如按钮、文本框、标签等)。与 JFrame 不同的是,JPanel 本身不是一个顶级容器,它必须被添加到某个顶级容器(如 JFrame、JDialog 或 JApplet)中才能显示。
- 这个类的内容比较多,因为是"内容面板"嘛。
package ui; import javax.swing.*; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; /** * @Title: Panel * @Author HeYouLong * @Package ui * @Date 2024/9/12 上午8:38 * @description: */ public class Panel extends JPanel { private BufferedImage bg = GetImg.getImg("bg5.jpg"); private Plane plane; private List<EnemyPlane> enemyPlaneList = new ArrayList<>(); private List<Fire> fires = new ArrayList<>(); //敌机 public void begin() { new Thread() { public void run() { while (true) { CreateEp(); //创建敌机 todo MoveEp(); //敌机移动 todo hit(); //子弹碰撞 try { Thread.sleep(20); } catch (InterruptedException e) { throw new RuntimeException(e); } repaint();//画敌机 } } }.start(); } private static int score=0; //判断子弹与敌机是否碰撞 private void hit() { for (int i = 0; i < enemyPlaneList.size(); i++) { EnemyPlane enemyPlane = enemyPlaneList.get(i); for (int j = 0; j < fires.size(); j++) { Fire fire = fires.get(j); if(fire.x+fire.image.getWidth()/2>enemyPlane.getX() && fire.x<enemyPlane.getX()+enemyPlane.getImg().getWidth() && fire.y+fire.image.getHeight()/2>enemyPlane.getY() && fire.y<enemyPlane.getY()+enemyPlane.getImg().getHeight()){ enemyPlaneList.remove(i); fires.remove(j); score++; } } } } //子弹的线程 public void fireBegin() { new Thread() { public void run() { while (true) { //创建子弹 fireCreate(); //子弹移动 fireMove(); //休息线程 try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } //画子弹 repaint(); } } }.start(); } private void fireMove() { for (int i = 0; i < fires.size(); i++) { Fire fire = fires.get(i); fire.y=fire.y-10; } } private static int index = 0; private void fireCreate() { index++; if (index >= 12) { Fire fire = new Fire(plane); fires.add(fire); index = 0; } } private void MoveEp() { for (int i = 0; i < enemyPlaneList.size(); i++) { EnemyPlane enemyPlane = enemyPlaneList.get(i); enemyPlane.move(); } } private static int count = 0; private void CreateEp() { count++; if (count >= 12) { EnemyPlane enemyPlane = new EnemyPlane(); enemyPlaneList.add(enemyPlane); count = 0; } } public Panel(Frame frame) { plane = new Plane(); //鼠标操作 mouse(); //键盘操作 todo key(frame); } private void key(Frame frame) { KeyAdapter keyAdapter = new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { super.keyPressed(e); int i = e.getKeyCode();//获得按的键 if (i == KeyEvent.VK_A || i == KeyEvent.VK_LEFT) { plane.setX(plane.getX() - 30); if (plane.getX() <= 0) { plane.setX(0); } } else if (i == KeyEvent.VK_D || i == KeyEvent.VK_RIGHT) { plane.setX(plane.getX() + 30); if (plane.getX() >= 395) { plane.setX(395); } } else if (i == KeyEvent.VK_W || i == KeyEvent.VK_UP) { plane.setY(plane.getY() - 30); if (plane.getY() <= 0) { plane.setY(0); } } else if (i == KeyEvent.VK_S || i == KeyEvent.VK_DOWN) { plane.setY(plane.getY() + 30); if (plane.getY() >= 635) { plane.setY(635); } } repaint(); } }; frame.addKeyListener(keyAdapter); } private void mouse() { MouseAdapter mouseAdapter = new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { super.mouseMoved(e); plane.setX(e.getX() - plane.getImage().getWidth() / 2); plane.setY(e.getY() - plane.getImage().getHeight() / 2); //重新画 repaint(); } }; addMouseListener(mouseAdapter); addMouseMotionListener(mouseAdapter); } @Override public void paint(Graphics g) { super.paint(g); g.drawImage(bg, 0, 0, null); //本人飞机初始位置 g.drawImage(plane.getImage(), plane.getX(), plane.getY(), null); //画敌机 for (int i = 0; i < enemyPlaneList.size(); i++) { EnemyPlane enemyPlane = enemyPlaneList.get(i); g.drawImage(enemyPlane.getImg(), enemyPlane.getX(), enemyPlane.getY(), null); } //画子弹 for (int i = 0; i < fires.size(); i++) { Fire fire = fires.get(i); g.drawImage(fire.image,fire.x, fire.y,fire.image.getWidth()/2,fire.image.getHeight()/2, null); } //画分数 g.setColor(Color.white); Font font = new Font("黑体", Font.PLAIN, 22); g.setFont(font); g.drawString("当前游戏分数:"+score, 10, 20); } }
(4)"敌机"类(EnemyPlane)
(控制初始敌机生成的初始x、y坐标位置,控制出现边界,不同类型飞机移动速度等等)
package ui; import java.awt.image.BufferedImage; import java.util.Random; /** * @Title: EnemyPlane * @Author HeYouLong * @Package ui * @Date 2024/9/13 上午10:26 * @description: */ public class EnemyPlane { private int x; private int y; private int z; private BufferedImage img; public void move(){ final int MOVE_SPEED = 10; // 固定的移动速度 final int ENEMY_WIDTH = this.img.getWidth(); // 敌机图像的宽度 if(z<10){ y=y+14; return; }else{ /*Random random = new Random(); int i = random.nextInt(2); if(i==0){ x -= MOVE_SPEED; // 假设z也影响移动速度,这里简单地使用z的模和加数来调整 if (x <= 0) { x = 512-ENEMY_WIDTH; // 防止敌机移出屏幕左侧 } }else { // 向右移动 x += MOVE_SPEED; // 同上,调整移动速度 if (x >= 512-this.img.getWidth()) { x = 0; } }*/ y=y+8; } } public EnemyPlane() { Random random = new Random(); int i = random.nextInt(15)+1; String j = i<10?"0"+i:i+"";//文件名 String imgName = "ep"+j+".png"; this.img=GetImg.getImg(imgName);//随机图片 this.y=0; this.z=i; this.x=random.nextInt(512-this.img.getWidth()); } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public BufferedImage getImg() { return img; } public void setImg(BufferedImage img) { this.img = img; } public int getZ() { return z; } public void setZ(int z) { this.z = z; } }
(5)"本人飞机"类(Plane)
(设置初始位置、选定飞机图片、getter()、setter())
package ui; import java.awt.image.BufferedImage; /** * @Title: Plane * @Author HeYouLong * @Package ui * @Date 2024/9/12 上午9:05 * @description: */ public class Plane { private int x; private int y; private BufferedImage image; public Plane() { x=200; y=500; image = GetImg.getImg("hero.png"); } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } }
(6)"子弹"类(Fire)
(子弹的初始坐标与飞机的坐标要进行适配,也就是有联系。选定子弹图片)
package ui; import java.awt.image.BufferedImage; /** * @Title: Fire * @Author HeYouLong * @Package ui * @Date 2024/9/20 上午10:34 * @description: */ //子弹类 public class Fire { BufferedImage image; int x; int y; public Fire(Plane plane) { image = GetImg.getImg("fire.png"); //子弹的坐标 x=plane.getX()+plane.getImage().getWidth()/2-image.getWidth()/2/2; y=plane.getY()-image.getHeight()/2/2; } }