如何解决按下关键游戏后获得反应时间
所以我正在制作一个游戏,在你看到屏幕上弹出的东西后记录你的反应时间,但我无法获得反应时间。我希望用户在看到蓝色球时按下向上箭头键,并且我想记录他们按下该按钮后的反应时间。
这是我的代码:
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”,我想在用户按下向上箭头后获取时间,但它不起作用。
如果有什么不明白或不够清楚的地方,我会尽量详细说明
解决方法
我想出了以下 GUI。
我想解释两个重要的原则。第一个是创建 GUI 是一个独立于更新 GUI 的过程。二是游戏过程是一个状态机。游戏分为六个不同的状态。以下是我为牢记这些状态而写的内容。
事件顺序
- 左键单击按钮
- 等待 2 - 4 秒以显示圆圈。
- 捕捉开始时间
- 左键单击按钮
- 捕捉结束时间。
- 计算并显示反应时间。
- 重复 1 - 6。
因此,对于 GUI,我创建了一个 JFrame
和三个 JPanels
;上部 JPanel
、绘图 JPanel
和按钮 JPanel
。
我通过调用 SwingUtilities
invokeLater
方法启动了 Swing 应用程序。此方法可确保在 Event Dispatch Thread 上创建和执行 Swing 组件。
JFrame
有一个默认的 BorderLayout
,我用来放置三个 JPanels
。 JFrame
方法调用必须按特定顺序执行。这是我用于所有 Swing 应用程序的顺序。
上方的 JPanel
包含说明和反应时间显示。 JTextArea
非常适合显示说明。我使用 JTextArea
将 JPanel
放在内部 FlowLayout
中,我使用 JPanel
将其放置在上部 BorderLayout
中。像这样嵌套布局是一种以逻辑方式组织 Swing 组件的好方法。
我将反应时间 Swing 组件放在另一个内部 JPanel
中,我将其放在上部 JPanel
中。
我创建了一个绘图 JPanel
,这样我就不必费心处理图像了。
按钮 JPanel
包含提交 JButton
。
我创建了两个控制器类。一个控制器类 ButtonListener
响应 JButton
左键单击。另一个控制器类 TimerListener
为绘制圆创建延迟。
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));
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));
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();
}
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。