円(ボール)を1個に限定する

解決策2

ボールが複数ある時に出るdx,dyをグローバル変数にしたことによる問題の解決策その2。

ボールが1個であれば問題ありません。1つある時にはボタンを押せないようにします。

moveDisk

MoveDisk7.javaをもとに変更するように説明しますが、MoveDisk6.javaからでもできます。

ファイル名 MoveDisk8.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つになってしまうとつまらないので、このボールを障害物にあてて消していくゲームにしたてます。

moveDisk

障害物を複数作れるようにTargetというクラスで表し、配列にします。

ファイル名 MoveDisk8.java の一部

これもインナークラスとして、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();

moveDisk

動きの修正

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);
}

課題

1.

MoveDisk7.javaをもとにします

上記の様に働くようにし、動作を確認しなさい。

ファイル名 MoveDisk8.java

もくじ

聖愛高等学校
http://www.seiai.ed.jp/
Last Modified