ボールが複数ある時に出るdx,dyをグローバル変数にしたことによる問題の解決策その2。
ボールが1個であれば問題ありません。1つある時にはボタンを押せないようにします。
MoveDisk7.javaをもとに変更するように説明しますが、MoveDisk6.javaからでもできます。
actionPerformedに書き加えます。setEnabled(false)がボタンを押せなくするメソッド。setText("busy")がボタンの表示を変えるメソッドで、busyに変えて押せなくしていることを知らせます。
//イベント処理 @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == rbtn) { rbtn.setEnabled(false); rbtn.setText("busy"); Thread thread = new moveDisk(mypnl,buffimg); thread.start();
1つになってしまうとつまらないので、このボールを障害物にあてて消していくゲームにしたてます。
障害物を複数作れるようにTargetというクラスで表し、配列にします。
これもインナークラスとして、moveDiskのあとにつなげましょう。
}//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のフィールドにこの配列を加えます。tmaxは障害物の数をあとで変更できるように導入しました。
int gctgrn = 0;
int gctblu = 0;
int clct = 0;
int bnct = 0;
int tmax = 4;
Target[] ts = new Target[tmax];
この色の部分はあとでクリックの回数と壁への衝突回数を数えるために加えています。
障害物は配置される四角の大きさが決まってから作る必要があります。movdDiskのコンストラクタの中がいいでしょう。
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); } }
画面に書くのはスタートボタンを押したときにします。
public void run() { Graphics thg = image.createGraphics(); Color bc= new Color(255,255,191); //背景の色 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); } //thg.setColor(Color.red); //thg.drawString(getName(),x-90,y); //文字はいらない while ( true ){
ボールが通ったところが背景色になりますから、ぶつかっても半分削れるだけという現象が起こります。また、すべてクリアしたときに何かの動作を起こすためにも衝突判定が必要です。
runメソッド中のボールを動かしているwhile内に置かなければなりません。
while ( true ){ // .......ここにdx,dyの交換処理があります............ 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); //●で描くところ
この色の部分はクリアした障害物の数を数えているところです
たとえば上記のclctでクリア数を数えておき、tmaxとおなじになったらそのむねを表示する様にします。
このとき、同時にクリックした回数や、壁に跳ね返った数を別々に、あるいはその合計数をも表示する様に工夫します。この数を少なくすることを競うゲームとします。
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;
// ↑書く場所は現在の x,y の近くにするが、
// はみ出す場合は寄せる sx,sy
thg.drawString("Cleared",sx,sy);
// ↑ sx,sy に Cleared と書く
thg.drawString("Click "+(gctgrn+gctblu),sx,sy+16);
// ↑ sy+16 で1行下の場所を求め クリック数(gctgrn+gctblu)を書く
thg.drawString("Bounce "+bnct,sx,sy+16*2);
// ↑ sy+16*2 で2行下の場所を求め 壁に当たった数 bnct を書く
}
pnl.repaint();
MoveDisk5.java以来最初の動きは下になっていましたが、右に戻します。(これは好みの問題) dy=10, dx=0 を逆にすればよいだけです。)
やってみると消えない場合が出てきます。大きさが10で dx や dy が10ですから動きが粗いのでしょう。
そこで、一回に動く距離 int dx=10; を int dx=5; に変え、その代わりに Thread.sleep(100) を100から50にします。この値は int stime=50; として変数で指定するようにしました。難易度を調整しやすくします。動く距離が半分ですが時間も半分なので速さは理論的には同じです。
int d = 10; int dx = 5; int dy = 0; int stime = 50; int ctgrn; int ctblu;
100とあったところをこの変数にします。
try { Thread.sleep(stime); }
MoveDisk7.javaをもとにします
上記の様に働くようにし、動作を確認しなさい。