我正在尝试用java制作一个简单的盒子点击游戏,但我卡住了

问题描述 投票:0回答:2

我正在制作一个盒子点击游戏,我希望盒子在 500x500 JFrame 上具有随机形状和位置。另外,我想添加一个分钟计时器,以便游戏在该分钟到期后结束。

这是我的代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.\*;

public class Main {

    int boxSize;
    int boxPosY;
    int boxPosX;
    int points = 0;
    boolean isLooping = false;

    public static void main(String\[\] args) {
        // A JFrame is a window where we can design our UI
        JFrame frame = new JFrame("My Game");
        frame.setSize(500, 500);
        frame.setLayout(null);

        // create a Button and a Label
        JButton startButton = new JButton("Click to start");
        JButton pointButton = new JButton("");
        pointButton.setVisible(false);
        JLabel pointLabel = new JLabel();

        // place and size for components
        // setBounds(x position, y position, width, height)
        startButton.setBounds(175, 200, 150, 50);
        pointButton.setBounds(100, 100, 100, 100);
        pointLabel.setBounds(0,0,200,50);
        pointLabel.setFont(new Font("Arial", Font.PLAIN, 32));
        pointLabel.setForeground(Color.BLUE);

        // add components to JFrame f
        frame.add(startButton);
        frame.add(pointButton);
        frame.add(pointLabel);

        // add event listener for button click

        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                pointButton.setVisible(true);
                startButton.setVisible(false);
                final int points = 0;
                pointLabel.setText("Points: " + points);  
            }
        });

        while (true) {
            pointButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    final int points = 0 + 1;
                    pointLabel.setText("Points: " + points);
                } 
            });
            break; // here to just break out of the loop not finished.
        }

        // make the frame visible
        frame.setVisible(true);

    }

    public void randomiz() {
        boxSize = (int)(Math.random() \* 100) + 1;
        boxPosY = (int)(Math.random() \* 500) + 1;
        boxPosX = (int)(Math.random() \* 500) + 1;
    }
}

我想制作一个简单的盒子点击游戏,但是当我点击一个盒子时,我想在我的

randomiz()
方法中使用我的
actionPerformed
方法生成并放置一个新的随机盒子。我该如何解决这个问题,还有,如何制作一分钟计时器以在一分钟到期后停止游戏。

java time jframe
2个回答
0
投票

这个...

    while (true) {
        pointButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                final int points = 0 + 1;
                pointLabel.setText("Points: " + points);
            } 
        });
        break; // here to just break out of the loop not finished.
    }

真是个坏主意。

Swing 是一个事件驱动的环境,也就是说,发生某些事情并且您对其做出响应(

ActionListener
就是一个例子)。

Swing 也是单线程的(并且不是线程安全的),因此您的

while-loop
存在阻塞事件调度线程的风险,这会导致您的 UI 无响应。

话虽如此,

break
语句无论如何都会导致循环在第一次迭代时退出。

总的来说,这是一个坏主意。

如果我这样做,我会从自定义绘画路线开始。

参见:

了解更多详情。

然后我会利用

Shape
s API,它提供了许多额外的支持,包括简化的绘画和命中框检测。

参见:

了解更多详情。

我还会利用 Swing

Timer
来管理问题的“定时”方面。有关更多详细信息,请参阅如何使用 Swing 计时器

您还需要某种方法来检测鼠标何时被单击,请参阅如何编写鼠标侦听器了解更多详细信息。

可运行的示例...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MainPane extends JPanel {
        private BoxPane boxPane;

        public MainPane() {
            setLayout(new BorderLayout());
            boxPane = new BoxPane();
            add(boxPane);

            JButton btn = new JButton("Start");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (boxPane.isRunning()) {
                        boxPane.stop();
                        btn.setText("Start");
                    } else {
                        boxPane.start();
                        btn.setText("Stop");
                    }
                }
            });

            add(btn, BorderLayout.SOUTH);
        }
    }

    public class BoxPane extends JPanel {
        private Rectangle boxy;
        private Random random = new Random();

        private Timer timer;

        public BoxPane() {
            timer = new Timer(5000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    randomiseLocation();
                }
            });
            timer.setInitialDelay(0);

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (boxy == null) {
                        return;
                    }
                    if (!boxy.contains(e.getPoint())) {
                        return;
                    }
                    // Box was clicked
                    randomiseLocation();
                    timer.restart();
                }
            });
        }

        protected void randomiseLocation() {
            int x = random.nextInt(getWidth() - boxy.width);
            int y = random.nextInt(getHeight() - boxy.height);
            boxy.x = x;
            boxy.y = y;
            repaint();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        public boolean isRunning() {
            return timer.isRunning();
        }

        public void start() {
            boxy = new Rectangle(0, 0, 20, 20);
            randomiseLocation();
            timer.start();
        }

        public void stop() {
            timer.stop();
            boxy = null;
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (boxy == null) {
                return;
            }
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            g2d.fill(boxy);
            g2d.setColor(Color.BLUE);
            g2d.draw(boxy);
            g2d.dispose();
        }

    }
}

