面向对象程序综合设计——大球吃小球

目录

一、团队成员介绍

二、前期调查:

三、项目功能架构图与主要功能流程图

四、包名类名

五、项目运行截图

六、项目代码

七、代码静态扫描:(未成功修改,有的看不太懂),其余代码基本符合规范

八、尚待改进或者新的想法


一、团队成员介绍

姓名 学号任务分配及实现
包佳莉(组长)202221336069球(Ball)我的球(MyBall),其他球(OtherBall),方向接口(Direction),小组博客编写
张子翔(组员)202221336080多线程实现球类的移动和倒计时(Frame2),选择难度和代码的整合(SelectFrame)
胡凌瑞(组员)202221336090背景音乐的添加(Music),登陆界面(GameLogin),重开/退出(Again)

二、前期调查:

借鉴了一些别人的代码:Java多线程-球球小游戏 · 3053a03 · hello world007/球球小游戏 - Gitee.com

三、项目功能架构图与主要功能流程图

四、包名类名

五、项目运行截图

1、登陆注册

2、选择难度

3、游戏界面

游戏胜利:

游戏失败:

                                      (点击是,则开始上一次选择的难度的游戏)

(点击否,则重新选择游戏难度)

六、项目代码

Ball类:实现对球的移动,吃球,绘画球

public void move(int m) {
        // 根据随机生成的方向值来移动球
        switch (this.direction) {
            //随机方向
            case 1 -> x -= m;
            case 2 -> x += m;
            case 3 -> y -= m;
            case 4 -> y += m;
            case 5 -> {
                x -= m;
                y -= m;
            }
            case 6 -> {
                x -= m;
                y += m;
            }
            case 7 -> {
                x += m;
                y -= m;
            }
            case 8 -> {
                x += m;
                y += m;
            }
            default -> {
            }
        }
    }

    public void eat(Ball b1, int i) {
        // eat方法,用于处理球吃掉其他球的逻辑
        int x1 = b1.getX();
        int y1 = b1.getY();
        int d1 = b1.getD();
        // 如果被吃球的直径小于当前球的直径
        if (d1 < this.d) {
            // 计算两球中心点的距离
//                小球被吃掉
            int d = (int) Math.sqrt((x1 + d1 / 2 - this.getX() - this.getD() / 2) * (x1 + d1 / 2 - this.getX() - this.getD() / 2) + (y1 + d1 / 2 - this.getY() - this.getD() / 2) * (y1 + d1 / 2 - this.getY() - this.getD() / 2));
            // 如果距离小于两球半径之和,表示可以吃掉
            if (d < (d1 + this.getD()) / 2) {
// 增加当前球的直径,并将被吃球移出界面
                this.setD(this.d + d1 / i);
                b1.setX(-100);
                b1.setY(-100);
                b1.setD(0);
                b1 = null;
            }
//                b1 = null;
        } else if (d1 > this.getD()) {
            // 如果被吃球的直径大于当前球的直径
            int d = (int) Math.sqrt((x1 + d1 / 2 - this.getX() - this.getD() / 2) * (x1 + d1 / 2 - this.getX() - this.getD() / 2) + (y1 + d1 / 2 - this.getY() - this.getD() / 2) * (y1 + d1 / 2 - this.getY() - this.getD() / 2));
            // 如果距离小于两球半径之和,表示当前球被吃掉
            if (d < (d1 + this.getD()) / 2) {
//                    小球应该被吃掉
// 将当前球移出界面
                this.setX(-100);
                this.setY(-100);
                this.setD(0);
            }
        }
    }

    public void draw(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        // 设置剪辑区域为圆形
        g2d.setClip(new Ellipse2D.Float(this.x - this.d / 2, this.y - this.d / 2, this.d, this.d));
        // 在剪辑区域内绘制图片
        g2d.drawImage(this.image, this.x - this.d / 2, this.y - this.d / 2, this.d, this.d, null);
        g2d.dispose();
    }
}

SelectFrame类:添加游戏难度选择界面,球的移动数值初始化,背景音乐播放

