Java实现飞机大战游戏 附完整源码

目录
  • 飞机大战详细文档
  • 实现效果:
  • 结构设计
  • 详细分析
    • Main界面类使用边框布局,给面板分三个区,如图所示
    • 绘制背景地图
    • 飞行道具类UML图
    • 绘制线程: 如何让我们的游戏动起来
    • 背景的绘制
    • 我的飞机的绘制
    • 移动线程
    • 如何控制我的飞机移动?
    • 敌方飞机线程 : 如何生成敌方飞机呢?
    • 敌方子弹线程 : 使每一个敌方飞机开火
    • 检测碰撞线程 : 在子弹与敌机碰撞时,移除敌机
    • 其他功能:显示玩家hp,掉落道具,得分,升级,更换地图

飞机大战详细文档

文末有源代码,以及本游戏使用的所有素材,将plane2文件复制在src文件下可以直接运行。

实现效果:

结构设计

  • 角色设计

    • 飞行对象类 FlyObject

      • 战机类

        • 我的飞机 MyPlane
        • 敌方飞机 EnemyPlane
      • 子弹类
        • 我的子弹 MyBullet
        • 敌方子弹 EnemyBullet
      • 道具类 Prop
        • 加分,加血,升级
    • 地图背景类 Background
    • 玩家类 Player
      • HP,得分
  • 线程类
    • 绘制线程 DrawThread
    • 移动线程 MoveThread
    • 生成敌方飞机线程 EnemyPlaneThread
    • 敌方飞机生成子弹线程 EnemyButtleThread
    • 检测碰撞线程 TestCrashThread
  • 界面类
    • 主界面 GameUI
    • 选择地图界面 SelectMapUI
  • 监听器类 KListener
    • 通过按压键盘改变我方飞机的速度
  • 数据结构
    • 我方战机(只有一个)
    • 我方飞机子弹集合
    • 敌方飞机集合
    • 敌方子弹集合
    • 道具集合

详细分析

Main界面类使用边框布局,给面板分三个区,如图所示

关键代码:

  JFrame jf = new JFrame("飞机大战"); //创建窗体
        jf.setSize(670,800);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jf.setLayout(new BorderLayout()); //布局

        //创建三个JPanel,左上为按钮,左下为分数显示 右为游戏页面
        JPanel left = new JPanel();
        JPanel leftUp = new JPanel();  //左上
        JPanel leftDown = new JPanel();   //左下
        game = new JPanel();   //游戏显示区

        left.setPreferredSize(new Dimension(170,800));
        left.setBackground(new Color(-3355444));
        jf.add(left,BorderLayout.WEST);

        jf.add(game,BorderLayout.CENTER);
        game.requestFocus();
        left.setLayout(new BorderLayout());

        leftUp.setPreferredSize(new Dimension(0,250));
        leftUp.setBackground(new Color(-3355444));
        left.add(leftUp,BorderLayout.NORTH);

        leftDown.setBackground(new Color(-6710887));
        leftDown.setPreferredSize(new Dimension(0,550));
        left.add(leftDown,BorderLayout.SOUTH);

绘制背景地图

飞行道具类UML图

判断FlyObject对象是否碰撞

public boolean judge_crash(FlyObject fo){
        if(x+sizeX<fo.x || y+sizeY<fo.y || x > fo.x + fo.sizeX || y > fo.y+ fo.sizeY ){
            return false;
        }else{
            return true;
        }
    }

绘制线程: 如何让我们的游戏动起来

  • 视频原理:我们在屏幕上看见的动态图像图像实际上由若干个静止图像构成,由于人眼有暂留特性,刚显示的图像在大脑中停留一段时间,若静态图像每
  • 秒钟变化25幅,那么人的感觉屏幕上的图像是动的。
  • 绘制时要把所有的飞行物都绘制一遍,所以我们需要在每一个飞行物被创建时,添加到相关的飞行物集合中。(为了方便传值,我们将集合设为静态变量)
  • 我们的绘制线程,选择每30ms绘制一次,注意先画背景,然后再遍历飞行物集合画飞行物。

背景的绘制

要想绘制动态的背景,首先我们要先画一张静态的背景图,那么如何绘制一张静态的背景图呢?