但是等等,缺少什么?没错,我所做的一切都是为了你。 “一分钟超时”尚未实现,但我已经为您提供了实现它的基本解决方案,Swing

Timer

但是,如果您想显示倒计时时钟,那就有点复杂了。

您还需要使用

java.time
API,因为这可以让您轻松(准确)计算两个时间点之间的差异。

对于示例示例

您可能还想花一些时间研究观察者模式,因为这将为您提供向感兴趣的各方提供有关不同状态变化事件的反馈的方法(仅供参考:

ActionListener
是观察者的一个示例)


0
投票

这是另一个利用 Swing Timer 提供游戏持续时间和剩余时间显示的示例:

可运行示例:

请务必阅读代码中的注释:

public class ClickBox {

    /* Swing components declared a class members for so
       that they can be accessed class globlly:    */
    private javax.swing.JFrame frame;
    private javax.swing.JButton startButton;
    private javax.swing.JLabel pointLabel;

    private int boxWidth;
    private int boxHeight;
    private int boxPosY;
    private int boxPosX;
    private int points = 0;
    private javax.swing.Timer timer;
    private final int timeLimit = 60;  // Game time limit In seconds
    private int secondsRemaining = (timeLimit + 1); // Keeps track of seconds remaining:
    private int titleBarHeight;

    // Constructor:
    public ClickBox() {
        // Create Game Window:
        initializeForm();

        /* Add a Mouse Lister to JFrame to catch the MouseClick event
           in the case where the player misses clicking on a box. If
           he/she misses a box, then a point is removed:        */
        frame.addMouseListener(new java.awt.event.MouseAdapter() {
            @Override
            public void mouseClicked(java.awt.event.MouseEvent e) {
                if (timer != null && timer.isRunning()) {
                    points--;
                    pointLabel.setText(String.format("Points: %s%20s", points, "Seconds: " + secondsRemaining));
                }
            }
        });

        /* Add a Window Listener for JFrame to make use of the 
           `windowClosing` event in order to shut down the swing
           timer if it's running and the Window is abruptly closed:  */
        frame.addWindowListener(new java.awt.event.WindowAdapter() {
            @Override
            public void windowClosing(java.awt.event.WindowEvent e) {
                if (timer != null && timer.isRunning()) {
                    timer.stop();
                }
            }
        });
        
        /* Add a JFrame resize event to maintain center for the Points and 
           Seconds Remaining as well as set the location of the Start button 
           in the center of JFrame Window when it is resized.           */
        frame.addComponentListener(new java.awt.event.ComponentAdapter() {
            @Override
            public void componentResized(java.awt.event.ComponentEvent evt) {
                java.awt.Component c = (java.awt.Component) evt.getSource();
                pointLabel.setSize(frame.getWidth(), 30);
                startButton.setLocation(((frame.getWidth() / 2) - (150/2)), 
                                       ((frame.getHeight() / 2) - (30/2)) - 
                                       (titleBarHeight == 0 ? 35 : titleBarHeight));
            }
        });
    }

    public static void main(String[] args) {
        /* App started this way to avoid the need for statics
           unless we really want them:        */
        new ClickBox().startGame(args);

    }

    private void startGame(String[] args) {
        // Make the JFrame (Game) Window visible:
        java.awt.EventQueue.invokeLater(() -> {
            frame.setVisible(true);
            
            // Center Window in Screen
            frame.setLocationRelativeTo(null); 
            
            /* Get the JFrame's TitleBar height. This value is used
               in maintaining center for the Game `Start` Button: */
            titleBarHeight = frame.getInsets().top + frame.getInsets().bottom;
        });
    }