Music audioPlayWave = new Music("E:\\ideal\\BallGamebjl\\src\\BalleatBall\\6.wav");
    JButton bt1 = new JButton();
    JButton bt2 = new JButton();
    JButton bt3 = new JButton();
    JButton bt4 = new JButton();

    public SelectFrame() {
        audioPlayWave.start();

        JPanel panel = new JPanel();
        this.setContentPane(panel);
        this.setTitle("选择难度");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(400, 400);
        this.setVisible(false);
        // 初始时隐藏选择难度的窗口
        bt1.setText("初级");
        bt2.setText("中级");
        bt3.setText("高级");
        bt4.setText("终极");
        bt1.setActionCommand("bt1");
        bt2.setActionCommand("bt2");
        bt3.setActionCommand("bt3");
        bt4.setActionCommand("bt4");
        bt1.addActionListener(this);
        bt2.addActionListener(this);
        bt3.addActionListener(this);
        bt4.addActionListener(this);
        panel.add(bt1);
        panel.add(bt2);
        panel.add(bt3);
        panel.add(bt4);
        panel.setLayout(new GridLayout(4, 1));
    }

    /**
     * 球的移动
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("bt1")) {
            dispose();
            audioPlayWave.stop();
            this.setVisible(false);
            Frame2 frame2 = new Frame2(2, 2, 1, 10);
        } else if (e.getActionCommand().equals("bt2")) {
            dispose();
            audioPlayWave.stop();
            this.setVisible(false);
            Frame2 frame2 = new Frame2(4, 2, 1, 10);
        } else if (e.getActionCommand().equals("bt3")) {
            dispose();
            audioPlayWave.stop();
            this.setVisible(false);
            Frame2 frame2 = new Frame2(6, 2, 1, 10);
        } else if (e.getActionCommand().equals("bt4")) {
            dispose();
            audioPlayWave.stop();
            this.setVisible(false);
            Frame2 frame2 = new Frame2(6, 2, 1, 8);
        }
    }

Frame2类:创建MyBall和OtherBall,多线程实现小球的移动,设置键盘监听器实现上下左右移动,设置倒计时增加游戏难度

OtherBall ob = new OtherBall();
    /**
     * 创建一个MyBall对象,表示玩家控制的球
     */
    MyBall mb = new MyBall(10, 300, 25, Color.pink, "E:\\ideal\\BallGamebjl\\src\\BalleatBall\\微信图片_20240111185319.jpg");
    /**
     * 创建一个JButton对象,用于重新开始游戏
     * JButton btn = new JButton("重新开始");
     * 创建一个标志,用于控制游戏的暂停和恢复
     */
    private boolean isAlive = true;
    Music audioPlayWave = new Music("E:\\ideal\\BallGamebjl\\src\\BalleatBall\\游戏开始音乐.wav");
    private GamePanel gamePanel;


    /**
     * 构造函数,初始化游戏窗口
     */
    public Frame2() {
    }

    public Frame2(int i, int k, int m, int j) {
        audioPlayWave.start();


        @SuppressWarnings("unused")
        int musicOpenLab = 1;


        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setFocusable(true);
        setSize(new Dimension(1000, 700));
        setLocationRelativeTo(null);
        setResizable(false);
        setTitle("大球吃小球");
        getContentPane().setBackground(Color.black);


        this.setVisible(true);

        // Initialize the timer label
                        timerLabel = new JLabel("Time left: 01:00", SwingConstants.CENTER);
                timerLabel.setForeground(Color.WHITE);
                timerLabel.setFont(new Font("Arial", Font.BOLD, 20));
                getContentPane().add(timerLabel, BorderLayout.NORTH);

                // Initialize the timer
                timer = new Timer(1000, e -> {
                    timeLeft--;
                    int minutes = timeLeft / 60;
                    int seconds = timeLeft % 60;
                    timerLabel.setText(String.format("Time left: %02d:%02d", minutes, seconds));
                    if (timeLeft <= 0) {
                        timer.stop();
                        isAlive = false;
                JOptionPane.showMessageDialog(Frame2.this, "时间到,游戏失败!", "游戏结束", JOptionPane.ERROR_MESSAGE);
                // showContinueGameDialog(i, k, m, j);
            }
        });
        timer.start();


        gamePanel = new GamePanel();
        add(gamePanel, BorderLayout.CENTER);

        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {

                // 根据按键改变玩家控制的球的移动方向
                Direction dir = mb.getDirection();
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_A:
                        dir = Direction.LEFT;
                        System.out.println("左键");
                        break;
                    case KeyEvent.VK_W:
                        dir = Direction.UP;
                        System.out.println("上键");
                        break;
                    case KeyEvent.VK_S:
                        dir = Direction.DOWN;
                        System.out.println("下键");
                        break;
                    case KeyEvent.VK_D:
                        dir = Direction.RIGHT;
                        System.out.println("右键");
                        break;
                    case KeyEvent.VK_LEFT:
                        dir = Direction.LEFT;
                        System.out.println("左键");
                        break;
                    case KeyEvent.VK_UP:
                        dir = Direction.UP;
                        System.out.println("上键");
                        break;
                    case KeyEvent.VK_DOWN:
                        dir = Direction.DOWN;
                        System.out.println("下键");
                        break;
                    case KeyEvent.VK_RIGHT:
                        dir = Direction.RIGHT;
                        System.out.println("右键");
                        break;
                    case KeyEvent.VK_SPACE:
                        isAlive = !isAlive;
                        requestFocus();
                        break;
                    default:
                        break;
                }
                if (dir != mb.getDirection()) {
                    mb.changeDir(dir);
                }


            }
        });


        // 启动一个新的线程,用于控制游戏的主要逻辑,  匿名内部类和线程池
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    if (isAlive) {
                        // 判断是否吃球,球的移动,以及游戏结束后的处理
                        ob.isEat(mb, i);
                        ob.isAlive();
                        gamePanel.repaint();
                        if (mb.getDiameter() != 0 && mb.getX() > 0 && mb.getX() < 1000 && mb.getY() > 0 && mb.getY() < 1000) {
                            //判断小球球在游戏界面内
                            ob.move(m);
                            mb.move(k);
                            repaint();
                            //请求重新绘制组件
                        } else {
                            // 停止计时器
                            timer.stop();
                            isAlive = false;

                            audioPlayWave.stop();
                            // showContinueGameDialog(i, k, m, j);
                            int choice = JOptionPane.showConfirmDialog(Frame2.this, "游戏失败,是否重新开始游戏?", "游戏结束", JOptionPane.YES_NO_OPTION);
                            if (choice == JOptionPane.YES_OPTION) {
                                // 创建新的 Frame2 对象来重新开始游戏
                                Frame2 newGame = new Frame2(i, k, m, j);
                                Frame2.this.dispose();
                            } else {

                                // 关闭当前窗口
                                Frame2.this.dispose();
                                // 创建一个新的选择难度的窗口
                                SelectFrame frame = new SelectFrame();
                                frame.setLocationRelativeTo(null); // 将窗口居中显示(可选)
                                frame.setVisible(true);
                            }
                        }
                        try {
                            Thread.sleep(j);//线程刷新,
                            //控制刷新率在游戏中非常重要,因为它影响到游戏的响应速度和流畅度。
                            // 如果刷新率设置得过高,可能会导致屏幕闪烁或游戏运行不稳定;如果设置得太低,则可能会影响游戏的响应性和视觉效果。
                            // 因此,根据游戏的需求和性能要求,合理设置线程的刷新率是必要的。
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }


                }
            }
        }).start();

        setVisible(true);
    }