获取包中的图片:

  String fileName_0 = "src\\plane2\\z_img\\img_bg_0.jpg"; //相对地址(和绝对地址区分开)
        BufferedImage bufferedImage;
        bufferedImage = ImageIO.read(new File(fileName_0));  //将文件读出记录在bufferedImage中,记得抛出异常
        g.drawImage(bufferedImage,0,0,null);   // 将bufferedImage中的内容画在画笔g对应的地方

我们的地图是一张可以从上往下无缝滚动的图片,就像是这样的图

接下来,如何让画出连续的图片呢?

在绘制函数中,有一个函数可以完美实现我们的需求

img – the specified image to be drawn. This method does nothing if img is null.
        dx1 – the x coordinate of the first corner of the destination rectangle.
        dy1 – the y coordinate of the first corner of the destination rectangle.
        dx2 – the x coordinate of the second corner of the destination rectangle.
        dy2 – the y coordinate of the second corner of the destination rectangle.
        sx1 – the x coordinate of the first corner of the source rectangle.
        sy1 – the y coordinate of the first corner of the source rectangle.
        sx2 – the x coordinate of the second corner of the source rectangle.
        sy2 – the y coordinate of the second corner of the source rectangle.
        observer – object to be notified as more of the image is scaled and converted.
    public abstract boolean drawImage(Image img,
                                      int dx1, int dy1, int dx2, int dy2,
                                      int sx1, int sy1, int sx2, int sy2,
                                      ImageObserver observer);

比如说,我们的图片高度为712个像素点,我们在下一时刻,图片向下移动了m个像素点,那么我们就将这张图片的0 ~ 712-m 部分,绘制到游戏界面的m ~ 712部分,
再将712-m ~ 712 部分绘制到游戏界面的0 ~ m 部分;

接下来,我们就要确定 m 的值,这个就很简单了,在绘制线程中,定义一个整数变量m ,每次绘制完 m++ 就可以了。(个人建议m+=2比较舒服)

/**
* @author liTianLu
* @Date 2022/5/21 23:33
* @purpose 绘制背景
 * 提醒: 这里我写了四种地图的绘制,后面在选择地图时会用到。
*/
public class BackGround {
    Graphics g;
    BufferedImage bufferedImage_1;
    BufferedImage bufferedImage_2;
    BufferedImage bufferedImage_3;
    BufferedImage bufferedImage_4;
    int w;
    int h;
    String fileName_1 = "src\\plane2\\z_img\\img_bg_1.jpg";   //地图1
    String fileName_2 = "src\\plane2\\z_img\\img_bg_2.jpg";   //地图2
    String fileName_3 = "src\\plane2\\z_img\\img_bg_3.jpg";   //地图3
    String fileName_4 = "src\\plane2\\z_img\\img_bg_4.jpg";   //地图4
    public BackGround(Graphics g) throws IOException {
        this.g = g;
        bufferedImage_1 = ImageIO.read(new File(fileName_1));
        bufferedImage_2 = ImageIO.read(new File(fileName_2));
        bufferedImage_3 = ImageIO.read(new File(fileName_3));
        bufferedImage_4 = ImageIO.read(new File(fileName_4));
        w = bufferedImage_1.getWidth();
        h = bufferedImage_1.getHeight();
    }
    /**
    * i : 向下移动了i个像素
    * num : 用来控制绘制哪一个地图
    */
    public void draw(int i , int num){
        switch(num){
            case 1 :
                g.drawImage(bufferedImage_1,0,i,w,i+h,0,0,w,h,null);
                g.drawImage(bufferedImage_1,0,0,w,i,0,h-i,w,h,null);
                break;
            case 2 :
                g.drawImage(bufferedImage_2,0,i,w,i+h,0,0,w,h,null);
                g.drawImage(bufferedImage_2,0,0,w,i,0,h-i,w,h,null);
                break;
            case 3 :
                g.drawImage(bufferedImage_3,0,i,w,i+h,0,0,w,h,null);
                g.drawImage(bufferedImage_3,0,0,w,i,0,h-i,w,h,null);
                break;
            case 4 :
                g.drawImage(bufferedImage_4,0,i,w,i+h,0,0,w,h,null);
                g.drawImage(bufferedImage_4,0,0,w,i,0,h-i,w,h,null);
                break;
        }
    }
    public int getH() {
        return h;
    }
}

