《飞机大战游戏》实训项目(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)启动类(主类)
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;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/881688.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

828华为云征文|Flexus云服务器X实例部署宝塔运维面板

本次华为云Flexus云服务器X实例部署宝塔运维面板教学&#xff0c;这次是推陈出新啊 之前的云耀云服务器L实例已经很不错了&#xff0c;大力赞叹华为云的 同时感谢华为云提供优惠卷&#xff0c;只能说白嫖真是太棒了 华为云近期正在筹办华为云828企业节活动&#xff0c;90款免…

HarmonyOS Next开发----使用XComponent自定义绘制

XComponent组件作为一种绘制组件&#xff0c;通常用于满足用户复杂的自定义绘制需求&#xff0c;其主要有两种类型"surface和component。对于surface类型可以将相关数据传入XComponent单独拥有的NativeWindow来渲染画面。 由于上层UI是采用arkTS开发&#xff0c;那么想要…

【RabbitMQ】消息分发、事务

消息分发 概念 RabbitMQ队列拥有多个消费者时&#xff0c;队列会把收到的消息分派给不同的消费者。每条消息只会发送给订阅该队列订阅列表里的一个消费者。这种方式非常适合扩展&#xff0c;如果现在负载加重&#xff0c;那么只需要创建更多的消费者来消费处理消息即可。 默…

深度学习01-概述

深度学习是机器学习的一个子集。机器学习是实现人工智能的一种途径&#xff0c;而深度学习则是通过多层神经网络模拟人类大脑的方式进行学习和知识提取。 深度学习的关键特点&#xff1a; 1. 自动提取特征&#xff1a;与传统的机器学习方法不同&#xff0c;深度学习不需要手动…

【数据库】常用数据库简介

目录 &#x1f354; 常用的关系型数据库 &#x1f354; Mysql简介 &#x1f354; SQL 简介 SQL语句的分类 SQL 写法 SQL 常用的数据类型 &#x1f354; DDL语句 对数据库的操作 对数据表的操作 &#x1f354; DML语句 插入数据 insert into 修改数据 update 删除数…

python实现多个pdf文件合并

打印发票时&#xff0c;需要将pdf合并成一个&#xff0c;单页两张打印。网上一些pdf合并逐渐收费&#xff0c;这玩意儿都能收费&#xff1f;自己写一个脚本使用。 实现代码&#xff1a; 输入pdf文件夹路径data_dir&#xff0c;统计目录下的“合并后的PDF”文件夹下&#xff0c;…

linux重要文件

/etc/sysconfig/network-scripts/ifcfg-eth1 网卡重启 /etc/init.d/network restart ifup ethname & ifdown ethname /etc/resolv.conf 设置Linux本地的客户端DNS的配置文件 linux客户端DNS可以在网卡配置文件(/etc/sysconfig/network/ifcfg-eth0 DNS2)里配置 也可以在/et…

Java_Day04学习