Again类:实现游戏重新开始后的选择

 public Again() {
        audioPlayWave.start();
        @SuppressWarnings("unused")
        int musicOpenLab = 1;
        // 设置窗口关闭时的操作
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 设置窗口为可见
        this.setVisible(true);
        // 设置窗口的大小
        this.setSize(200, 200);
        // 设置按钮的动作命令,这些命令将在动作事件中使用
        bt1.setActionCommand("bt1");
        bt2.setActionCommand("bt2");
        // 为按钮添加动作监听器
        bt1.addActionListener(this);
        bt2.addActionListener(this);
        // 创建一个JPanel对象,并将其设置为窗口的内容面板
        JPanel panel = new JPanel();
        this.setContentPane(panel);
        // 将按钮添加到面板
        panel.add(bt1);
        panel.add(bt2);
        // 设置面板的布局为网格布局,1行2列
        panel.setLayout(new GridLayout(1, 2));
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("bt1")) {
            // 关闭当前窗口
            this.dispose();
            // 如果点击的是"重新开始"按钮,那么创建一个新的选择难度的窗口
            SelectFrame frame = new SelectFrame();
            // 确保选择难度的窗口是可见的
            frame.setVisible(true);
        }
        if (e.getActionCommand().equals("bt2")) {
            // 如果点击的是"结束游戏"按钮,那么结束程序
            System.exit(0);
        }
    }

七、代码静态扫描:(未成功修改,有的看不太懂),其余代码基本符合规范

八、尚待改进或者新的想法

1.球球的碰撞检测和吃球善待改进,有时候还没碰到大球就gameover了,此bug还没解决。

2.调整吞噬、成长等机制,确保游戏在不同阶段都有足够的挑战性。

3.增加玩家排名和排行榜,让玩家可以比较自己的分数和排名。

4.增加一个游戏内聊天功能,提高玩家互动感,

5.增加更多独特的关卡和模式,如团队战、生存模式等。

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值