回答編集履歴

3

showAndFocus

2024/05/24 11:11

投稿

jimbe
jimbe

スコア13170

test CHANGED
@@ -30,8 +30,8 @@
30
30
  PausePanel pausePanel = new PausePanel(gamePanel::resume); //esc が押されたら gamePanel.resume() を呼ぶ
31
31
  FinishedPanel finishedPanel = new FinishedPanel(gamePanel::start); //enter が押されたら gamePane.start() を呼ぶ
32
32
 
33
- gamePanel.setPauseListener(() -> pausePanel.setVisible(true)); //esc が押されたら pausePanel を表示
33
+ gamePanel.setPauseListener(pausePanel::showAndFocus); //esc が押されたら pausePanel.showAndFocus()呼ぶ
34
- gamePanel.setFinishedListener(finishedPanel::show); //finish したら finishedPanel.show(String,int) を呼ぶ
34
+ gamePanel.setFinishedListener(finishedPanel::showAndFocus); //finish したら finishedPanel.showAndFocus(String,int) を呼ぶ
35
35
 
36
36
  setLayout(new OverlayLayout(getContentPane())); //全てを重ねる
37
37
  add(finishedPanel); //一番上
@@ -144,13 +144,11 @@
144
144
  setBackground(bg);
145
145
  setFocusable(true);
146
146
  setVisible(false);
147
-
148
- addComponentListener(new ComponentAdapter() {
149
- @Override
147
+ }
148
+
150
- public void componentShown(ComponentEvent e) {
149
+ void showAndFocus() {
150
+ setVisible(true);
151
- requestFocus();
151
+ requestFocus();
152
- }
153
- });
154
152
  }
155
153
 
156
154
  protected JLabel addLabel(String text, Color fg, Font font, Object constraints) {
@@ -211,10 +209,10 @@
211
209
  addKeyEvent(KeyEvent.VK_ENTER, KeyAction.PRESSED, restartListener);
212
210
  }
213
211
 
214
- void show(String message, int score) {
212
+ void showAndFocus(String message, int score) {
215
213
  messageLabel.setText(message);
216
214
  scoreLabel.setText("Score: " + score);
217
- setVisible(true);
215
+ showAndFocus();
218
216
  }
219
217
  }
220
218
 

2

FinishedPanel に GAME OVER/Victrory 表示を追加、OverlapPanel 追加、StringDrawer 追加等

2024/05/23 17:06

投稿

jimbe
jimbe

スコア13170

test CHANGED
@@ -13,7 +13,7 @@
13
13
  import java.awt.*;
14
14
  import java.awt.event.*;
15
15
  import java.util.Random;
16
- import java.util.function.Consumer;
16
+ import java.util.function.BiConsumer;
17
17
 
18
18
  import javax.swing.*;
19
19
 
@@ -31,10 +31,9 @@
31
31
  FinishedPanel finishedPanel = new FinishedPanel(gamePanel::start); //enter が押されたら gamePane.start() を呼ぶ
32
32
 
33
33
  gamePanel.setPauseListener(() -> pausePanel.setVisible(true)); //esc が押されたら pausePanel を表示
34
- gamePanel.setFinishedListener(finishedPanel::setScoreAndVisible); //finish したら finishedPanel.setScoreAndVisible(int) を呼ぶ
34
+ gamePanel.setFinishedListener(finishedPanel::show); //finish したら finishedPanel.show(String,int) を呼ぶ
35
-
36
- Container contentPane = getContentPane();
35
+
37
- contentPane.setLayout(new OverlayLayout(contentPane)); //全てを重ねる
36
+ setLayout(new OverlayLayout(getContentPane())); //全てを重ねる
38
37
  add(finishedPanel); //一番上
39
38
  add(pausePanel);
40
39
  add(gamePanel); //一番下
@@ -44,11 +43,29 @@
44
43
  }
45
44
  }
46
45
 