绘制线程:

backGround.draw(m, player.mapNum);
            m = m+2;
            if(m>= backGround.getH()){
                m = 0;
            }

我的飞机的绘制

使用的飞机素材图片:

飞机扇动翅膀的原理与视频的原理相同,不停更换图片,形成视觉暂留效果

//这里仅使用了三张图片来回切换,更多的图片会有更好的效果
public void draw(int i){    //此处的i是用来控制显示哪一张图片的
        int j = i%30; // 150ms换一张
        if (j<10){
            g.drawImage(plane_img,x,y,x+sizeX,y+sizeY,0,0,sizeX,sizeY,null);
        }else if(j<20) {
            g.drawImage(plane_img,x,y,x+sizeX,y+sizeY,0,sizeY,sizeX,2*sizeY,null);
        }else if(j<30){
            g.drawImage(plane_img,x,y,x+sizeX,y+sizeY,288,0,424,112,null);
        }
    }

敌方飞机,敌方子弹等飞行物的绘制原理与MyPlane相同,后面不在赘述。(为了简化开发流程,飞行物可以不”扇动翅膀“)

移动线程

  • 我们已经给每个飞行对象设置了X轴移动速度和Y轴移动速度,所以每次移动的时候,我们只需要遍历所有的飞行对象,
  • 然后逐个移动一个speedX 和 speedY 单位即可。
  • 多久移动一次呢?和绘制线程的间隔时间相同就好了,我们都设为30ms.
  • 当飞行物飞出屏幕时,将飞行物移出集合,减少计算机资源的消耗。

如何控制我的飞机移动?

  • 当然是通过键盘的 ↑ ↓ ← → 来控制了,我们需要设置一个键盘监听器给game界面,
  • 注意要先使用 game.requestFocus(); 获取焦点,键盘监听器才可以使用。
 @Override
        //键盘按压时,设置速度
    public void keyPressed(KeyEvent e) {
        int c = e.getKeyCode();
        if(DrawThread.myPlane!=null){
            switch (c){
                case 37:
                    DrawThread.myPlane.setSpeedX(-speed);
                    break;
                case 38:
                    DrawThread.myPlane.setSpeedY(-speed);
                    break;
                case 39:
                    DrawThread.myPlane.setSpeedX(speed);
                    break;
                case 40:
                    DrawThread.myPlane.setSpeedY(speed);
                    break;
            }
        }
    }

@Override
        //键盘释放时,速度设为0
    public void keyReleased(KeyEvent e) {
        int c = e.getKeyCode();
        switch (c){
            case 37:
            case 39:
                DrawThread.myPlane.setSpeedX(0);
                break;
            case 38:
            case 40:
                DrawThread.myPlane.setSpeedY(0);
                break;
        }
    }

敌方飞机线程 : 如何生成敌方飞机呢?

每隔一段时间,在游戏面板的顶部,产生一个敌方飞机

