《飞机大战游戏》实训项目(Java GUI实现)(设计模式)(简易)

目录

一、最终实现后,效果如下。

(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)启动类(主类)
java 复制代码
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"。
java 复制代码
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)中才能显示。
  • 这个类的内容比较多,因为是"内容面板"嘛。
java 复制代码
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坐标位置,控制出现边界,不同类型飞机移动速度等等)

java 复制代码
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())

java 复制代码
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)

(子弹的初始坐标与飞机的坐标要进行适配,也就是有联系。选定子弹图片)

java 复制代码
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;
    }
}
相关推荐
X² 编程说19 分钟前
14.面试算法-字符串常见算法题(三)
java·数据结构·后端·算法·面试
请不要叫我菜鸡1 小时前
Go语言基础学习02-命令源码文件;库源码文件;类型推断;变量重声明
linux·后端·golang·类型推断·短变量·变量重声明·库源码文件
AskHarries1 小时前
Spring Boot集成Akka Cluster快速入门Demo
java·spring boot·后端·akka
少喝冰美式1 小时前
【大模型教程】如何在Spring Boot中无缝集成LangChain4j,玩转AI大模型!
人工智能·spring boot·后端·langchain·llm·ai大模型·计算机技术
FellAveal2 小时前
【图灵完备 Turing Complete】游戏经验攻略分享 Part.5 编程
游戏·硬件架构·硬件工程
lucifer3112 小时前
深入理解 Spring Boot 自动配置原理
java·后端
JavaGuide3 小时前
一条 SQL 语句在 MySQL 中是如何执行的?
java·数据库·后端·mysql
ABin-阿斌3 小时前
SpringBoot 整合 Easy_Trans 实现翻译的具体介绍
java·spring boot·后端
终末圆3 小时前
MyBatis XML映射文件编写【后端 18】
xml·java·开发语言·后端·算法·spring·mybatis