类继承实例 package com.dx.test03; public class extendsTest {public static void main(String args[]) {// 实例化一个Cat对象&#xff0c;设置属性name和age&#xff0c;调用voice()和eat()方法&#xff0c;再打印出名字和年龄信息/********* begin *********/Cat cat ne…

Pandas -----------------------基础知识(一)

目录 Series对象 属性和方法 布尔值列表获取Series对象中部分数据 运算 DateFrame对象 常用属性 常见方法 运算 总结 Series对象 是DataFrame的列对象或者行对象 生成Series对象生成索引使用元组创建Series对象使用字典创建Series对象 通过Pandas创建对象 自定义索引 …

面试官问:你最自豪的成就是什么?

当面试官问你最自豪的成就是什么&#xff0c;我们首先分析面试官为什么这么问&#xff0c;他想通过这问题得到什么信息&#xff1f; 你最自豪的成就是什么&#xff1f; 其实反应了一个人的职业驱动力&#xff0c;比如我们常说的&#xff1a;上进心&#xff0c;主动积极性&…

【机器学习-监督学习】朴素贝叶斯

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科&#xff0c;通过算法和模型让计算机从数据中学习&#xff0c;进行模型训练和优化&#xff0c;做出预测、分类和决策支持。Python成为机器学习的首选语言&#xff0c;…

【小沐学GIS】基于Openstreetmap创建Sionna RT场景(Python)

文章目录 1、简介1.1 blender 2、下载和安装2.1 Python2.2 jupyter 3、运行结语 1、简介 1.1 blender https://www.blender.org/ Blender 是一款免费开源的3D创作套件。 使用 Blender&#xff0c;您可以创建3D可视化效果&#xff0c;例如静态图像、3D动画、VFX&#xff08;…

【UE5】将2D切片图渲染为体积纹理,最终实现使用RT实时绘制体积纹理【第一篇-原理】

如果想直接制作&#xff0c;请看【第二篇】内容 这次做一个这样的东西&#xff0c;通过在2DRT上实时绘制&#xff0c;生成动态的体积纹理&#xff0c;也就是可以runtime的VDB 设想的文章流程: 对原理进行学习制作体积渲染制作实时绘制 第一篇&#xff08;本篇&#xff09;是对“…

【Rust练习】16.模式

文章题目来自&#xff1a;https://practice-zh.course.rs/pattern-match/patterns.html 1 &#x1f31f;&#x1f31f; 使用 | 可以匹配多个值, 而使用 … 可以匹配一个闭区间的数值序列 fn main() {} fn match_number(n: i32) {match n {// 匹配一个单独的值1 > println!(…

【赵渝强老师】K8s中的Deployment控制器

K8s的Deployment将Pod部署成无状态的应用程序&#xff0c;它只关心Pod的数量、Pod更新方式、使用的镜像和资源限制等。由于是无状态的管理方式&#xff0c;因此Deployment中没有角色和顺序的概念&#xff0c;换句话说&#xff1a;Deployment中没有状态。   通过使用Deploymen…

【远程调用PythonAPI-flask】

文章目录 前言一、Pycharm创建flask项目1.创建虚拟环境2.创建flask项目 二、远程调用PythonAPI——SpringBoot项目集成1.修改PyCharm的host配置2.防火墙设置3.SpringBoot远程调用PythonAPI 前言 解决Pycharm运行Flask指定ip、端口更改无效的问题 首先先创建一个新的flask项目&…

C语言 | Leetcode C语言题解之第415题字符串相加

题目&#xff1a; 题解&#xff1a; char* addStrings(char* num1, char* num2) {int i strlen(num1) - 1, j strlen(num2) - 1, add 0;char* ans (char*)malloc(sizeof(char) * (fmax(i, j) 3));int len 0;while (i > 0 || j > 0 || add ! 0) {int x i > 0 ?…

Games101学习 - 着色

本文主要讲述Games101中的着色部分。 文中将使用UE的UTexture2D接口&#xff0c;若不了解可以看这篇&#xff1a; https://blog.csdn.net/grayrail/article/details/142165442 1.面积比计算三角形坐标 通过三角形面积比可以得到三角形的坐标alpha、beta、gamma从而进行插值&a…

ChatGPT 4o 使用指南 (9月更新)

首先基础知识还是要介绍得~ 一、模型知识&#xff1a; GPT-4o&#xff1a;最新的版本模型&#xff0c;支持视觉等多模态&#xff0c;OpenAI 文档中已经更新了 GPT-4o 的介绍&#xff1a;128k 上下文&#xff0c;训练截止 2023 年 10 月&#xff08;作为对比&#xff0c;GPT-4…

【Linux笔记】虚拟机内Linux内容复制到宿主机的Window文件夹(文件)中

一、共享文件夹 I、Windows宿主机上创建一个文件夹 目录&#xff1a;D:\Centos_iso\shared_files II、在VMware中设置共享文件夹 1、打开VMware Workstation 2、选择需要设置的Linux虚拟机&#xff0c;点击“编辑虚拟机设置”。 3、在“选项”标签页中&#xff0c;选择“共…