/**
* @author liTianLu
* @Date 2022/5/22 0:30
* @purpose 产生敌机的线程
*/
    @Override
    public void run() {
        int sleepTime  = 800;
        while (true){
            if(DrawThread.player.score>=500){  //当分数高于500时,加快敌机产生的频率
                sleepTime = 300;
            }
            EnemyPlane enemyPlane = null;
            try {
                enemyPlane = new EnemyPlane();
            } catch (IOException e) {
                e.printStackTrace();
            }
            enemyPlanes.add(enemyPlane);
            new Thread(new EnemyBulletThread(enemyPlane)).start(); //启动一个发射子弹线程
            try {
                sleep(sleepTime+ random.nextInt(300));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

敌方子弹线程 : 使每一个敌方飞机开火

我们为每一个敌方飞机创建一个生成子弹的线程,要确定子弹产生的具体位置,就要知道敌方飞机的位置,所以我们要传入一个敌方飞机对象给该线程。

public EnemyBulletThread(EnemyPlane enemyPlane){
        this.enemyPlane = enemyPlane;
    }
    @Override
    public void run() {
        try {
            sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while(enemyPlane.isAlive() ){
            EnemyBullet enemyBullet = null;
            int enemyBullet_x = enemyPlane.getX()+25;
            int enemyBullet_y = enemyPlane.getY()+66;
            try {
                enemyBullet = new EnemyBullet(enemyBullet_x,enemyBullet_y);
            } catch (IOException e) {
                e.printStackTrace();
            }
            enemyBullets.add(enemyBullet);
            try {
                sleep(2000+ random.nextInt(2000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

检测碰撞线程 : 在子弹与敌机碰撞时,移除敌机

  • 此时我们会遇到一个问题,就是在遍历时,move移动线程有可能将其中的一个飞行物移出集合,会出现IndexOutOfBoundsException异常
  • ,我们只需要在两个线程使用飞行物集合时,加上synchronized关键字,即可解决。
  • MoveThread 遍历我的子弹集合
synchronized (MyPlane.myBulletList){
    if(MyPlane.myBulletList.size()!=0){
        for (int i = 0; i < MyPlane.myBulletList.size(); i++) {
            MyPlane.myBulletList.get(i).setY(MyPlane.myBulletList.get(i).getY()+MyPlane.myBulletList.get(i).getSpeedY()    );

            if(MyPlane.myBulletList.get(i).getY() <= -100){
                MyPlane.myBulletList.remove(i);
                continue;
            }
        }
    }
}

TestCrashThread 检测我的子弹与敌方飞机碰撞

synchronized (MyPlane.myBulletList){
    for (int i = 0; i < MyPlane.myBulletList.size(); i++) {
        for (int j = 0; j < EnemyPlaneThread.enemyPlanes.size() ;j++) {
            if(MyPlane.myBulletList.get(i).judge_crash(EnemyPlaneThread.enemyPlanes.get(j)) ){
                EnemyPlaneThread.enemyPlanes.get(j).setAlive(false);  //关线程
                DrawThread.player.score+=5; //分数+5
                EnemyPlaneThread.enemyPlanes.remove(j);
                MyPlane.myBulletList.remove(i);
                j = -1;
            }
            if(i >= MyPlane.myBulletList.size()){
                break;
            }
        }

    }
}

其他功能:显示玩家hp,掉落道具,得分,升级,更换地图

  • 显示hp:每次检测到我的飞机与敌方飞机,敌方子弹碰撞,就减分。减到<=0时,游戏结束。
  • 得分:子弹打到敌方飞机时,加分,并将当前分数通过绘制线程绘制在屏幕上。
  • 掉落道具:敌机消失的时候,随机掉落一个道具,我的飞机碰到道具时,回血/加分/升级
  • 升级:我的飞机初始为1级,最高为3级,等级改变时,使用switch 根据等级改变我的飞机的子弹发射方式。
  • 更换地图: 使用一个新的窗体,设置几个单选按钮,选择时通过监听器,改变地图的控制变量,从而改变地图的绘制。

源码下载:

链接: https://pan.baidu.com/s/1ORdS-Ep0MNmVsslv9YFjiQ

提取码: hvz4

到此这篇关于Java实现飞机大战游戏 附完整源码的文章就介绍到这了,更多相关java飞机大战内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java版飞机大战实战项目详细步骤

    本文为大家分享了java版飞机大战实战项目,供大家参考,具体内容如下 分析 飞机大战 首先对这个游戏分析,在屏幕上的物体都是飞行物,我们可以把建一个类,让其他飞行物继承这个类.游戏中应有英雄机(也就是自己控制的飞机).敌人.而敌人应该分为打死给分的飞机(就是普通飞机),另一种就是打死有奖励的敌人.他们都应该是飞行物的子类,我们也可以为普通飞机和给奖励的敌人设一个接口让他们去实现接口,这样有利于以后的扩展,我在这里给的简化版的飞机大战,主要是为了让大家了解面向对象. 第一步建立飞行物类 impor

  • java实现飞机大战案例详解

    前言 飞机大战是一个非常经典的案例,因为它包含了多种新手需要掌握的概念,是一个非常契合面向对象思想的入门练习案例 程序分析: 在此游戏中共有六个对象: 小敌机Airplane,大敌机BigAirplane,小蜜蜂Bee,天空Sky,英雄机Hero,子弹Bullet 其次我们还需要三个类: 超类Flyer,图片类Images,测试类World 还需: 英雄机2张,小敌机,大敌机,小蜜蜂,子弹,天空各1张,爆炸图4张,游戏开始,暂停,游戏结束各1张,共14张图片放入与图片类Images同包中 超类F

  • java实现简易飞机大战

    目录 整体思路 代码实现 英雄战机类 敌机类 子弹类 图片工具类 游戏窗体类 启动游戏类 运行效果图 本文实例为大家分享了java实现简易飞机大战的具体代码,供大家参考,具体内容如下 整体思路 1.创建游戏窗体,添加面板JPanel,重写JPanel中的paint方法,遍历所有飞机和子弹绘制,用定时器进行重绘,实现动画效果2.添加敌机和发射子弹用的是多线程3.碰撞检测采用的是矩形类Rectangle中的intersects方法 代码实现 用手机查看代码好像只显示62行 英雄战机类 package

  • java实战之飞机大战小游戏(源码加注释)

    一.工程文件 二.Main.java 主函数,实现类 package ui; //主函数实现 public class Main { public static void main(String[] args) { //创建窗体 GameFrame frame = new GameFrame(); //创建面板 GamePanel panel = new GamePanel(frame); //调用开始游戏的方法启动游戏 panel.action(); //将面板加入到窗体中 frame.add

  • 一天时间用Java写了个飞机大战游戏,朋友直呼高手

    一.代码实现 创建窗口 首先创建一个游戏窗体类GameFrame,继承至JFrame,用来显示在屏幕上(window的对象),每个游戏都有一个窗口,设置好窗口标题.尺寸.布局等就可以. /* * 游戏窗体类 */ public class GameFrame extends JFrame { public GameFrame() { setTitle("飞机大战");//设置标题 setSize(526, 685);//设定尺寸 setLayout(new BorderLayout()

  • java实现飞机大战游戏

    java实现飞机大战 用Java写个飞机大战游戏练习一下,实现可播放游戏背景音乐和游戏的基本功能 设计 1.准备好相应的图片和背景音乐(.wav文件): 2.直接看源码: 3.还有部分功能未实现. 源码 package forGame 加载游戏图片类 package forGame; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.image.BufferedImage; import java.io.Fil

  • Java实现飞机大战游戏 附完整源码

    目录 飞机大战详细文档 实现效果: 结构设计 详细分析 Main界面类使用边框布局,给面板分三个区,如图所示 绘制背景地图 飞行道具类UML图 绘制线程: 如何让我们的游戏动起来 背景的绘制 我的飞机的绘制 移动线程 如何控制我的飞机移动? 敌方飞机线程 : 如何生成敌方飞机呢? 敌方子弹线程 : 使每一个敌方飞机开火 检测碰撞线程 : 在子弹与敌机碰撞时,移除敌机 其他功能:显示玩家hp,掉落道具,得分,升级,更换地图 飞机大战详细文档 文末有源代码,以及本游戏使用的所有素材,将plane2文

  • 使用python+pygame开发消消乐游戏附完整源码

    效果是这样的 ↓ ↓ ↓ 一.环境要求 windows系统,python3.6+ pip21+ 开发环境搭建地址 一起来学pygame吧 游戏开发30例(开篇词)--环境搭建+游戏效果展示 安装游戏依赖模块 pip install pygame 二.游戏简介 消消乐应该大家都玩过,或者看过.这个花里胡哨的小游戏 用python的pygame来实现,很简单. 今天带大家,用Python来实现一下这个花里胡哨的小游戏. 三.完整开发流程 1.项目主结构 首先,先整理一下项目的主结构,其实看一下主结构

  • javascript实现打砖块小游戏(附完整源码)

    小时候玩一天的打砖块小游戏,附完整源码 在?给个赞? 实现如图 需求分析 1.小球在触碰到大盒子上.左.右边框,以及滑块后沿另一方向反弹,在碰到底边框后游戏结束: 2.小球在触碰到方块之后,方块消失: 3.消除所有方块获得游戏胜利: 4.可通过鼠标与键盘两种方式移动滑块: 5.游戏难度可调整,实时显示得分. 代码分析 1.html结构:左右两个提示框盒子分别用一个div,在其中添加需要的内容:中间主体部分用一个div,里面包含一个滑块(slider),一个小球(ball),以及一个装有所有方块的

  • 半小时实现Java手撸网络爬虫框架(附完整源码)

    最近在做一个搜索相关的项目,需要爬取网络上的一些链接存储到索引库中,虽然有很多开源的强大的爬虫框架,但本着学习的态度,自己写了一个简单的网络爬虫,以便了解其中的原理.今天,就为小伙伴们分享下这个简单的爬虫程序!! 首先介绍每个类的功能: DownloadPage.java的功能是下载此超链接的页面源代码. FunctionUtils.java 的功能是提供不同的静态方法,包括:页面链接正则表达式匹配,获取URL链接的元素,判断是否创建文件,获取页面的Url并将其转换为规范的Url,截取网页网页源

  • 基于spring-boot和docker-java实现对docker容器的动态管理和监控功能[附完整源码下载]

    docker简介 Docker 是一个开源的应用容器引擎,和传统的虚拟机技术相比,Docker 容器性能开销极低,因此也广受开发者喜爱.随着基于docker的开发者越来越多,docker的镜像也原来越丰富,未来各种企业级的完整解决方案都可以直接通过下载镜像拿来即用.因此docker变得越来越重要. 本文目的 本文通过一个项目实例来介绍如果通过docker对外接口来实现对docker容器的管理和监控. 应用场景: 对服务器资源池通过docker进行统一管理,按需分配资源和创建容器,达到资源最大化利

  • 微信小程序之侧边栏滑动实现过程解析(附完整源码)

    一.效果图 讲什么都不如直接上效果图好,所以我们先来看下实现效果如何. 通过滑动屏幕,或者点击左上角的图标按钮,都能实现侧边栏的划出效果. 二.原理解析 1.先实现侧边栏的内容,让侧边栏的内容居左,然后将侧边栏的内容置于屏幕的最底部. 2.接着实现主页的内容,并且让主页的内容默认是覆盖在侧边栏的内容上面. 3.然后,实现手指滑动屏幕的时候,主页的内容,向左滑动一定的宽度,让侧边栏的内容显示出来,而滑动的效果是通过 css 的 transition 来实现的. 三.源码 由于实现过程的时,我对代码

  • python抢购软件/插件/脚本附完整源码

    距上篇关于淘宝抢购源码的文章已经过去五个月了,五个月来我通过不停的学习,掌握了更深层的抢购技术及原理,而上篇文章中我仅分享了关于加入购物车的商品的抢购源码,且有部分不足. 博主不提供任何服务器端程序,也不提供任何收费抢购软件.该文章仅作为学习selenium框架及GUI开发的一个示例代码.该思路可运用到其他任何网站,京东,天猫,淘宝均可使用,且不属于外挂或者软件之类,只属于一个自动化点击工具,如有侵犯到任何公司的合法权益,请私信联系,会第一时间将相关代码给予删除. 本篇文章我将附上完整源码,及其

  • 超详细OpenMV与STM32单片机通信 附完整源码

    目录 1.前言(闲话) 2.硬件连接 3.软件代码---OpenMV端 4.软件代码---STM32端 5.利用PC端测试数据数据是否发送接收正常 6.学习补充 (代码看不懂的时候可以来看一下) 8.博客更新 9.参考链接 10.完整版代码链接 1.前言(闲话) 最近在做电磁炮,发现题目需要用到颜色跟踪,于是花了一点时间学了一下OpenMV,只学习OpenMV是远远不够的,还需要实现与单片机的通信,本以为很简单,在CSDN上找了一些代码,直接拿来修改粘贴,把代码看明白了,这些只花了几个小时,本以

  • java实现贪吃蛇游戏代码(附完整源码)

    先给大家分享源码,喜欢的朋友点此处下载. 游戏界面 GUI界面 java实现贪吃蛇游戏需要创建一个桌面窗口出来,此时就需要使用java中的swing控件 创建一个新窗口 JFrame frame = new JFrame("贪吃蛇游戏"); //设置大小 frame.setBounds(10, 10, 900, 720); 向窗口中添加控件 可以直接用add方法往窗口中添加控件 这里我创建GamePanel类继承自Panel,最后使用add方法添加GamePanel 加载图片 图片加载

随机推荐