46
+ class StringDrawer {
47
+ private Font font;
48
+ private FontMetrics fontMetrics;
49
+
50
+ StringDrawer(JComponent comp, Font font) {
51
+ this.font = font;
52
+ fontMetrics = comp.getFontMetrics(font);
53
+ }
54
+ void drawInCenter(Graphics g, String s, JComponent comp) {
55
+ int x = (comp.getWidth() - fontMetrics.stringWidth(s)) / 2;
56
+ int y = (comp.getHeight() - fontMetrics.getHeight()) / 2;
57
+ draw(g, s, x, y);
58
+ }
59
+ void draw(Graphics g, String s, int x, int y) {
60
+ g.setFont(font);
61
+ g.drawString(s, x, y + fontMetrics.getAscent());
62
+ }
63
+ }
64
+
47
65
  class GamePanel extends JPanel {
48
- private Consumer<Integer> finishedListener;
66
+ private BiConsumer<String,Integer> finishedListener;
49
67
  private Runnable pauseListener;
50
- private Font font1, font2;
68
+ private StringDrawer sd1, sd2;
51
- private FontMetrics fontMetrics1, fontMetrics2;
52
69
  private Timer timer;
53
70
  private Random random = new Random();
54
71
  private int keycode, value, bar;
@@ -60,10 +77,8 @@
60
77
  setFocusable(true);
61
78
  setBackground(Color.CYAN); //重なりを分かり易くするため色を付けてみる
62
79
 
63
- font1 = getFont();
64
- fontMetrics1 = getFontMetrics(font1);
80
+ sd1 = new StringDrawer(this, getFont());
65
- font2 = font1.deriveFont(Font.BOLD, 50f);
81
+ sd2 = new StringDrawer(this, getFont().deriveFont(Font.BOLD, 50f));
66
- fontMetrics2 = getFontMetrics(font2);
67
82
 
68
83
  addKeyListener(new KeyAdapter() {
69
84
  @Override
@@ -85,7 +100,7 @@
85
100
  });
86
101
  }
87
102
 
