java--飞机大战游戏

目前版本的飞机大战游戏由五个类构成,分别是:GameUI类(主界面窗体类),Fighter类(敌我飞机类),GameListener类(键盘监听类), MainThread类(主线程类),Bullet类(子弹类)

下面分为五个类讲解:

1.GameUI类

此类主要作用在于显示游戏的主界面,所以继承JFrame类。这里采用重写paint方法,使用缓冲图片将绘制内容一次性画到窗体上

java 复制代码
package 多线程游戏0321;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyListener;

/**
 * @author jinhuang
 * @date 2026/3/21  19:44
 * @description
 */
public class GameUI extends JFrame{



        // 全局监听器,方便线程访问
        GameListener listener = new GameListener();
        MainThread thread;

        public GameUI() {
            // 1. 窗体设置
            this.setTitle("飞机大战");
            this.setSize(500, 800);
            this.setLocationRelativeTo(null); // 居中
            this.setResizable(false);//禁止用户调整窗口大小
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


            // 2. 添加键盘监听器
            this.addKeyListener( listener);

            // 3. 启动游戏线程
            thread = new MainThread(this);
            thread.start();

            // 4. 显示窗体
            this.setVisible(true);
            /*Graphics g=this.getGraphics();
            g.drawRect(25,25,100,50);
            g.setColor(Color.GREEN);
            g.fillRect(25,25,thread.myFighter.hp,50);*/
        }

        // 重写paint方法,使用双缓冲解决闪烁
        @Override
        public void paint(Graphics g) {
            // 创建缓冲图片
            Image buffer = createImage(500, 800);
            Graphics gBuffer = buffer.getGraphics();

            // 在缓冲图片上绘制游戏内容
            thread.paintSelf(gBuffer);

            // 将缓冲图片一次性绘制到屏幕上
            g.drawImage(buffer, 0, 0, this);
        }

        public static void main(String[] args) {
            new GameUI();
        }
    }

2.Fighter类

此类主要用于引入飞机大战中的形象,以及战机的生成,移动,攻击,被攻击判定,死亡判定等