    private void initializeForm() {
        // Initialize a JFrame Window & set properties:
        frame = new javax.swing.JFrame("Click-Box Game - You have " + timeLimit + " seconds to click on Boxes!");
        frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
        frame.setAlwaysOnTop(true);
        frame.setSize(600, 600);
        frame.setLayout(null);

        // Initialize the Start Button & set properties:
        startButton = new javax.swing.JButton("Click to start");
        // Size and Placement for the Start Button:
        startButton.setSize(150, 30);
        startButton.setLocation(((frame.getWidth() / 2) - (150/2)), 
                               ((frame.getHeight() / 2) - (30/2)) - 20);

        // BOX (which is actually a JButton)
        javax.swing.JButton boxButton = new javax.swing.JButton("");
        boxButton.setVisible(false);
        /* Get & set the random Size and random Location 
           for 'first' box (boxButton JButton). This is
           later radomly continued within the boxButton's 
           MouseClick event:                          */
        randomize();
        boxButton.setSize(boxWidth, boxHeight);
        boxButton.setLocation(boxPosY, boxPosY);

        // Game label for points (score) and seconds remaining display:
        pointLabel = new javax.swing.JLabel();
        pointLabel.setHorizontalAlignment(javax.swing.JLabel.CENTER);
        pointLabel.setSize(frame.getWidth(), 30);
        pointLabel.setLocation(0, 0);
        pointLabel.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 32));
        pointLabel.setForeground(java.awt.Color.BLUE);

        // Add components to JFrame:
        frame.add(startButton); // Starts as visible:
        frame.add(boxButton);   // Starts as non-visible:
        frame.add(pointLabel);  // Starts as non-visible:

        // Add an ActionPerformed event for 'Start' button click:
        startButton.addActionListener((java.awt.event.ActionEvent e) -> {
            boxButton.setVisible(true);
            startButton.setVisible(false);
            points = 0;
            
            /* Setup and start the Game (Swing) Timer. The ActionEvent 
               is fired every one second (1000 milliseconds) and the 
               game duration is maintained with the `secondsRemaining`
               counter:                        */
            timer = new javax.swing.Timer(1000, (java.awt.event.ActionEvent evt) -> {
                secondsRemaining--;
                if (secondsRemaining <= 0) {
                    timer.stop();
                    pointLabel.setText("Game Over! You have " + points + " points!");
                    boxButton.setVisible(false);
                    startButton.setVisible(true);
                    secondsRemaining = (timeLimit + 1);
                }
                else {
                    pointLabel.setText(String.format("Points: %s%20s", points, "Seconds: " + secondsRemaining));
                }
            });
            timer.setInitialDelay(0); // No Timer Startup Delay:
            timer.start();            // Start the Game Timer:
        });

        // Add an ActionPerformed event for 'BOX' buttons:
        boxButton.addActionListener((java.awt.event.ActionEvent e) -> {
            points++;   // Add a point to the Score:
            // Update the Points Label in Game Window:
            pointLabel.setText(String.format("Points: %s%20s", points, "Seconds: " + secondsRemaining));
            /* Get & set the random Size and random Location 
               for next box (boxButton JButton) to be displayed.  */
            randomize();
            boxButton.setSize(boxWidth, boxHeight);
            boxButton.setLocation(boxPosY, boxPosY);
        });
    }

    /**
     * Generates a new Random Size and Location for the Box (`boxButton`) to 
     * be displayed within the Game Window. Sizes and Locations can change if
     * the Game Window is resized.
     */
    public void randomize() {
        boxWidth = 0;
        boxHeight = 0;
        int maxWidth = (frame.getWidth() - 10);
        int maxHeight = (frame.getHeight() - 10);

        // Create a box that fits in location x and y:
        while ((boxWidth < 10) || ((boxPosX + boxWidth) >= maxWidth)) {
            this.boxPosX = java.util.concurrent.ThreadLocalRandom.current().nextInt(10, maxWidth);
            this.boxWidth = java.util.concurrent.ThreadLocalRandom.current().nextInt(10, maxWidth);
        }

        while ((boxHeight < 10) || ((boxPosY + boxHeight) >= maxHeight)) {
            this.boxPosY = java.util.concurrent.ThreadLocalRandom.current().nextInt(10, maxHeight);
            this.boxHeight = java.util.concurrent.ThreadLocalRandom.current().nextInt(10, maxHeight);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.