88
- void setFinishedListener(Consumer<Integer> listener) {
103
+ void setFinishedListener(BiConsumer<String,Integer> listener) {
89
104
  finishedListener = listener;
90
105
  }
91
106
  void setPauseListener(Runnable listener) {
@@ -103,7 +118,7 @@
103
118
  timer = new Timer(50, e -> {
104
119
  if(value == 0 || value == 100) { //終わり判定
105
120
  timer.stop();
106
- if(finishedListener != null) finishedListener.accept(value); //テキトウにスコアとして value を渡してみる
121
+ if(finishedListener != null) finishedListener.accept(value==0?"GAME OVER":"Victory", value); //テキトウに渡してみる
107
122
  return;
108
123
  }
109
124
  if(keycode == KeyEvent.VK_LEFT) value -= 1;
@@ -118,88 +133,16 @@
118
133
  public void paintComponent(Graphics g) {
119
134
  super.paintComponent(g);
120
135
 
121
- String s = "=".repeat(bar);
136
+ sd1.draw(g, "=".repeat(bar), 10, 10);
122
- int x = 0 + 10;
123
- int y = fontMetrics1.getAscent() + 10;
124
- g.setFont(font1);
125
- g.drawString(s, x, y);
126
-
127
- s = "← " + value + " →";
137
+ sd2.drawInCenter(g, "← " + value + " →", this);
128
- x = (getWidth() - fontMetrics2.stringWidth(s)) / 2;
129
- y = (getHeight() - fontMetrics2.getHeight()) / 2 + fontMetrics2.getAscent();
130
- g.setFont(font2);
131
- g.drawString(s, x, y);
132
- }
138
+ }
133
- }
139
+ }
134
-
140
+
135
- class FinishedPanel extends JPanel {
141
+ abstract class OverlapPanel extends JPanel {
136
- private JLabel scoreLabel;
142
+ OverlapPanel(Color bg) {
137
-
138
- FinishedPanel(Runnable restartListener) {
139
143
  super(new GridBagLayout());
140
- if(restartListener == null) throw new IllegalArgumentException("Required restartListener");
141
- setBackground(new Color(0,0,0,180)); //半透明
142
-
143
- Font font = new Font("Verdana", Font.BOLD, 18);
144
-
145
- GridBagConstraints gbc = new GridBagConstraints();
146
- gbc.gridx = 0;
147
-
148
- scoreLabel = new JLabel();
149
- scoreLabel.setForeground(Color.WHITE);
150
- scoreLabel.setFont(font);
151
- add(scoreLabel, gbc);
152
-
153
- add(Box.createVerticalStrut(30), gbc);
154
-
155
- JLabel restartLabel = new JLabel("Press ENTER to restart");
156
- restartLabel.setForeground(Color.GREEN);
157
- restartLabel.setFont(font);
158
- add(restartLabel, gbc);
159
-
160
- addKeyListener(new KeyAdapter() {
161
- @Override
162
- public void keyPressed(KeyEvent e) {
163
- if(e.getKeyCode() == KeyEvent.VK_ENTER) {
164
- setVisible(false);
144
+ setBackground(bg);
165
- restartListener.run();
166
- }
167
- }
168
- });
169
-
170
- setVisible(false);
171
- }
172
-
173
- void setScoreAndVisible(int score) {
174
- scoreLabel.setText("Score: " + score);
175
- setVisible(true);
176
- requestFocus();
177
- }
178
- }
179
-
180
- class PausePanel extends JPanel {
181
- PausePanel(Runnable resumeListener) {
182
- super(new BorderLayout());
183
- if(resumeListener == null) throw new IllegalArgumentException("Required resumeListener");
184
- setBackground(new Color(100,100,100,180)); //半透明
185
145
  setFocusable(true);
186
-
187
- JLabel label = new JLabel("PAUSE");
188
- label.setHorizontalAlignment(SwingConstants.CENTER);
189
- label.setForeground(Color.YELLOW);
190
- label.setFont(new Font("Monospaced", Font.BOLD, 25));
191
- add(label, BorderLayout.CENTER);
192
-
193
- addKeyListener(new KeyAdapter() {
194
- @Override
195
- public void keyReleased(KeyEvent e) {
196
- if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
197
- setVisible(false);
198
- resumeListener.run();
199
- }
200
- }
201
- });
202
-
203
146
  setVisible(false);
204
147
 
205
148
  addComponentListener(new ComponentAdapter() {
@@ -209,7 +152,81 @@
209
152
  }
210
153
  });
211
154
  }
155
+
156
+ protected JLabel addLabel(String text, Color fg, Font font, Object constraints) {
157
+ JLabel label = new JLabel(text);
158
+ label.setForeground(fg);
159
+ label.setFont(font);
160
+ add(label, constraints);
161
+ return label;
162
+ }
163
+
164
+ protected enum KeyAction {
165
+ PRESSED {
166
+ KeyListener createKeyListener(JComponent comp, int keyCode, Runnable listener) {
167
+ return new KeyAdapter() {
168
+ @Override
169
+ public void keyPressed(KeyEvent e) { if(e.getKeyCode() == keyCode) action(comp, listener); }
170
+ };
171
+ }
172
+ },
173
+ RELEASED {
174
+ KeyListener createKeyListener(JComponent comp, int keyCode, Runnable listener) {
175
+ return new KeyAdapter() {
176
+ @Override
177
+ public void keyReleased(KeyEvent e) { if(e.getKeyCode() == keyCode) action(comp, listener); }
178
+ };
179
+ }
180
+ };
181
+
182
+ abstract KeyListener createKeyListener(JComponent comp, int keyCode, Runnable listener);
183
+ private static void action(JComponent comp, Runnable listener) {
184
+ comp.setVisible(false);
185
+ listener.run();
186
+ }
187
+ }
188
+
189
+ protected void addKeyEvent(int keyCode, KeyAction keyAction, Runnable listener) {
190
+ addKeyListener(keyAction.createKeyListener(this, keyCode, listener));
191
+ }
192
+ }
193
+
194
+ class FinishedPanel extends OverlapPanel {
195
+ private JLabel messageLabel, scoreLabel;
196
+
197
+ FinishedPanel(Runnable restartListener) {
198
+ super(new Color(0,0,0,180)); //半透明
199
+
200
+ Font font = new Font("Verdana", Font.BOLD, 18);
201
+
202
+ GridBagConstraints gbc = new GridBagConstraints();
203
+ gbc.gridx = 0;
204
+
205
+ messageLabel = addLabel(null, Color.WHITE, font, gbc);
206
+ add(Box.createVerticalStrut(50), gbc);
207
+ scoreLabel = addLabel(null, Color.WHITE, font, gbc);
208
+ add(Box.createVerticalStrut(30), gbc);
209
+ addLabel("Press ENTER to restart", Color.GREEN, font, gbc);
210
+
211
+ addKeyEvent(KeyEvent.VK_ENTER, KeyAction.PRESSED, restartListener);
212
+ }
213
+
214
+ void show(String message, int score) {
215
+ messageLabel.setText(message);
216
+ scoreLabel.setText("Score: " + score);
217
+ setVisible(true);
218
+ }
219
+ }
220
+
221
+ class PausePanel extends OverlapPanel {
222
+ PausePanel(Runnable resumeListener) {
223
+ super(new Color(100,100,100,180)); //白っぽい半透明
224
+
225
+ addLabel("PAUSE", Color.YELLOW, new Font("Monospaced", Font.BOLD, 25), null);
226
+
227
+ addKeyEvent(KeyEvent.VK_ESCAPE, KeyAction.RELEASED, resumeListener);
228
+ }
212
229
  }
213
230
  ```
214
231
  ![一時停止時画面](https://ddjkaamml8q8x.cloudfront.net/questions/2024-05-23/e2c13bd9-d3d3-473d-be16-35747618d116.png)
215
- ![フィニッシュ時画面](https://ddjkaamml8q8x.cloudfront.net/questions/2024-05-23/f706f59d-59c5-4bca-b69b-8ec720547064.png)
232
+ ![フィニッシュ時画面(Victory)](https://ddjkaamml8q8x.cloudfront.net/questions/2024-05-24/18664310-69c1-4dcf-959b-aa8ea788618c.png)

1

PanelsFrame.java を追加

2024/05/22 19:59

投稿

jimbe
jimbe

スコア13170

test CHANGED
@@ -1,2 +1,215 @@
1
1
  Swing の表示は全て paintComponent で行います。
2
2
  キー操作によって表示を変えるのなら、表示要因を変更したうえで repaint 等を呼んで Swing に表示を更新して貰う形になります。
3
+
4
+ ---
5
+ 質問へのコメントで提案させて頂きましたが、ゲームパネル・フィニッシュパネル・一時停止パネルを用意して重ねて置き、状況によって表示を切り替える形を作って見ました。
6
+ こうするとゲームパネルの paintComponent 等から全体の状況別の処理切替が無くなります。
7
+
8
+ 一応ゲームパネルはそれっぽく動いている状態を見れるように、左上に (Timer が動いていることを示す)ランダムに動き続けるバーと、左右矢印キーで数値を増減できる数値の表示を置き、数値が 0 か 100 になったらフィニッシュとしてその数値をスコアとして表示するようにしてみました。
9
+ フィニッシュ後は ENTER で再スタート、ゲーム中は ESC で一時停止/復帰します。
10
+
11
+ PanelsFrame.java
12
+ ```java
13
+ import java.awt.*;
14
+ import java.awt.event.*;
15
+ import java.util.Random;
16
+ import java.util.function.Consumer;
17
+
18
+ import javax.swing.*;
19
+
20
+ public class PanelsFrame extends JFrame {
21
+ public static void main(String[] args) {
22
+ SwingUtilities.invokeLater(() -> new PanelsFrame().setVisible(true));
23
+ }
24
+
25
+ PanelsFrame() {
26
+ super("PanelsFrame");
27
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
28
+
29
+ GamePanel gamePanel = new GamePanel();
30
+ PausePanel pausePanel = new PausePanel(gamePanel::resume); //esc が押されたら gamePanel.resume() を呼ぶ
31
+ FinishedPanel finishedPanel = new FinishedPanel(gamePanel::start); //enter が押されたら gamePane.start() を呼ぶ
32
+
33
+ gamePanel.setPauseListener(() -> pausePanel.setVisible(true)); //esc が押されたら pausePanel を表示
34
+ gamePanel.setFinishedListener(finishedPanel::setScoreAndVisible); //finish したら finishedPanel.setScoreAndVisible(int) を呼ぶ
35
+
36
+ Container contentPane = getContentPane();
37
+ contentPane.setLayout(new OverlayLayout(contentPane)); //全てを重ねる
38
+ add(finishedPanel); //一番上
39
+ add(pausePanel);
40
+ add(gamePanel); //一番下
41
+ pack();
42
+
43
+ gamePanel.start();
44
+ }
45
+ }
46
+
47
+ class GamePanel extends JPanel {
48
+ private Consumer<Integer> finishedListener;
49
+ private Runnable pauseListener;
50
+ private Font font1, font2;
51
+ private FontMetrics fontMetrics1, fontMetrics2;
52
+ private Timer timer;
53
+ private Random random = new Random();
54
+ private int keycode, value, bar;
55
+
56
+ GamePanel() {
57
+ super(null);
58
+ setSize(400, 400);
59
+ setPreferredSize(getSize());
60
+ setFocusable(true);
61
+ setBackground(Color.CYAN); //重なりを分かり易くするため色を付けてみる
62
+
63
+ font1 = getFont();
64
+ fontMetrics1 = getFontMetrics(font1);
65
+ font2 = font1.deriveFont(Font.BOLD, 50f);
66
+ fontMetrics2 = getFontMetrics(font2);
67
+
68
+ addKeyListener(new KeyAdapter() {
69
+ @Override
70
+ public void keyPressed(KeyEvent e) {
71
+ int kc = e.getKeyCode();
72
+ if(kc == KeyEvent.VK_LEFT || kc == KeyEvent.VK_RIGHT) keycode = kc;
73
+ }
74
+ @Override
75
+ public void keyReleased(KeyEvent e) {
76
+ int kc = e.getKeyCode();
77
+ if(kc == KeyEvent.VK_ESCAPE) pause();
78
+ if(kc == keycode) keycode = 0;
79
+ }
80
+ private void pause() {
81
+ timer.stop();
82
+ keycode = 0;
83
+ if(pauseListener != null) pauseListener.run();
84
+ }
85
+ });
86
+ }
87
+
88
+ void setFinishedListener(Consumer<Integer> listener) {
89
+ finishedListener = listener;
90
+ }
91
+ void setPauseListener(Runnable listener) {
92
+ pauseListener = listener;
93
+ }
94
+
95
+ void start() {
96
+ keycode = 0;
97
+ value = 50;
98
+ resume();
99
+ }
100
+
101
+ void resume() {
102
+ requestFocus();
103
+ timer = new Timer(50, e -> {
104
+ if(value == 0 || value == 100) { //終わり判定
105
+ timer.stop();
106
+ if(finishedListener != null) finishedListener.accept(value); //テキトウにスコアとして value を渡してみる
107
+ return;
108
+ }
109
+ if(keycode == KeyEvent.VK_LEFT) value -= 1;
110
+ if(keycode == KeyEvent.VK_RIGHT) value += 1;
111
+ bar = random.nextInt(10); //タイマーが動いているかを確認する為の表示
112
+ repaint();
113
+ });
114
+ timer.start();
115
+ }
116
+
117
+ @Override
118
+ public void paintComponent(Graphics g) {
119
+ super.paintComponent(g);
120
+
121
+ String s = "=".repeat(bar);
122
+ int x = 0 + 10;
123
+ int y = fontMetrics1.getAscent() + 10;
124
+ g.setFont(font1);
125
+ g.drawString(s, x, y);
126
+
127
+ s = "← " + value + " →";
128
+ x = (getWidth() - fontMetrics2.stringWidth(s)) / 2;
129
+ y = (getHeight() - fontMetrics2.getHeight()) / 2 + fontMetrics2.getAscent();
130
+ g.setFont(font2);
131
+ g.drawString(s, x, y);
132
+ }
133
+ }
134
+
135
+ class FinishedPanel extends JPanel {
136
+ private JLabel scoreLabel;
137
+
138
+ FinishedPanel(Runnable restartListener) {
139
+ super(new GridBagLayout());
140
+ if(restartListener == null) throw new IllegalArgumentException("Required restartListener");
141
+ setBackground(new Color(0,0,0,180)); //半透明
142
+
143
+ Font font = new Font("Verdana", Font.BOLD, 18);
144
+
145
+ GridBagConstraints gbc = new GridBagConstraints();
146
+ gbc.gridx = 0;
147
+
148
+ scoreLabel = new JLabel();
149
+ scoreLabel.setForeground(Color.WHITE);
150
+ scoreLabel.setFont(font);
151
+ add(scoreLabel, gbc);
152
+
153
+ add(Box.createVerticalStrut(30), gbc);
154
+
155
+ JLabel restartLabel = new JLabel("Press ENTER to restart");
156
+ restartLabel.setForeground(Color.GREEN);
157
+ restartLabel.setFont(font);
158
+ add(restartLabel, gbc);
159
+
160
+ addKeyListener(new KeyAdapter() {
161
+ @Override
162
+ public void keyPressed(KeyEvent e) {
163
+ if(e.getKeyCode() == KeyEvent.VK_ENTER) {
164
+ setVisible(false);
165
+ restartListener.run();
166
+ }
167
+ }
168
+ });
169
+
170
+ setVisible(false);
171
+ }
172
+
173
+ void setScoreAndVisible(int score) {
174
+ scoreLabel.setText("Score: " + score);
175
+ setVisible(true);
176
+ requestFocus();
177
+ }
178
+ }
179
+
180
+ class PausePanel extends JPanel {
181
+ PausePanel(Runnable resumeListener) {
182
+ super(new BorderLayout());
183
+ if(resumeListener == null) throw new IllegalArgumentException("Required resumeListener");
184
+ setBackground(new Color(100,100,100,180)); //半透明
185
+ setFocusable(true);
186
+
187
+ JLabel label = new JLabel("PAUSE");
188
+ label.setHorizontalAlignment(SwingConstants.CENTER);
189
+ label.setForeground(Color.YELLOW);
190
+ label.setFont(new Font("Monospaced", Font.BOLD, 25));
191
+ add(label, BorderLayout.CENTER);
192
+
193
+ addKeyListener(new KeyAdapter() {
194
+ @Override
195
+ public void keyReleased(KeyEvent e) {
196
+ if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
197
+ setVisible(false);
198
+ resumeListener.run();
199
+ }
200
+ }
201
+ });
202
+
203
+ setVisible(false);
204
+
205
+ addComponentListener(new ComponentAdapter() {
206
+ @Override
207
+ public void componentShown(ComponentEvent e) {
208
+ requestFocus();
209
+ }
210
+ });
211
+ }
212
+ }
213
+ ```
214
+ ![一時停止時画面](https://ddjkaamml8q8x.cloudfront.net/questions/2024-05-23/e2c13bd9-d3d3-473d-be16-35747618d116.png)
215
+ ![フィニッシュ時画面](https://ddjkaamml8q8x.cloudfront.net/questions/2024-05-23/f706f59d-59c5-4bca-b69b-8ec720547064.png)