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

news2024/11/16 12:45:39

目录

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

(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;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在Mac上查看剪贴板历史记录

重点摘要 macOS 内建的剪贴簿查看器可以透过 Finder 存取,但只能显示最近一次复制的内容,而且重新开机后就会清除。若要更进阶的剪贴簿管理,第三方 app 像是 CleanClip 提供了强大的功能和更好的组织方式。CleanClip 提供了全方位的剪贴簿历史管理解决方案,支援各种内容类型和…

HarmonyOS鸿蒙开发实战(5.0)表情图片聊天案例实践

鸿蒙HarmonyOS NEXT开发实战往期文章必看&#xff08;持续更新......&#xff09; HarmonyOS NEXT应用开发性能实践总结 HarmonyOS NEXT应用开发案例实践总结合集 最新版&#xff01;“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门…

线性表一(vector)

#include<bits/stdc.h> using namespace std; vector<int> a(5,2);//定义一个初始长度为5&#xff0c;每个元素值为2的可变数组 vector<char> b(3);//定义一个初始长度为3&#xff0c;每个元素为默认值的可变数组 vector<int> v;//定义一个长度为0的可…

mxnet系统架构

mxnet系统架构 MXNet 是一个高性能、灵活的深度学习框架&#xff0c;最早由李沐&#xff08;Mu Li&#xff09;等人开发&#xff0c;并且得到了 Amazon 的支持。它支持多种语言&#xff08;包括 Python、Scala、C、R、Julia、Perl 等&#xff09;&#xff0c;并以其灵活的编程…

【保奖思路】2024年华为杯研赛B题完整代码建模过程(后续会更新)

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片&#xff0c;那是获取资料的入口&#xff01; 点击链接加入【2024华为杯研赛资料汇总】&#xff1a;https://qm.qq.com/q/XzdIsvbiM0https://qm.qq.com/q/XzdIsvbiM0请根据附件WLAN网络实测训练集中所提供…

python多继承 - 子类指定父类

菜鸟教程-面向对象 https://www.runoob.com/python3/python3-class.html 子类内指定父类 父类名称.__init__(self,参数1&#xff0c;参数2&#xff0c;...) 子类对象指定父类 class Parent1:def my_method(self):print("Parent1s my_method")class Parent2:def my_…

基于uni-app的计算机类面试宝设计与实现(毕业论文)

目 录 1 前言 1 1.1 研究目的与意义 1 1.2 研究现状 1 1.3 论文结构 2 2 可行性分析 3 2.1 经济可行性 3 2.2 法律可行性 3 2.3 技术可行性 4 2.4 市场可行性 4 2.5 可行性分析结论 4 3 系统需求分析 4 3.1 用户需求分析 4 3.2 系统功能分析 5 3.3 系统性能需求分析 6 4 概要设…

前端vue-ref与document.querySelector的对比

ref只在本组件中查找&#xff0c;而document.querySelector是在整个页面查找

【学习笔记】手写Tomcat 四

目录 一、Read 方法返回 -1 的问题 二、JDBC 优化 1. 创建配置文件 2. 创建工具类 3. 简化 JDBC 的步骤 三、修改密码 优化返回数据 创建修改密码的页面 注意 测试 四、优化响应动态资源 1. 创建 LoginServlet 类 2. 把登录功能的代码放到 LoginServlet 类 3. 创…

hackmyvm靶场--zon

环境 攻击机kali 靶机 未知 主机探测 因为在同一个局域网内使用ARP协议探测存活主机 靶机为192.168.56.128 端口探测 常见的80和22端口 那么一定是寻找web漏洞拿shell了 后台扫描 后台扫描常用dirsearch和gobuster,有时候小字典可能不太行&#xff0c;可以尝试换个大点…

Android SystemUI组件(07)锁屏KeyguardViewMediator分析

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分即可。 为了更好理解本文的内容&#xff0c;优先说明下SystemUI中与Ke…

电力行业螺钉螺帽螺丝缺失检测数据集 voc yol

电力行业螺钉螺帽螺丝缺失检测数据集 数据集描述 该数据集旨在用于电力行业中的螺钉、螺帽、螺丝等紧固件的缺失检测任务。数据集包含了大量的图像及其对应的标注信息&#xff0c;可用于训练计算机视觉模型&#xff0c;以识别和定位电力设施中的螺钉、螺帽、螺丝等部件是否存在…

Go-知识-定时器

Go-知识-定时器 1. 介绍2. Timer使用场景2.1 设定超时时间2.2 延迟执行某个方法 3. Timer 对外接口3.1 创建定时器3.2 停止定时器3.3 重置定时器3.4 After3.5 AfterFunc 4. Timer 的实现原理4.1 Timer数据结构4.1.1 Timer4.1.2 runtimeTimer 4.2 Timer 实现原理4.2.1 创建Timer…

golang学习笔记1-go程序执行流程

声明&#xff1a;本人已有C&#xff0c;C,Python基础&#xff0c;只写本人认为的重点&#xff0c;方便自己回顾。 命令行执行go程序有两种方式&#xff0c;其流程如下图 注意第一种方式会得到可执行文件&#xff0c;第二种不会。 例1 在当前目录下编译hello.go go build hel…

更换硬盘后,电脑装完系统进不去?或PE能识别硬盘但开机/启动/BIOS识别不了硬盘解决办法

由于现在的电脑主板&#xff0c;默认都是UEFI启动&#xff0c;硬盘只有使用GUID分区表&#xff0c;主板BIOS才找得到系统引导&#xff01; 而当我们拿到一块新硬盘&#xff0c;使用分区工具默认类型分区&#xff0c;默认是MBR类型&#xff0c;所以这种分区的硬盘&#xff0c;B…

【后端开发】JavaEE初阶—线程的理解和编程实现

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解多线程的知识哟~~~&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;【后端开发】JavaEE初阶——计算机是如何工作的&#xff1f;&#xff1f;&#xff1f;-CSDN博客 &#x1f308;感兴趣的小伙…

腾讯云ssl证书到期,续期免费证书并部署

首先咱用的免费证书&#xff0c;现在最长90天有效期&#xff0c;今天又到期了&#xff0c;得及时续期避免关联资源访问受限。 我这个证书是关联了一个负载均衡和两个容器服务的&#xff08;如果您的应用是ngnix或其他的应用那和本文操作可能有点不一样&#xff09; 所以需要做…

17【Protues单片机仿真】基于51单片机的太阳能智能谷物翻晒机器人

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;避障&#xff0c;低于50CM报警&#xff0c;LED灯亮起&#xff0c;自动翻晒用光敏电阻&#xff0c;光照强度大&#xff0c;电机转动&#xff0c;相当于翻晒粮食&#xff0…

【python设计模式7】行为型模式2

目录 策略模式 模板方法模式 策略模式 定义一个个算法&#xff0c;把它们封装起来&#xff0c;并且使它们可以相互替换。本模式使得算法可独立于使用它的客户而变化。角色有&#xff1a;抽象策略、具体策略和上下文。 from abc import abstractmethod, ABCMeta from datetim…

2024年最新Redis内存数据库主从复制、哨兵模式、集群部署等详细教程(更新中)

Centos 安装 Redis 检查安装 GCC 环境 [rootVM-4-17-centos ~]# gcc --version gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4) Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; no…