我已經在下面的代碼中作業了很長一段時間,但我似乎無法讓 keyListeners 作業。我試過移動 setFocusable(true)、requestFocus() 和 addKeyListener(this),但這并沒有什么不同。
而且,在任何人提到它之前,是的,如果到目前為止我在所有閱讀中都學到了一件事,互聯網似乎一致認為鍵系結更勝一籌。問題是,這是一個學校作業,所以我必須按照書本去做。我應該怎么做才能激活 KeyListener?
public class SnakeGUI extends JComponent implements KeyListener {
private static JTextField timeKeeper;
private static JTextField scoreKeeper;
private static int time;
private static int score;
private static boolean playing;
private static SnakeSettings settings;
private static Snake snake;
private static SnakePanel snakePanel;
private static Timer gameTimer;
private static Timer moveTimer;
public static void main(String[] args) {
// @author Every second, the displayed time ticks up
TimerTask uptick = new TimerTask() {
public void run() {
time = 1;
scoreKeeper.setText(Integer.toString(score));
timeKeeper.setText(Integer.toString(time));
}
};
// @author Depending on difficulty, the snake moves at different speeds.
TimerTask move = new TimerTask() {
public void run() {
snake.move();
playing = ! snake.isGameOver(settings.getWidth(), settings.getHeight());
if (! playing) {
// @author Clear timers until next game.
gameTimer.cancel();
moveTimer.cancel();
}
else {
snakePanel.setDisplay(snake);
}
}
};
//@author Use defaults settings first time around.
settings = new SnakeSettings();
SnakeSettingsPanel settingsPanel;
JFrame jf;
SnakeGUI gui;
// @author Alternate between game/settings elements till they quit.
while (true) {
settingsPanel = new SnakeSettingsPanel(settings);
jf = new JFrame();
jf.add(settingsPanel);
jf.pack();
jf.setTitle("Snake");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
// @author Wait until they press play...
while (! settingsPanel.getPlay()) {
try {
Thread.sleep(25);
} catch (Exception e) {
System.out.println(e);
}
}
// @author Then, update settings accordingly.
settings = settingsPanel.getSettings();
gui = new SnakeGUI(settings);
// @author Remove settingspanel, add game gui.
jf.dispose();
jf = new JFrame();
jf.add(gui);
jf.pack();
jf.setTitle("Snake");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
// @author Begin a new game.
playing = true;
time = 0;
score = 0;
snake = new Snake(new Point(settings.getWidth()/2, settings.getHeight()/2));
gameTimer = new Timer();
moveTimer = new Timer();
gameTimer.schedule(uptick, 1000, 1000);
// @author Set the delay based on the game speed.
if (Speed.SLOW == settings.getSpeed()) {
moveTimer.schedule(move, 750, 750);
}
else if (Speed.MEDIUM == settings.getSpeed()) {
moveTimer.schedule(move, 500, 500);
}
else {
moveTimer.schedule(move, 333, 333);
}
// @author Wait until the game ends.
while (playing) {
try {
Thread.sleep(25);
} catch (Exception e) {
System.out.println(e);
}
}
jf.dispose();
}
}
public SnakeGUI(SnakeSettings set) {
addKeyListener(this);
setFocusable(true);
requestFocus();
setLayout(new GridBagLayout());
JLabel tm = new JLabel("Time:");
JLabel sc = new JLabel("Score:");
timeKeeper = new JTextField(4);
scoreKeeper = new JTextField(4);
timeKeeper.setText("0");
scoreKeeper.setText("0");
timeKeeper.setEditable(false);
scoreKeeper.setEditable(false);
JPanel jp = new JPanel();
jp.setLayout(new FlowLayout());
jp.add(tm);
jp.add(timeKeeper);
jp.add(sc);
jp.add(scoreKeeper);
snakePanel = new SnakePanel(set);
GridBagConstraints p = new GridBagConstraints();
p.gridx = 0;
p.gridy = 0;
add(jp, p);
p.gridy = 1;
add(snakePanel, p);
setVisible(true);
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
System.out.println(1); // For testing purposes
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println(1);
snake.changeDirection(SnakeInterface.Direction.Left);
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println(2); // For testing purposes
snake.changeDirection(SnakeInterface.Direction.Right);
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
snake.changeDirection(SnakeInterface.Direction.Down);
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
snake.changeDirection(SnakeInterface.Direction.Up);
}
}
}
uj5u.com熱心網友回復:
好吧,這...
// @author Alternate between game/settings elements till they quit.
while (true) {
settingsPanel = new SnakeSettingsPanel(settings);
jf = new JFrame();
jf.add(settingsPanel);
jf.pack();
jf.setTitle("Snake");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
// @author Wait until they press play...
while (! settingsPanel.getPlay()) {
try {
Thread.sleep(25);
} catch (Exception e) {
System.out.println(e);
}
}
// @author Then, update settings accordingly.
settings = settingsPanel.getSettings();
gui = new SnakeGUI(settings);
// @author Remove settingspanel, add game gui.
jf.dispose();
jf = new JFrame();
jf.add(gui);
jf.pack();
jf.setTitle("Snake");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
// @author Begin a new game.
playing = true;
time = 0;
score = 0;
snake = new Snake(new Point(settings.getWidth()/2, settings.getHeight()/2));
gameTimer = new Timer();
moveTimer = new Timer();
gameTimer.schedule(uptick, 1000, 1000);
// @author Set the delay based on the game speed.
if (Speed.SLOW == settings.getSpeed()) {
moveTimer.schedule(move, 750, 750);
}
else if (Speed.MEDIUM == settings.getSpeed()) {
moveTimer.schedule(move, 500, 500);
}
else {
moveTimer.schedule(move, 333, 333);
}
// @author Wait until the game ends.
while (playing) {
try {
Thread.sleep(25);
} catch (Exception e) {
System.out.println(e);
}
}
jf.dispose();
}
太瘋狂了,再加上使用,static你很快就會遇到很多問題,其中任何一個都很容易在你面前爆炸。
Swing 不是執行緒安全的,因此在執行緒之間冒臟狀態的風險(臟讀/寫)的一部分,您冒著 UI 在資料更新時嘗試執行繪制程序的風險 - 嘗試除錯它。
Swing 是一個事件驅動的環境,也就是說,發生了一些事情并且您對其做出回應,這與程式驅動的作業流不同,例如控制臺應用程式,其中每個陳述句都從最后一個陳述句開始。
下面是一個過于簡化的版本,它有一個“選單”和“游戲”面板,你可以簡單地在它們之間切換,使用一個CardLayout和一系列的“觀察者”
一個“技巧”......實際上,這不是一個“技巧”,它是一個徹頭徹尾的骯臟黑客,是當“移動”計時器滴答作響時,我們再次請求焦點。同樣,這是 hack,如果您希望用戶與之互動的 UI 上有其他控制元件,那么這將導致您無休止的問題,正如我已經說過的,KeyListener這不是解決問題的合適方法。
相反,您應該使用:
- 如何使用搖擺計時器
- 鍵系結 API
對于稍微不那么糟糕的做事方式......
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.time.Duration;
import java.time.Instant;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
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 CardLayout cardLayout;
private MenuPane menuPane;
private GamePane gamePane;
public MainPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
menuPane = new MenuPane(new MenuPane.Observer() {
@Override
public void didStartGame(MenuPane source) {
gamePane.start();
cardLayout.show(MainPane.this, "game");
}
});
gamePane = new GamePane(new GamePane.Observer() {
@Override
public void gameDidEnd(GamePane source, int score) {
source.stop();
cardLayout.show(MainPane.this, "menu");
}
});
add(menuPane, "menu");
add(gamePane, "game");
}
}
public class MenuPane extends JPanel {
public interface Observer {
public void didStartGame(MenuPane source);
}
public MenuPane(Observer observer) {
setLayout(new GridBagLayout());
JPanel contentPane = new JPanel(new GridLayout(-1, 1));
JButton startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
observer.didStartGame(MenuPane.this);
}
});
contentPane.add(startButton);
add(contentPane);
}
}
public class GamePane extends JPanel {
public interface Observer {
public void gameDidEnd(GamePane source, int score);
}
public enum Direction {
UP, DOWN, LEFT, RIGHT;
}
private Set<Direction> keyManager = new TreeSet<>();
private Timer gameTimer;
private int score;
private Instant startedAt;
private Rectangle player = new Rectangle(195, 195, 10, 10);
public GamePane(Observer observer) {
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
keyManager.add(Direction.UP);
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
keyManager.add(Direction.DOWN);
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
keyManager.add(Direction.LEFT);
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
keyManager.add(Direction.RIGHT);
}
}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
keyManager.remove(Direction.UP);
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
keyManager.remove(Direction.DOWN);
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
keyManager.remove(Direction.LEFT);
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
keyManager.remove(Direction.RIGHT);
}
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void start() {
stop();
keyManager.clear();
startedAt = Instant.now();
score = 0;
gameTimer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//scoreKeeper.setText(Integer.toString(score));
//timeKeeper.setText(Integer.toString(time));
move();
}
});
gameTimer.start();
}
public void stop() {
if (gameTimer != null) {
gameTimer.stop();
}
}
protected void move() {
requestFocusInWindow();
int delta = 1;
if (keyManager.contains(Direction.UP)) {
player.y -= delta;
}
if (keyManager.contains(Direction.DOWN)) {
player.y = delta;
}
if (keyManager.contains(Direction.LEFT)) {
player.x -= delta;
}
if (keyManager.contains(Direction.RIGHT)) {
player.x = delta;
}
if (player.y < 0) {
player.y = 0;
} else if (player.y player.height >= getHeight()) {
player.y = getHeight() - player.height;
}
if (player.x < 0) {
player.x = 0;
} else if (player.x player.width >= getWidth()) {
player.x = getWidth() - player.width;
}
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.fill(player);
g2d.setColor(Color.BLACK);
FontMetrics fm = g2d.getFontMetrics();
String text = Integer.toString(score);
g2d.drawString(text, 16, fm.getAscent());
text = "---";
if (startedAt != null) {
text = Long.toString(Duration.between(startedAt, Instant.now()).toSeconds());
}
g2d.drawString(text, getWidth() - 16 - fm.stringWidth(text), fm.getAscent());
g2d.dispose();
}
}
}
哦,還有關于 的話題static,不要這樣用,太容易出錯了。相反,使用依賴注入(即將資訊傳遞給方法或建構式)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/381311.html
