首页 > 解决方案 > 按键游戏后获得反应时间

问题描述

因此,我正在制作一款游戏,它会在您看到屏幕上弹出某些内容后记录您的反应时间,但我无法获得该反应时间。我希望用户在看到蓝色球后按向上箭头键,并且我想在他们按下该按钮后记录他们的反应时间。

这是我的代码:

public class Game extends JPanel 
{

private JLabel start, main, time;
private ImageIcon constant, react;

final int width = 600;
final int height = 600;

private Timer replace;


private Random random;
private int randTime;

private long startTime;
private long stopTime;
private long reactionTime;
private Action upAction;


public Game()
{

  setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

  setPreferredSize(new Dimension(width, height));
  setBackground(Color.black);

  start = new JLabel("Click Up Arrow when you see a blue ball");
  start.setForeground(Color.white);
  start.setAlignmentX(Component.CENTER_ALIGNMENT);
  add(start);
 
  constant = new ImageIcon("constantCircle.png");
  main = new JLabel(constant);
  main.setAlignmentX(Component.CENTER_ALIGNMENT);


  randomTime();
  replace = new Timer(randTime, timeListener);
  startTime = System.currentTimeMillis();
  replace.setRepeats(false);
  replace.start();    
  add(main);

  time = new JLabel("0");

  time.getInputMap().put(KeyStroke.getKeyStroke("UP"), "upAction");
  time.getActionMap().put("upAction", upAction);


  add(time);

}


public void randomTime()
{
  random = new Random();
  int max = 8000;
  randTime = random.nextInt(max);

}


ActionListener timeListener = new ActionListener()
{
  public void actionPerformed (ActionEvent e)
  {
    react = new ImageIcon("reactCircle.png");
    main.setIcon(react);     
  }
};

public class UpAction extends AbstractAction
{
  public void actionPerformed(ActionEvent e)
  {
    stopTime = System.currentTimeMillis();
    reactionTime = stopTime - startTime;
    time.setText("" + reactionTime);
  
  }
}  
}

我使用 System.currentTimeMillis 设置了一个“startTime”来获取球变蓝后的时间,但我不确定这是否是正确的方法。

我还在“UpAction”类中设置了一个“stopTime”,一旦用户按下向上箭头,我想在其中获取时间,但它不起作用。

如果有什么没有意义或不够清楚,我会尽力详细说明

标签: javaswingjframejpanelkey-bindings

解决方案


我想出了以下GUI。

反应时间游戏

我想解释两个重要的原则。首先是创建 GUI 是一个独立于更新 GUI 的过程。二是游戏过程是一个状态机。游戏处于六个不同的状态。这是我为牢记州而写的内容。

事件顺序

  1. 左键单击按钮
  2. 等待 2 - 4 秒以显示圆圈。
  3. 捕捉开始时间
  4. 左键单击按钮
  5. 捕捉结束时间。
  6. 计算并显示反应时间。
  7. 重复 1 - 6。

所以,对于 GUI,我创建了一个JFrame和三个JPanels;鞋面JPanel、绘图JPanel和按钮JPanel

我通过调用该SwingUtilities invokeLater方法启动了 Swing 应用程序。此方法确保在Event Dispatch Thread上创建和执行 Swing 组件。

JFrame有一个默认的BorderLayout,我用来放置三个JPanelsJFrame方法调用必须按特定顺序执行。这是我用于所有 Swing 应用程序的顺序。

上部JPanel包含说明和反应时间显示。AJTextArea非常适合显示说明。我使用 a 将内部放入JTextArea内部,然后JPanel使用 aFlowLayout将其放置在鞋面JPanelBorderLayout。像这样的嵌套布局是一种以逻辑方式组织 Swing 组件的好方法。

我将反应时间 Swing 组件放在另一个内部JPanel,我放置在鞋面中JPanel

我创建了一幅画JPanel,所以我不必为图像而烦恼。

该按钮JPanel持有 Submit JButton

我创建了两个控制器类。一个控制器类 ,ButtonListener响应JButton左键单击。另一个控制器类,TimerListener,创建绘制圆的延迟。

state 变量允许我用ButtonListener相同的ActionListener. 如果您愿意,您可以编写单独ActionListener的类,每个函数一个。

通过将我的代码分成视图和控制器类,我可以将我的关注点分开并一次专注于应用程序的一部分。

