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<Fighter> enemies = new ArrayList<>();
    ArrayList<Bullet> 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<Bullet> 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;
        }
    }

效果展示:

相关推荐
wuminyu9 小时前
Java锁机制之Java对象重量级锁源码剖析
java·linux·c语言·jvm·c++
艾利克斯冰9 小时前
Java设计模式-创建型设计模式
java
心之伊始9 小时前
MySQL EXPLAIN 执行计划实战:从 type、Extra 到慢 SQL 定位与优化
java·架构·源码分析·csdn
Java_2017_csdn9 小时前
ComplexKeysShardingAlgorithm 小结
java·大数据·算法
海梨花9 小时前
快手面试高频算法题
java·算法·面试
云烟成雨TD9 小时前
Spring AI 1.x 系列【37】RAG 知识库平台案例:知识库管理
java·人工智能·spring
KANGBboy9 小时前
java知识四(面向对象编程)
android·java·开发语言
tongluowan00710 小时前
ThreadLocal,InheritableThreadLocal,TransmittableThreadLocal详解
java·多线程·上下文
qq_25183645710 小时前
基于java Web 日化商超库存管理系统设计与实现
java·开发语言·前端
破土士V10 小时前
【Java基础语法10】继承、多态、抽象类接口、字符串与异常等
java·开发语言