解決策その2の続き。
クリアまでの時間を競うというのもゲームのよくあるパターンです。やってみましょう
System.currentTimeMillis()は現在時をミリ秒単位で知らせてくれます。戻り値はintでなくlongです。(実際には1970年1月1日からの現在までの経過時間を返します)
ゲームの最初に
long time0 = System.currentTimeMillis();
として時刻を記録し、ゲームの終わりに、
long time1 = System.currentTimeMillis();
として時刻を再度記録します。
time1-time0
は、かかった時間をミリ秒単位で計測したものになります。つまり16000となれば16秒ということです。
普通は1000で割って秒に直します。
(time1-time0)/1000
longとintの計算なので整数に切り捨てられます。
少数点以下も表現したいときは次のようにします。
(time1-time0)/1000.0
いまさらですが、green, blue は斜めの線にしておくと跳ね返りの方向が分かっていいでしょう。全角のバックスラッシュは「きごう」で変換すると出てきます。"/"は「すらっしゅ」を変換してもOKです。
rbtn = new JButton("start"); gbtn = new JButton("\"); bbtn = new JButton("/");
import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.awt.image.*; public class MoveDisk8 extends JFrame implements ActionListener{ JButton rbtn; JButton gbtn; JButton bbtn; MyPanel mypnl; JPanel btnpnl; BufferedImage buffimg; Graphics bfg; int gctgrn = 0; int gctblu = 0; int clct = 0; int bnct = 0; int tmax = 2; Target[] ts = new Target[tmax]; //constructor public MoveDisk8() { setDefaultCloseOperation(EXIT_ON_CLOSE); setTitle("MoveDisk"); mypnl = new MyPanel(); rbtn = new JButton("start"); gbtn = new JButton("\"); bbtn = new JButton("/"); btnpnl = new JPanel(); btnpnl.setLayout(new GridLayout(1,3,0,0)); btnpnl.add(rbtn); btnpnl.add(gbtn); btnpnl.add(bbtn); setLayout(new BorderLayout()); add(mypnl, BorderLayout.CENTER); add(btnpnl,BorderLayout.SOUTH); rbtn.addActionListener(this); gbtn.addActionListener(this); bbtn.addActionListener(this); pack(); setVisible(true); //BufferedImageを作るのはpaintComponentに移した } //イベント処理 @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == rbtn) { clct=0; gctblu=0; gctgrn=0; bnct =0; rbtn.setEnabled(false); rbtn.setText("busy"); Thread thread = new moveDisk(mypnl,buffimg); thread.start(); } if (e.getSource() == gbtn) { gctgrn++; } if (e.getSource() == bbtn) { gctblu++; } } public static void main(String[] args){ MoveDisk8 myframe = new MoveDisk8(); } //内部クラス public class MyPanel extends JPanel{ Color bc= new Color(255,255,191); //背景の色 Color c = new Color(0,0,0); //楕円の色 boolean firsttime = true; public MyPanel(){ setBackground(new Color(255,255,191)); setPreferredSize(new Dimension(400,400)); //panel側で大きさを指定する } @Override public void paintComponent(Graphics myg){ super.paintComponent(myg); if (firsttime){ //1回目の描画でBufferedImageをつくる buffimg = new BufferedImage( getSize().width, getSize().height, BufferedImage.TYPE_INT_RGB); bfg = buffimg.createGraphics(); bfg.setColor(bc); bfg.fillRect(0, 0, getSize().width, getSize().height); firsttime = false; //次回はやらない } myg.drawImage(buffimg, 0, 0 ,getSize().width, getSize().height,this); //getSize().widthはMyPanelのインスタンスの幅 } //円を動かすメソッド→下記内部クラスに }// end of class MyPanel //円を動かすクラス class moveDisk extends Thread{ MyPanel pnl; BufferedImage image; int x ; int y ; int lx =0; int ly =0; int d = 10; int dx = 5; int dy = 0; int stime = 50; //sleeptime dx=10:stime=100 int ctgrn; int ctblu; //constructor public moveDisk(MyPanel pn, BufferedImage im) { this.pnl = pn; this.image = im; y = (int)(image.getHeight()*Math.random()); int w = image.getWidth(); int h = image.getHeight(); for(int i=0 ; tmax>i ; i++){ ts[i] = new Target(w,h); } ctgrn = gctgrn; ctblu = gctblu; } @Override public void run() { Graphics thg = image.createGraphics(); Color bc= new Color(255,255,191); //背景の色 thg.setColor(bc); thg.fillRect(0,0,image.getWidth(),image.getHeight()); thg.setColor(Color.blue); for(int i=0 ; tmax>i ; i++){ if (ts[i].cleared) continue; thg.fillOval(ts[i].x-d/2,ts[i].y-d/2,d,d); } while ( ! rbtn.isEnabled() ){ if (gctgrn != ctgrn) { int tmp = dx; dx = dy; dy = tmp; ctgrn = gctgrn; } if (gctblu != ctblu) { int tmp = dy; dy = -dx; dx = -tmp; ctblu = gctblu; } thg.setColor(bc); thg.fillOval(lx-d/2,ly-d/2,d,d); for(int i=0 ; tmax>i ; i++){ if (ts[i].cleared) continue; if (d/2>Math.abs(ts[i].x-x)){ if (d/2>Math.abs(ts[i].y-y)){ ts[i].cleared = true; thg.fillOval(ts[i].x-d/2,ts[i].y-d/2,d,d); clct++; } } } thg.setColor(Color.red); thg.fillOval(x-d/2,y-d/2,d,d); if (clct==tmax) { int sx = x+8; if (sx>image.getWidth()-60) sx=image.getWidth()-60; int sy = y+16; if (sy>image.getHeight()-60) sy=image.getHeight()-60; thg.drawString("Cleared",sx,sy); thg.drawString("Click "+(gctgrn+gctblu),sx,sy+16); thg.drawString("Bounce "+bnct,sx,sy+16*2); rbtn.setEnabled(true); rbtn.setText("replay"); } pnl.repaint(); lx = x; ly = y; x += dx; y += dy; if (x >image.getWidth()){ x = 2*image.getWidth()-x; dx = -dx; } if (0 > x){ x = -x; dx = -dx; } if (y >image.getHeight()){ y = 2*image.getHeight()-y; dy = -dy; } if (0 > y){ y = -y; dy = -dy; } //(stime÷1000 秒)停止 try { Thread.sleep(stime); } catch(InterruptedException ex) { System.err.println(ex); } }//end of while }//end of run }//end of class moveDisk class Target{ int x; //x位置 int y; //y位置 boolean cleared = false; //クリアされたかどうか public Target(int w,int h){ x = (int)(w*Math.random()); y = (int)(h*Math.random()); } }//end of class Target }
主な変更点
MoveDisk8.javaに書き加えます。
1回のゲームが終わるたびに Click 3 などとクリック数が表示されています
その下の bouns 0 は壁の跳ね返り数を数えるためのものですが、これはまだ実装されていません。跳ね返り数は bnct という変数を使うように、宣言して初期値は入っています。跳ね返るところに bnct++ などと加えて正しい数が表示されるようにしなさい。
また、上記を参考にクリアにかかった秒数も表示するようにしなさい。