这是完整的可运行代码。我将所有类都设为内部类,因此我可以将此代码作为一个块发布。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class ReactionTimeGame implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new ReactionTimeGame());
    }
    
    private long reactionTime;
    
    private DrawingPanel drawingPanel;
    
    private JTextField reactionTimeField;
    
    public ReactionTimeGame() {
        this.reactionTime = 0L;
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Reaction Time Game");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(createUpperPanel(), BorderLayout.BEFORE_FIRST_LINE);
        this.drawingPanel = new DrawingPanel();
        frame.add(drawingPanel, BorderLayout.CENTER);
        frame.add(createButtonPanel(), BorderLayout.AFTER_LAST_LINE);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JPanel createUpperPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        JPanel innerPanel = new JPanel(new FlowLayout());
        
        String instructions = "This game will test your reaction time. To play "
                + "the game, left-click on the Submit button.  After a random time "
                + "from 2 - 4 seconds, a circle will appear.  Left-click the "
                + "Submit button again.  Your reaction time will be displayed "
                + "above where the circle was.\n\n"
                + "Left-click the Submit button to start each round of the game.";
        JTextArea textArea = new JTextArea(7, 40);
        textArea.setEditable(false);
        textArea.setText(instructions);
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        innerPanel.add(textArea);
        
        panel.add(innerPanel, BorderLayout.BEFORE_FIRST_LINE);
        
        innerPanel = new JPanel(new FlowLayout());
        
        JLabel label = new JLabel("Reaction Time:");
        innerPanel.add(label);
        
        reactionTimeField = new JTextField(5);
        reactionTimeField.setEditable(false);
        updateReactionTime();
        innerPanel.add(reactionTimeField);
        
        label = new JLabel("seconds");
        innerPanel.add(label);
        
        panel.add(innerPanel, BorderLayout.AFTER_LAST_LINE);
        
        return panel;
    }
    
    private JPanel createButtonPanel() {
        JPanel panel = new JPanel(new FlowLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        JButton button = new JButton("Submit");
        button.addActionListener(new ButtonListener());
        panel.add(button);
        
        return panel;
    }
    
    public void setReactionTime(long reactionTime) {
        this.reactionTime = reactionTime;
    }

    public void drawCircle() {
        drawingPanel.setDrawCircle(true);
        drawingPanel.repaint();
    }
    
    public void eraseCircle() {
        drawingPanel.setDrawCircle(false);
        drawingPanel.repaint();
    }
    
    public void updateReactionTime() {
        double time = 0.001 * reactionTime;
        reactionTimeField.setText(String.format("%.3f", time));
    }
    
    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private boolean drawCircle;
        
        public DrawingPanel() {
            this.drawCircle = false;
            this.setPreferredSize(new Dimension(300, 300));
        }

        public void setDrawCircle(boolean drawCircle) {
            this.drawCircle = drawCircle;
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            if (drawCircle) {
                int centerX = getWidth() / 2;
                int centerY = getHeight() / 2;
                int radius = Math.min(getWidth(), getHeight()) * 9 / 20;
                int diameter = radius + radius;
                g.setColor(Color.MAGENTA);
                g.fillOval(centerX - radius, centerY - radius, diameter, diameter);
            }
        }
        
    }
    
    public class ButtonListener implements ActionListener {
        
        private int state;
        
        private long startTime;
        
        private final Random random;
        
        private Timer timer;
        
        public ButtonListener() {
            this.state = 1;
            this.random = new Random();
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            switch (state) {
            case 1:
                int delay = random.nextInt(2000) + 2000;
                timer = new Timer(delay, new TimerListener(this));
                timer.start();
                state = 2;
                break;
            case 2:
                setEndTime(System.currentTimeMillis());
                eraseCircle();
                state = 1;
                break;
            }
        }

        public int getState() {
            return state;
        }

        public void setStartTime(long startTime) {
            this.startTime = startTime;
        }

        public void setEndTime(long endTime) {
            long elapsedTime = endTime - startTime;
            setReactionTime(elapsedTime);
            updateReactionTime();
        }
        
    }
    
    public class TimerListener implements ActionListener {
        
        private final ButtonListener listener;

        public TimerListener(ButtonListener listener) {
            this.listener = listener;
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            Timer timer = (Timer) event.getSource();
            timer.stop();
            
            if (listener.getState() == 2) {
                listener.setStartTime(System.currentTimeMillis());
                drawCircle();
            }
        }
        
    }

}

推荐阅读