質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

2回答

3849閲覧

なぜか一回のクリックでイベントが複数回起こる。

Pcios

総合スコア5

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2020/01/21 17:19

コードは長いですが、簡単なゲームをつくろうとしています。このコードで実行⇒スタート(ボタン)⇒右上の画像ボタン(最初は別の画像で、押すと消える)を押すと元のウィンドウは消え、別ウィンドウに画像が表示されるイベント処理があります。1回目は成功するのですが、なぜか2回目からはこの動作が複数回起き(2回程度)、続けていると1回のクリックに対する動作の回数が増えていき、最終的にはウィンドウの嵐になります。対処法を教えてください。
コードは長いですが、バグに関係あるのはタイマー処理に関係する部分と、CATCH1~3()のところだと思ってます。

java

package sample;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

class TASK extends TimerTask{

// タイマー処理のメソッドを誘発させる public void run(){ Fishing Act = new Fishing(); // これができなければ詰んでた Act.ROLL(); }

}

class TASK2 extends TimerTask{

// タイマー処理のメソッドを誘発させる public void run(){ Fishing Act = new Fishing(); Act.ROLL2(); }

}

public class Fishing extends JFrame implements ActionListener
{
private static final long serialVersionUID = 1L;

//クラス変数定義
public static int flag=0;
static int gamescore =0;
static int alltime =0; //60sカウントに使う。
static int[] fish_score1={0,50,50,100,100};
static int[] fish_score2={150,150,200,200,250};
static int[] fish_score3={300,300,400,400,500};
static int[] fish_scoreQ={-50,-50,-100,0,1000};
static ImageIcon[] fish1={new ImageIcon("N0.jpg"),new ImageIcon("N1.jpg"),new ImageIcon("N2.jpg"),new ImageIcon("N3.jpg"),new ImageIcon("N4.jpg"),};
static ImageIcon[] fish2={new ImageIcon("R0.jpg"),new ImageIcon("R1.jpg"),new ImageIcon("R2.jpg"),new ImageIcon("R3.jpg"),new ImageIcon("R4.jpg"),};
static ImageIcon[] fish3={new ImageIcon("SR0.jpg"),new ImageIcon("SR1.jpg"),new ImageIcon("SR2.jpg"),new ImageIcon("SR3.jpg"),new ImageIcon("SR4.jpg"),};
static ImageIcon[] fishQ={new ImageIcon("SC0.jpg"),new ImageIcon("SC1.jpg"),new ImageIcon("SC2.jpg"),new ImageIcon("SC3.jpg"),new ImageIcon("SC4.jpg"),};
static JButton[] Bbt={new JButton(new ImageIcon("しーん.jpg")),new JButton(new ImageIcon("!.jpg")),
new JButton(new ImageIcon("!!.jpg")),new JButton(new ImageIcon("!!!.jpg")),new JButton(new ImageIcon("?.jpg"))};
ImageIcon Titlegazo = new ImageIcon("タイトル画像.jpg");
ImageIcon RULE1 = new ImageIcon("ルール1.jpg"); ImageIcon RULE2 = new ImageIcon("ルール2.jpg");
ImageIcon NINGEN = new ImageIcon("釣りbasic2.jpg"); ImageIcon SEA = new ImageIcon("海.jpg");
static JButton CHANGEBt=Bbt[0];
JButton bt1 = new JButton("スタート"); JButton bt2 = new JButton("あそびかた");
JButton bt3 = new JButton("つぎへ"); JButton bt4 = new JButton("タイトルへ");
JButton bt5 =new JButton("もどる");
JPanel p4 = new JPanel(); Timer timer2 = new Timer(true); Timer timer1 = new Timer(true);

// タイマー処理(本命)
public void ROLL(){
timer2.cancel();
int x= Atrandom();
//p4.revalidate();
//p4.remove(CHANGEBt); p4.add(Bbt[x]);
CHANGEBt.setBounds(0,0,0,0);
CHANGEBt=Bbt[x];
CHANGEBt.setBounds(378,120,375,280);
p4.revalidate();
p4.repaint();
switch(x){
case 1:
{
timer1.schedule(new TASK2(),600); break;
}
case 2:
{
timer1.schedule(new TASK2(),400); break;
}

}

}

//もう一つのタイマー処理
public void ROLL2(){
//if(flag%2==0){
timer1.cancel();
CHANGEBt.setBounds(0,0,0,0);
CHANGEBt=Bbt[0];
CHANGEBt.setBounds(378,120,375,280);
p4.revalidate();
p4.repaint();
// System.exit(0);
//Fishing Act = new Fishing(); Act.MAINGAME();
//}
}

//1~4までの非等倍乱数を得る。
public int Atrandom(){
int Ra[]={1,1,1,1,1,1,1,1,2,2,2,2,1,3,3,2,1,2,1,2}; Random r=new Random(); //4,4,4,4,4
int A=r.nextInt(20); int B = Ra[A];
return B;
}

//タイトル画面
public void TITLE(){
setBounds(550, 100, 770, 800);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("魚釣りゲーム~タイトル~");
JLabel titleLabel = new JLabel(Titlegazo);
JPanel p1 = new JPanel();
p1.setLayout(null);
bt1.setBounds(310,580,130,30); bt2.setBounds(310,650,130,30);
bt1.addActionListener(this ); bt1.addActionListener(event -> dispose());
bt2.addActionListener(this ); bt2.addActionListener(event -> dispose());
p1.add(bt1); p1.add(bt2);
p1.add(titleLabel); titleLabel.setBounds(-10,0,770,760);
add("Center",p1);
setVisible(true);
}

//ルール説明1
public void Explain1(){
setBounds(550, 100, 770, 800);
setTitle("魚釣りゲームのルール説明");
JPanel p2 = new JPanel();
p2.setLayout(null);
bt3.setBounds(100,540,130,30);
bt3.addActionListener(this ); bt3.addActionListener(event -> dispose());
p2.add(bt3);
JLabel RURELabel1 = new JLabel(RULE1);
p2.add(RURELabel1); RURELabel1.setBounds(0,150,760,460);
add("Center",p2);
setVisible(true);
}

//ルール説明2
public void Explain2(){
setBounds(550, 100, 770, 800);
setTitle("魚釣りゲームのルール説明");
JPanel p3 = new JPanel();
p3.setLayout(null);
bt4.setBounds(50,520,180,30);
bt4.addActionListener(this ); bt4.addActionListener(event -> dispose());
p3.add(bt4);
JLabel RURELabel2 = new JLabel(RULE2);
p3.add(RURELabel2); RURELabel2.setBounds(0,150,760,460);
add("Center",p3);
setVisible(true);

}

// ゲーム画面
public void MAINGAME(){
setBounds(550, 100, 770, 800);
setTitle("魚釣りゲーム");
p4.setLayout(null);
JLabel SCORE_Label = new JLabel();
SCORE_Label.setText("SCORE: "+gamescore+"点");
p4.add(SCORE_Label); SCORE_Label.setBounds(100,0,400,400);
JLabel SEA_Label = new JLabel(SEA);
p4.add(SEA_Label); SEA_Label.setBounds(195,400,560,350);
JLabel NINGEN_Label = new JLabel(NINGEN);
p4.add(NINGEN_Label); NINGEN_Label.setBounds(0,180,380,380);
p4.add(CHANGEBt); CHANGEBt.setBounds(378,120,375,280);
CHANGEBt.addActionListener(this ); CHANGEBt.addActionListener(event -> dispose());
p4.add(Bbt[1]); p4.add(Bbt[2]); p4.add(Bbt[3]); p4.add(Bbt[4]); //サイズで表示非表示を表現するなら、ボタンは全部Addされていないといけない
Bbt[1].addActionListener(this ); Bbt[1].addActionListener(event -> dispose()); Bbt[3].addActionListener(this ); Bbt[3].addActionListener(event -> dispose());
Bbt[2].addActionListener(this ); Bbt[2].addActionListener(event -> dispose()); Bbt[4].addActionListener(this ); Bbt[4].addActionListener(event -> dispose());
add("Center",p4); //saigo
setVisible(true); //saigo
Random r = new Random(); int R;
R=100*(r.nextInt(50) +1); // 100<= R <= 5000
alltime = alltime + R; // 総合時間を加算

timer2.schedule(new TASK(),R); //タイマー処理は最後にコンパイラされる

}

// !ボタンが押されたとき
public void CATCH1(){
//flag=flag+1;
setBounds(550, 100, 770, 800); setTitle("魚釣りゲーム");
JPanel p5 = new JPanel(); p5.setLayout(null);
Random r = new Random(); int B= r.nextInt(5);
bt5.setBounds(280,650,130,30);
bt5.addActionListener(this ); bt5.addActionListener(event -> dispose());
p5.add(bt5);
ImageIcon A = fish1[B]; gamescore= gamescore+fish_score1[B];
JLabel CATCH_Label = new JLabel(); CATCH_Label.setText("釣り上げた!");
p5.add(CATCH_Label); CATCH_Label.setBounds(305,120,100,100);
JLabel A_Label = new JLabel(A);
p5.add(A_Label); A_Label.setBounds(150,200,400,400);
add("Center",p5); setVisible(true);

}

//!!ボタンが押されたとき
public void CATCH2(){
flag=flag+1;
setBounds(550, 100, 770, 800); setTitle("魚釣りゲーム");
JPanel p6 = new JPanel(); p6.setLayout(null);
Random r = new Random(); int B= r.nextInt(5);
bt5.setBounds(280,650,130,30);
bt5.addActionListener(this ); bt5.addActionListener(event -> dispose());
p6.add(bt5);
ImageIcon A = fish2[B]; gamescore=gamescore+fish_score2[B];
JLabel CATCH_Label = new JLabel(); CATCH_Label.setText("釣り上げた!");
p6.add(CATCH_Label); CATCH_Label.setBounds(305,120,100,100);
JLabel A_Label = new JLabel(A);
p6.add(A_Label); A_Label.setBounds(150,200,400,400);
add("Center",p6); setVisible(true);

}

//!!!ボタンが押されたとき
public void CATCH3(){
flag=flag+1;
setBounds(550, 100, 770, 800); setTitle("魚釣りゲーム");
JPanel p7 = new JPanel(); p7.setLayout(null);
Random r = new Random(); int B= r.nextInt(5);
bt5.setBounds(280,650,130,30);
bt5.addActionListener(this ); bt5.addActionListener(event -> dispose());
p7.add(bt5);
ImageIcon A = fish3[B]; gamescore=gamescore+fish_score3[B];
JLabel CATCH_Label = new JLabel(); CATCH_Label.setText("釣り上げた!");
p7.add(CATCH_Label); CATCH_Label.setBounds(305,120,100,100);
JLabel A_Label = new JLabel(A);
p7.add(A_Label); A_Label.setBounds(150,200,400,400);
add("Center",p7); setVisible(true);

}

// クリックからメソッドを誘導する
public void actionPerformed(ActionEvent e) {
if(e.getSource()==bt2){
Fishing ive = new Fishing(); ive.Explain1();
}
else if(e.getSource()==bt3){
Fishing ive = new Fishing(); ive.Explain2();
}
else if(e.getSource()==bt4){
Fishing ive = new Fishing(); ive.TITLE();
}
else if(e.getSource()==bt1){
Fishing ive = new Fishing(); ive.MAINGAME(); // スタート→メイン画面へ遷移
}
else if(e.getSource()==Bbt[1]){
Fishing ive = new Fishing(); ive.CATCH1();
}
else if(e.getSource()==Bbt[2]){
Fishing ive = new Fishing(); ive.CATCH2();
}
else if(e.getSource()==Bbt[3]){
Fishing ive = new Fishing(); ive.CATCH3();
}
else if(e.getSource()==bt5){ // 釣り上げ→メイン画面へ遷移
if(alltime<60000)
{
//flag=flag+1;
CHANGEBt=Bbt[0];
Fishing ive = new Fishing(); ive.MAINGAME();
}
else
{
//game end
}

}

}

//メインメソッド
public static void main(String[] args)
{
Fishing set = new Fishing(); set.TITLE();
}
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shiracamus

2020/01/22 00:28

インデントが正しく表示されるように、コードをcodeブロックで囲んでください。
jimbe

2020/01/22 03:36 編集

前の回答で「TimerTaskでnew Fishing()はよくない」と言われた意味をお考えください.
guest

回答2

0

かなりひどいコードです.
命名規則を無視し変数名はテキトウ, スコープを理解せずオブジェクトをそこら中で作りまくり, static 変数だらけです.

Fishing を new するのはメインメソッドでの1回のみとなるように, スコープを理解して修正してみてください.


java

1import java.awt.CardLayout; 2import java.awt.event.*; 3import java.util.Random; 4import javax.swing.*; 5 6public class JFishing extends JFrame { 7 /** 魚 */ 8 private static class Fish { 9 private ImageIcon icon; 10 private int score; 11 Fish(String iconName, int score) { 12 icon = new ImageIcon(iconName); 13 this.score = score; 14 } 15 Icon getIcon() { return icon; } 16 int getScore() { return score; } 17 } 18 /** 釣り上げチャンス */ 19 private static class CatchChance { 20 private static Random random = new Random(System.currentTimeMillis()); 21 private int ratio; 22 private Icon icon; 23 private int time; 24 private Fish[] fishes; 25 /** 26 * コンストラクタ 27 * @param ratio 確率(全体に占める割合) 28 * @param iconName イメージファイル名 29 * @param time 継続時間 30 * @param fishes 釣れる可能性のある魚の配列 31 */ 32 CatchChance(int ratio, String iconName, int time, Fish ... fishes) { 33 this.ratio = ratio; 34 this.icon = new ImageIcon(iconName); 35 this.time = time; 36 this.fishes = fishes; 37 } 38 int getRatio() { return ratio; } 39 Icon getIcon() { return icon; } 40 int getTime() { return time; } 41 Fish getFish() { 42 if(fishes.length == 0) return null; 43 int j = random.nextInt(fishes.length); 44 return fishes[j]; 45 } 46 }; 47 /** 魚が掛かっていない状態 */ 48 private static class NormalState extends CatchChance { 49 private Random random = new Random(System.currentTimeMillis()); 50 NormalState(String iconName) { 51 super(0, iconName, 0); 52 } 53 /** 魚が掛かっていない時間 */ 54 int getTime() { 55 return 100 * (random.nextInt(50) + 1); // 100 - 5000 56 } 57 } 58 private static final CatchChance CATCH_CHANCES[] = { 59 new NormalState("しーん.jpg"), 60 new CatchChance(11,"!.jpg", 600, new Fish("N0.jpg" , 0), new Fish("N1.jpg" , 50), new Fish("N2.jpg" , 50), new Fish("N3.jpg" ,100), new Fish("N4.jpg" , 100)), 61 new CatchChance( 7,"!!.jpg", 400, new Fish("R0.jpg" ,150), new Fish("R1.jpg" ,150), new Fish("R2.jpg" , 200), new Fish("R3.jpg" ,200), new Fish("R4.jpg" , 250)), 62 new CatchChance( 2,"!!!.jpg",300, new Fish("SR0.jpg",300), new Fish("SR1.jpg",300), new Fish("SR2.jpg", 400), new Fish("SR3.jpg",400), new Fish("SR4.jpg", 500)), 63 new CatchChance( 0,"?.jpg", 0, new Fish("SC0.jpg",-50), new Fish("SC1.jpg",-50), new Fish("SC2.jpg",-100), new Fish("SC3.jpg", 0), new Fish("SC4.jpg",1000)) 64 }; 65 66 public static void main(String[] args) { 67 new JFishing().setVisible(true); 68 } 69 70 //private int flag = 0; //使い道不定 71 private int gamescore = 0; 72 private int alltime = 0; //60sカウントに使う。 73 74 private CardLayout mgr; 75 private CatchPanel catchPanel; 76 77 JFishing() { 78 super(); 79 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 80 setBounds(550, 100, 770, 800); 81 82 mgr = new CardLayout(); 83 getContentPane().setLayout(mgr); 84 add(new TitlePanel(), "Title"); 85 add(new ExplainPanel(), "Explain"); 86 add(new GamePanel(), "Game"); 87 88 catchPanel = new CatchPanel(); 89 add(catchPanel, "Catch"); 90 91 showTitlePanel(); 92 } 93 private void showTitlePanel() { 94 gamescore = 0; 95 alltime = 0; 96 mgr.show(getContentPane(), "Title"); 97 } 98 private void showExplainPanel() { 99 mgr.show(getContentPane(), "Explain"); 100 } 101 private void showGamePanel() { 102 mgr.show(getContentPane(), "Game"); 103 } 104 private void showCatchPanel(Fish fish) { 105 catchPanel.setFish(fish); 106 mgr.show(getContentPane(), "Catch"); 107 } 108 109 /** タイトルパネル */ 110 private class TitlePanel extends JPanel { 111 TitlePanel() { 112 super(null); 113 setTitle("魚釣りゲーム~タイトル~"); 114 115 JLabel titleLabel = new JLabel(new ImageIcon("タイトル画像.jpg")); 116 titleLabel.setBounds(-10, 0, 770, 760); 117 add(titleLabel); 118 119 JButton startButton = new JButton("スタート"); 120 startButton.setBounds(310, 580, 130, 30); 121 startButton.addActionListener(e -> showGamePanel()); // スタート→メイン画面へ遷移 122 add(startButton); 123 124 JButton explainButton = new JButton("あそびかた"); 125 explainButton.setBounds(310, 650, 130, 30); 126 explainButton.addActionListener(e -> showExplainPanel()); 127 add(explainButton); 128 } 129 } 130 131 /** ルール説明パネル */ 132 private class ExplainPanel extends JPanel { 133 private Icon rule1Icon = new ImageIcon("ルール1.jpg"); 134 private Icon rule2Icon = new ImageIcon("ルール2.jpg"); 135 private JLabel ruleLabel; 136 private JButton titleButton; 137 private JButton nextButton; 138 139 ExplainPanel() { 140 super(null); 141 setTitle("魚釣りゲームのルール説明"); 142 143 ruleLabel = new JLabel(rule1Icon); 144 ruleLabel.setBounds(0, 150, 760, 460); 145 add(ruleLabel); 146 147 titleButton = new JButton("タイトルへ"); 148 titleButton.setBounds(50, 520, 180, 30); 149 titleButton.addActionListener(e -> showTitlePanel()); 150 add(titleButton); 151 152 nextButton = new JButton("つぎへ"); 153 nextButton.setBounds(100, 540, 130, 30); 154 nextButton.addActionListener(e -> showRule2()); 155 add(nextButton); 156 157 addComponentListener(new ComponentAdapter() { 158 @Override 159 public void componentShown(ComponentEvent e) { 160 showRule1(); 161 } 162 }); 163 } 164 private void showRule1() { 165 ruleLabel.setIcon(rule1Icon); 166 nextButton.setVisible(true); 167 titleButton.setVisible(false); 168 } 169 private void showRule2() { 170 ruleLabel.setIcon(rule2Icon); 171 nextButton.setVisible(false); 172 titleButton.setVisible(true); 173 } 174 } 175 176 /** ゲームパネル */ 177 private class GamePanel extends JPanel { 178 private long starttime; 179 private CatchAction catchAction; 180 private JLabel scoreLabel; 181 182 GamePanel() { 183 super(null); 184 setTitle("魚釣りゲーム"); 185 186 scoreLabel = new JLabel(); 187 scoreLabel.setBounds(100, 0, 400, 400); 188 add(scoreLabel); 189 190 JLabel seaLabel = new JLabel(new ImageIcon("海.jpg")); 191 seaLabel.setBounds(195, 400, 560, 350); 192 add(seaLabel); 193 194 JLabel fisherLabel = new JLabel(new ImageIcon("釣りbasic2.jpg")); 195 fisherLabel.setBounds(0, 180, 380, 380); 196 add(fisherLabel); 197 198 catchAction = new CatchAction(CATCH_CHANCES); 199 catchAction.setOnCatchListener(fish -> { 200 gamescore += fish.getScore(); 201 rewriteScoreLabel(); 202 showCatchPanel(fish); 203 }); 204 205 JButton catchButton = new JButton(catchAction); 206 catchButton.setBounds(378, 120, 375, 280); 207 add(catchButton); 208 209 addComponentListener(new ComponentAdapter() { 210 @Override 211 public void componentShown(ComponentEvent e) { 212 starttime = System.currentTimeMillis(); 213 rewriteScoreLabel(); 214 catchAction.start(); 215 } 216 @Override 217 public void componentHidden(ComponentEvent e) { 218 alltime += (int)(System.currentTimeMillis() - starttime); 219 catchAction.stop(); 220 } 221 }); 222 rewriteScoreLabel(); 223 } 224 private void rewriteScoreLabel() { 225 scoreLabel.setText("SCORE: " + gamescore + "点"); 226 } 227 } 228 /** 釣り上げ */ 229 private static class CatchAction extends AbstractAction { 230 interface OnCatchListener { 231 void onCatch(Fish fish); 232 } 233 private OnCatchListener listener; 234 private CatchChance[] catchChances; 235 private int totalRatio; 236 private Random random = new Random(System.currentTimeMillis()); 237 private Timer timer; 238 private CatchChance chance; 239 240 CatchAction(CatchChance[] catchChances) { 241 this.catchChances = catchChances; 242 totalRatio = 0; 243 for(CatchChance cr : catchChances) totalRatio += cr.getRatio(); 244 245 chance = catchChances[0]; 246 putValue(LARGE_ICON_KEY, chance.getIcon()); 247 } 248 void setOnCatchListener(OnCatchListener listener) { 249 this.listener = listener; 250 } 251 void start() { 252 chance = catchChances[0]; 253 putValue(LARGE_ICON_KEY, chance.getIcon()); 254 int delay = chance.getTime(); 255 timer = new Timer(delay, new ActionListener() { 256 public void actionPerformed(ActionEvent e) { 257 timer.stop(); 258 chance = (chance == catchChances[0] ? getChance() : catchChances[0]); 259 putValue(LARGE_ICON_KEY, chance.getIcon()); 260 timer.setInitialDelay(chance.getTime()); 261 timer.restart(); 262 } 263 }); 264 timer.setRepeats(false); 265 timer.start(); 266 } 267 private CatchChance getChance() { 268 int v = random.nextInt(totalRatio); 269 int i = 1; 270 while(v>=catchChances[i].getRatio()) v-=catchChances[i++].getRatio(); 271 return catchChances[i]; 272 } 273 void stop() { 274 if(timer != null) { 275 timer.stop(); 276 timer = null; 277 } 278 } 279 @Override 280 public void actionPerformed(ActionEvent e) { 281 Fish fish = chance.getFish(); 282 if(fish != null && listener != null) { 283 stop(); 284 listener.onCatch(fish); 285 } 286 } 287 } 288 /** 釣り上げパネル */ 289 private class CatchPanel extends JPanel { 290 private JLabel imageLabel; 291 CatchPanel() { 292 JButton returnButton = new JButton("もどる"); 293 returnButton.setBounds(280, 650, 130, 30); 294 returnButton.addActionListener(e -> { 295 if(alltime < 60000) { 296 showGamePanel(); 297 } else { 298 //game end 299 } 300 }); 301 add(returnButton); 302 303 imageLabel = new JLabel(); 304 imageLabel.setBounds(150, 200, 400, 400); 305 add(imageLabel); 306 307 JLabel catchLabel = new JLabel("釣り上げた!"); 308 catchLabel.setBounds(305, 120, 100, 100); 309 add(catchLabel); 310 } 311 void setFish(Fish fish) { 312 imageLabel.setIcon(fish.getIcon()); 313 } 314 } 315}

投稿2020/01/22 03:48

編集2020/01/22 11:51
jimbe

総合スコア12646

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Pcios

2020/01/22 20:12

こんなにたくさん…!ありがとうございます! もう自分が書いたコードとはかけ離れてしまいましたが、私のコードのバグは、static変数が多すぎてバグったのですかね? 取り敢えず、明日くらいにじっくり確認させていただきます!
jimbe

2020/01/23 03:20

コードを全く変えてしまったのは申し訳ありません. 物が大量に詰まっている家の中では, 無くしモノを探す前に片付けなければなりません. 家の主なら何処に何があるのか分かっているかも知れませんが, 他人には分かりません. だからこそ, (多少長くなっても)変数名やメソッド名, クラス名等に命名規則に基づいた意味のある名前をつけたり, 分けられるものはクラスに分けたりするのです.
jimbe

2020/01/23 05:42

ご質問の原因は特定していませんが, static が多いというのは直接の原因ではありません. まず問題なのは, 回答に書きました通り Fishing を多量に生成していることです. オブジェクトに慣れていない方がよく勘違いされますのは, new HogeHoge によって生成されるモノが全て「一つのモノ」「同じモノ」だと思うことです. 実際には逆で, 全て別々のモノです. 例えば, ある個所(A)で new iPhone として得た iPhone と, 別の個所(B)で new iPhone として得た iPhone は, 同じ iPhone の設計図(クラス)から作られた iPhone (オブジェクト) ではありますが, モノとしては別々です. A の iPhone のアドレス帳に友人を登録しても, B の iPhone のアドレス帳にはその友人は登録されないでしょう. ところが java 的に, アドレス帳が static であったとすると, B の iPhone のアドレス帳にも友人が登録されているようになります. 「なんだ, じゃあ全部 static にして, 必要になったら new iPhone で作れば良いじゃないか」...とは言えません. どの iPhone からでも同じアドレス帳に登録が出来るとしても, 友人を登録する度に iPhone を買うでしょうか? 一回電話をするだけの為に買うでしょうか? iPhone は(コストが)高いです. どんどん浪費することになるでしょう. (Fishing が継承している JFrame も背後に大量のコード・データがあり, コストが高いです.) そんなことをしなくても, 既にポケットに iPhone が入っているなら, 隣の部屋に iPhone があるなら, それを取って使えば良いだけです. 同じ iPhone を使い続ければ, アドレス帳が static でもそうでなくても関係ありません. それが「Fishing を new するのはメインメソッドでの1回のみとなるように」と回答に書かせていただいたことです.
Pcios

2020/01/23 10:20 編集

とても分かりやすい説明、ありがとうございます!お陰様で理解出来ました!オブジェクトをstaticにすると1つのものになると説明していただきましたが、普通にインスタンス化した場合(例えばFishing frame = new frame()とした場合)は、このオブジェクトframeはstaticになってるのでしょうか?それともスコープはインスタンス化したブロック内に限られるのでしょうか?もしstaticなオブジェクトを作るにはどうすれば良いですか?
Pcios

2020/01/23 10:23

画面生成用としてframeオブジェクトを作ったので、もしこのframeオブジェクトがstaticなら、あらゆるメソッドから操作できれば画面遷移が簡単に出来るのでは?と思ったので。。
jimbe

2020/01/23 11:36

static な変数は, "static" と書いたものだけです. static と付いていなければ, それはスコープを抜ければ消えることになります. 画面遷移の例ですが, 私のコードでは画面の遷移は "showほにゃららPanel" というメソッドを呼ぶだけで出来ています. ですが JFishing は static ではありません. 「(static で用いることで)あらゆるメソッドから操作できる」ことが「簡単になる」とは限りません. というより, それでは問題が大きかったのでオブジェクトが生まれたと言えるかと思います. この辺りは書き始めると長くなります. (というか書き始めてみたのですが止めました.) オブジェクトがなぜあるのか等は歴史をお調べになってみてください.
Pcios

2020/01/23 17:01

staticなオブジェクトを作るには、static Fishing frame= new Fishing();とすれば良いのでしょうか?
jimbe

2020/01/23 17:06

書き方としてはそうなります. なお, static なのはオブジェクトではなく変数です. オブジェクトが変数に入れられている場合は, オブジェクトの生存期間はその変数と共になります.
guest

0

jimbeさんの素敵なコードの後に出すのは気が引けますが、ちょうど中間あたりを狙ってみました。

変更点

  • 各画面をパネルに分割
    分割すると管理が楽になります。
  • 画面遷移は同じくカードレイアウトを使用
    遷移の常套手段です。
  • 全部同じでは芸がないので釣り上げ画面はダイアログに
    ImageIconなども簡単に入れられて楽でした。
  • 変数名やメソッドはできるだけ元のままにして、何がどこへいったかをわかりやすく
    ケース(Fish fish FISH等の大文字小文字の法則)くらいは標準的なものでないとムズムズします。
  • 内部クラスはお好みでないようなので使わない(ボタンのアクションだけはラムダを使用)
    内部クラスはコンストラクタで渡したりがなくなるので楽ですが、クラスが長くなるので一長一短ですね。
  • タイマーをjavax.swing.Timerに変更
    特に理由がなければこちらのほうがいいです。
  • static撲滅
    staticが全部ダメというわけではないのですが、はじめのうちはstatic void mainでしか使わないぐらいでいいと思います。

Java

1import java.awt.CardLayout; 2import java.awt.Component; 3import java.awt.event.ActionEvent; 4import java.awt.event.ActionListener; 5import java.util.Random; 6import javax.swing.ImageIcon; 7import javax.swing.JButton; 8import javax.swing.JFrame; 9import javax.swing.JLabel; 10import javax.swing.JOptionPane; 11import javax.swing.JPanel; 12import javax.swing.Timer; 13 14 15public class Fishing extends JFrame { 16 17 public static void main(String[] args) { 18 new Fishing().setVisible(true); 19 } 20 21 private Fishing() { 22 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 23 setBounds(550, 100, 770, 800); 24 25 getContentPane().setLayout(new CardLayout()); 26 add(new TitlePanel(this), "タイトル"); // 自分自身(this)をコンストラクタでわたす 27 add(new Explain1Panel(this), "ルール1"); 28 add(new Explain2Panel(this), "ルール2"); 29 add(new MainGamePanel(this), "ゲーム"); 30 31 showPanel("タイトル"); 32 } 33 34 void showPanel(String name) { // 画面遷移 35 CardLayout cardLayout = (CardLayout) getContentPane().getLayout(); 36 cardLayout.show(getContentPane(), name); 37 38 for (Component c : getContentPane().getComponents()) { // ウィンドウタイトル変更 39 if (c.isVisible()) setTitle(c.getName()); 40 } 41 } 42} 43 44class TitlePanel extends JPanel { 45 46 TitlePanel(Fishing fishing) { // 表示しているFishingをコンストラクタでもらう 47 setName("魚釣りゲーム~タイトル~"); // ウィンドウタイトル用 48 setLayout(null); 49 50 JButton bt1 = new JButton("スタート"); 51 bt1.setBounds(310, 580, 130, 30); 52 bt1.addActionListener((e) -> fishing.showPanel("ゲーム")); // 引数でもらったFishingのメソッドを呼ぶ 53 add(bt1); 54 55 JButton bt2 = new JButton("あそびかた"); 56 bt2.setBounds(310, 650, 130, 30); 57 bt2.addActionListener((e) -> fishing.showPanel("ルール1")); 58 add(bt2); 59 60 JLabel titleLabel = new JLabel(new ImageIcon("タイトル画像.jpg")); 61 titleLabel.setBounds(-10, 0, 770, 760); 62 add(titleLabel); 63 } 64} 65 66class Explain1Panel extends JPanel { 67 68 Explain1Panel(Fishing fishing) { 69 setName("魚釣りゲームのルール説明"); 70 setLayout(null); 71 72 JButton bt3 = new JButton("つぎへ"); 73 bt3.setBounds(100, 540, 130, 30); 74 bt3.addActionListener((e) -> fishing.showPanel("ルール2")); 75 add(bt3); 76 77 JLabel RURELabel1 = new JLabel(new ImageIcon("ルール1.jpg")); 78 RURELabel1.setBounds(0, 150, 760, 460); 79 add(RURELabel1); 80 } 81} 82 83class Explain2Panel extends JPanel { 84 85 Explain2Panel(Fishing fishing) { 86 setName("魚釣りゲームのルール説明"); 87 setLayout(null); 88 89 JButton bt4 = new JButton("タイトルへ"); 90 bt4.setBounds(50, 520, 180, 30); 91 bt4.addActionListener((e) -> fishing.showPanel("タイトル")); 92 add(bt4); 93 94 JLabel RURELabel2 = new JLabel(new ImageIcon("ルール2.jpg")); 95 RURELabel2.setBounds(0, 150, 760, 460); 96 add(RURELabel2); 97 } 98} 99 100class MainGamePanel extends JPanel implements ActionListener { 101 private int[] Ra = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 3, 3, 2, 1, 2, 1, 2 }; 102 103 private int[] fish_score1 = { 0, 50, 50, 100, 100 }; 104 private int[] fish_score2 = { 150, 150, 200, 200, 250 }; 105 private int[] fish_score3 = { 300, 300, 400, 400, 500 }; 106 107 private ImageIcon[] fish1 = { new ImageIcon("N0.jpg"), new ImageIcon("N1.jpg"), new ImageIcon("N2.jpg"), new ImageIcon("N3.jpg"), new ImageIcon("N4.jpg"), }; 108 private ImageIcon[] fish2 = { new ImageIcon("R0.jpg"), new ImageIcon("R1.jpg"), new ImageIcon("R2.jpg"), new ImageIcon("R3.jpg"), new ImageIcon("R4.jpg"), }; 109 private ImageIcon[] fish3 = { new ImageIcon("SR0.jpg"), new ImageIcon("SR1.jpg"), new ImageIcon("SR2.jpg"), new ImageIcon("SR3.jpg"), new ImageIcon("SR4.jpg"), }; 110 111 private JButton[] Bbt = { new JButton(new ImageIcon("しーん.jpg")), new JButton(new ImageIcon("!.jpg")), new JButton(new ImageIcon("!!.jpg")), new JButton(new ImageIcon("!!!.jpg")), new JButton(new ImageIcon("?.jpg")) }; 112 private JLabel SCORE_Label = new JLabel(); 113 114 private Random random = new Random(); 115 private Timer timer1; 116 private Timer timer2; 117 private int gamescore = 0; 118 private int alltime = 0; 119 120 121 MainGamePanel(Fishing fishing) { 122 setName("魚釣りゲーム"); 123 setLayout(null); 124 125 SCORE_Label.setBounds(100, 0, 400, 400); 126 add(SCORE_Label); 127 addScore(0); 128 129 JLabel SEA_Label = new JLabel(new ImageIcon("海.jpg")); 130 SEA_Label.setBounds(195, 400, 560, 350); 131 add(SEA_Label); 132 133 JLabel NINGEN_Label = new JLabel(new ImageIcon("釣りbasic2.jpg")); 134 NINGEN_Label.setBounds(0, 180, 380, 380); 135 add(NINGEN_Label); 136 137 for (JButton b : Bbt) { 138 b.setBounds(378, 120, 375, 280); 139 b.setVisible(false); 140 b.addActionListener(this); 141 add(b); 142 } 143 Bbt[0].setVisible(true); 144 145 timer1 = new Timer(0, new TASK(this)); // delayはROLL ROLL2で設定 146 timer2 = new Timer(0, new TASK2(this)); 147 ROLL2(); 148 } 149 150 void ROLL() { 151 timer1.stop(); 152 int x = Atrandom(); 153 changeButton(x); 154 155 int delay; 156 switch (x) { 157 case 1: 158 delay = 600; 159 break; 160 case 2: 161 delay = 400; 162 break; 163 default: 164 delay = 200; 165 break; 166 } 167 168 timer2.setInitialDelay(delay); 169 alltime += delay; 170 timer2.start(); 171 } 172 173 void ROLL2() { 174 timer2.stop(); 175 changeButton(0); 176 177 int R = 100 * (random.nextInt(50) + 1); 178 alltime += R; 179 timer1.setInitialDelay(R); 180 timer1.start(); 181 } 182 183 @Override 184 public void actionPerformed(ActionEvent e) { 185 JButton b = (JButton) e.getSource(); 186 if (b == Bbt[0]) return; // 連打okなのか?? 187 188 timer1.stop(); 189 timer2.stop(); 190 if (b == Bbt[1]) CATCH1(); 191 else if (b == Bbt[2]) CATCH2(); 192 else if (b == Bbt[3]) CATCH3(); 193 194 ROLL2(); 195 } 196 197 private void addScore(int score) { 198 gamescore += score; 199 SCORE_Label.setText("SCORE: " + gamescore + "点"); 200 } 201 202 private void changeButton(int index) { // ボタンの変更 Visible式 203 for (JButton b : Bbt) { 204 b.setVisible(false); 205 } 206 Bbt[index].setVisible(true); 207 } 208 209 private int Atrandom() { 210 return Ra[random.nextInt(Ra.length)]; 211 } 212 213 private void CATCH1() { 214 int B = random.nextInt(5); 215 JOptionPane.showMessageDialog(this, fish1[B], "釣り上げた!", JOptionPane.PLAIN_MESSAGE); 216 // ダイアログは処理をブロックする 閉じるまで↓に行かない 217 addScore(fish_score1[B]); 218 } 219 220 private void CATCH2() { 221 int B = random.nextInt(5); 222 JOptionPane.showMessageDialog(this, fish2[B], "釣り上げた!", JOptionPane.PLAIN_MESSAGE); 223 addScore(fish_score2[B]); 224 } 225 226 private void CATCH3() { 227 int B = random.nextInt(5); 228 JOptionPane.showMessageDialog(this, fish3[B], "釣り上げた!", JOptionPane.PLAIN_MESSAGE); 229 addScore(fish_score3[B]); 230 } 231} 232 233class TASK implements ActionListener { 234 private MainGamePanel mainGamePanel; 235 236 TASK(MainGamePanel mainGamePanel) { 237 this.mainGamePanel = mainGamePanel; 238 } 239 240 @Override 241 public void actionPerformed(ActionEvent e) { 242 mainGamePanel.ROLL(); 243 } 244} 245 246class TASK2 implements ActionListener { 247 private MainGamePanel mainGamePanel; 248 249 TASK2(MainGamePanel mainGamePanel) { 250 this.mainGamePanel = mainGamePanel; 251 } 252 253 @Override 254 public void actionPerformed(ActionEvent e) { 255 mainGamePanel.ROLL2(); 256 } 257}

投稿2020/01/23 10:30

TN8001

総合スコア9321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Pcios

2020/01/23 16:56

回答ありがとうございます!! 明日実際実行してみます! ちなみになんですが、1回目の動作はうまくいくのに2回目からうまくいかなくなるってことが起きたとしたら、その原因って主にどんなものがありますか?
TN8001

2020/01/24 11:22

Fishingが複数残っていてCATCH()が重複して呼ばれているんだろうとは思いますが、詳しく追う気になりません^^; もしかして現コードをどうにか直そうと思っています? ここまで書いたのをどうにかしたい気持ちはわかります。 しかしあまりにもイレギュラーな作りなので、jimbeさんや私のコードを参考にしていただいて作り直すのを強く勧めます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問