1\]这里飞机形象采用静态资源块加载.在类首次加载的时候自动执行 ```java package 多线程游戏0321; /** * @author jinhuang * @date 2026/3/21 19:44 * @description */ import java.awt.*; import java.util.ArrayList; import java.util.Random; public class Fighter { int x, y; int width = 60; int height = 60; int speed; boolean isEnemy; int hp = 100;//血量 boolean alive = true;//存活情况 // 敌机专用 static Random random = new Random(); static Image enemyImg; static Image heroImg; static { // 实际使用时请加载图片 enemyImg = Toolkit.getDefaultToolkit().getImage("D:\\练习图片\\image_436466818269426.png"); heroImg = Toolkit.getDefaultToolkit().getImage("D:\\练习图片\\image_051206973203939.png"); } public Fighter(int x, int y, boolean isEnemy) { this.x = x; this.y = y; this.isEnemy = isEnemy; this.speed = isEnemy ? 3 : 8; // 敌机慢,我机快 } public void draw(Graphics g) { Image currentImg = isEnemy ? enemyImg : heroImg; if (currentImg != null) { g.drawImage(currentImg, x, y, width, height, null); } else { g.setColor(isEnemy ? Color.GREEN : Color.BLUE); g.fillRect(x, y, width, height); g.setColor(Color.WHITE); g.drawString(isEnemy ? "敌机" : "我机", x+15, y+30); } } // 核心逻辑:移动 public void move(int direction) { if (isEnemy) { // 敌机逻辑:自动向下移动 y += speed; // 敌机出界销毁 if (y > 850) { alive = false; } } else { // 我方逻辑:键盘控制 if (direction == 1) y -= speed; // 上 if (direction == 2) y += speed; // 下 if (direction == 3) x -= speed; // 左 if (direction == 4) x += speed; // 右 // 边界穿越逻辑 if (x < -width) x = 500; // 从左边出去,右边回来 if (x > 500) x = -width; // 从右边出去,左边回来 if (y < -height) y = 800; // 从上边出去,下边回来 if (y > 800) y = -height; // 从下边出去,上边回来 } } // 开火 public Bullet fire() { if (isEnemy) { // 敌机随机开火逻辑通常在主线程控制,这里只负责生成 return new Bullet(x + width/2, y + height, true); } else { return new Bullet(x + width/2 - 5, y, false); } } // 碰撞检测(矩形碰撞) public boolean isCollide(Fighter f) { return (this.x < f.x + f.width && this.x + this.width > f.x && this.y < f.y + f.height && this.y + this.height > f.y); } public boolean isCollide(Bullet b) { return (this.x < b.x + b.width && this.x + this.width > b.x && this.y < b.y + b.height && this.y + this.height > b.y); } } ``` 3.GameListener类 事件监听类: 实现键盘监听器,用direction方向指示飞机走向,键盘按下时给direction相应的值,松开时direction重置为0 ```java package 多线程游戏0321; /** * @author jinhuang * @date 2026/3/21 19:47 * @description */ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; public class GameListener implements KeyListener { // 方向状态:1上, 2下, 3左, 4右 public int direction = 0; public boolean fire = false; @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); switch (key) { case KeyEvent.VK_W: direction = 1; break; case KeyEvent.VK_S: direction = 2; break; case KeyEvent.VK_A: direction = 3; break; case KeyEvent.VK_D: direction = 4; break; case KeyEvent.VK_SPACE: fire = true; break; } } @Override public void keyReleased(KeyEvent e) { int key = e.getKeyCode(); // 松开按键时重置方向,避免按键冲突 if (key == KeyEvent.VK_W || key == KeyEvent.VK_S || key == KeyEvent.VK_A || key == KeyEvent.VK_D) { direction = 0; } if (key == KeyEvent.VK_SPACE) { fire = false; } } @Override public void keyTyped(KeyEvent e) {} } ``` 4.MainThread类 \[1\]:创建己方战机对象,敌方战机数组,子弹数组,定义变量记录击杀数 \[2\]:无限循环的敌机生成数组,每隔1s生成一个 \[3\]: ```java package 多线程游戏0321; /** * @author jinhuang * @date 2026/3/21 19:47 * @description */ import java.awt.*; import java.util.ArrayList; import java.util.Iterator; public class MainThread extends Thread { GameUI mui; Fighter myFighter; ArrayList enemies = new ArrayList<>(); ArrayList bullets = new ArrayList<>(); // 敌机生成线程 Thread autoGenThread; //击杀数 int Kills=0; public MainThread(GameUI mui) { this.mui = mui; // 初始化我方战机 myFighter = new Fighter(220, 700, false); // 启动敌机自动生成线程 autoGenThread = new Thread(() -> { while (true) { try { Thread.sleep(1000); // 每秒生成一个敌机 int rx = (int)(Math.random() * 440); // 随机X坐标 enemies.add(new Fighter(rx, -60, true)); } catch (InterruptedException e) { e.printStackTrace(); } } }); autoGenThread.start(); } @Override public void run() { while (true) { // 1. 逻辑更新 updateLogic(); // 2. 重绘 mui.repaint(); // 3. 线程休眠 (控制帧率,防止闪烁) try { Thread.sleep(30); } catch (InterruptedException e) { e.printStackTrace(); } } } private void updateLogic() { // --- 我方逻辑 --- myFighter.move(mui.listener.direction); // 我方开火 (简单的连发冷却控制,这里简化为按下即发) if (mui.listener.fire && Math.random() > 0.8) { bullets.add(myFighter.fire()); } // --- 敌机逻辑 --- // 遍历敌机并移动 for (Fighter enemy : enemies) { enemy.move(0); // 敌机不需要方向参数,自动向下 // 敌机随机开火 if (Math.random() > 0.98) { bullets.add(enemy.fire()); } } // --- 子弹逻辑 --- for (Bullet b : bullets) { b.move(); } // --- 碰撞检测 --- // 1. 我方子弹 击中 敌机 Iterator bulletIt = bullets.iterator(); while (bulletIt.hasNext()) { Bullet b = bulletIt.next(); if (!b.isEnemyBullet) { // 仅检查我方子弹 for (Fighter e : enemies) { if (e.alive && b.alive && e.isCollide(b)) { e.hp -= 50; b.alive = false; // 子弹消失 if (e.hp <= 0) { e.alive = false; Kills++; } // 敌机死亡 } } } } // 2. 敌方子弹 击中 我机 for (Bullet b : bullets) { if (b.isEnemyBullet && b.alive && myFighter.isCollide(b)) { myFighter.hp -= 5; b.alive = false; if (myFighter.hp <= 0) { System.out.println("游戏结束!"); // 这里可以添加重启逻辑 myFighter.hp = 100; myFighter.x = 220; myFighter.y = 700; enemies.clear(); } } } // 3. 我机撞击敌机 for (Fighter e : enemies) { if (e.alive && myFighter.isCollide(e)) { myFighter.hp = 0; // 撞击即死 e.alive = false; } } // --- 清理尸体 (移除不存活的对象) --- // 使用 removeIf 简化清理逻辑 bullets.removeIf(b -> !b.alive); enemies.removeIf(e -> !e.alive); } // 供MUI调用的绘制方法 public void paintSelf(Graphics g) { // 绘制背景 g.setColor(Color.BLACK); g.fillRect(0, 0, 500, 800); // 绘制角色 myFighter.draw(g); for (Fighter e : enemies) e.draw(g); for (Bullet b : bullets) b.draw(g); // 绘制血量 g.drawRect(0,25,100,30); g.setColor(Color.GREEN); g.fillRect(0,25,myFighter.hp,30); //绘制得分 g.setFont(new Font("微软雅黑", Font.BOLD, 24)); //g.setColor(Color.WHITE); g.drawString("得分:"+Kills*10, 400, 25); } } ``` 5.Bullet类 边界检测等 ```java package 多线程游戏0321; /** * @author jinhuang * @date 2026/3/21 19:47 * @description */ import java.awt.*; public class Bullet { int x, y; int width = 10; int height = 20; int speed = 10; boolean isEnemyBullet; // true为敌方子弹,false为我方子弹 boolean alive = true; // 静态资源(示例用色块,实际开发请加载图片) static Image img; static { // 实际使用时请替换为: img = Toolkit.getDefaultToolkit().getImage("res/bullet.png"); img = null; } public Bullet(int x, int y, boolean isEnemyBullet) { this.x = x; this.y = y; this.isEnemyBullet = isEnemyBullet; } public void draw(Graphics g) { if (img != null) { g.drawImage(img, x, y, width, height, null); } else { g.setColor(isEnemyBullet ? Color.RED : Color.YELLOW); g.fillRect(x, y, width, height); } } public void move() { if (isEnemyBullet) { y += speed; // 敌方子弹向下 } else { y -= speed; // 我方子弹向上 } // 边界检测:出界即销毁 if (y < -50 || y > 900) { alive = false; } } ``` 效果展示: ![](https://i-blog.csdnimg.cn/direct/b44be4465eab478d870097dc48e60fb3.png)

相关推荐
BullSmall13 分钟前
Redis 双机部署 完整方案(两种架构,适配两台机器)
java·redis·架构
A-Jie-Y1 小时前
JAVA23种设计模式
java·设计模式
小同志001 小时前
IoC 详解
java·开发语言
BENA ceic1 小时前
Java进阶-在Ubuntu上部署SpringBoot应用
java·spring boot·ubuntu
asdfg12589632 小时前
以生活例子理解编程中的“多态”
java·生活·多态
wsjsf2 小时前
智能代码审查助手的搭建
java·学习·ai编程
xuhaoyu_cpp_java2 小时前
MyBatis学习(二)
java·经验分享·笔记·学习·mybatis
石榴树下的七彩鱼2 小时前
智能抠图 API 多语言接入实战:从零到上线的 Python / Java / PHP / JS 完整教程(附避坑指南)
java·python·php·智能抠图·api接入·石榴智能·shiliuai
无限进步_2 小时前
C++ 继承机制完全解析:从基础原理到菱形继承问题
java·开发语言·数据结构·c++·vscode·后端·算法