今度は自動的にボールが跳ね返るようにしました。
import java.awt.*;
import java.applet.Applet;
public class Lesson3 extends Applet implements Runnable {
int x = 150, y = 50, dx = 10, dy = 10;
Thread ball;
public void init() {
setBackground(Color.white);
setForeground(Color.blue);
}
public void start() {
if (ball == null)
ball = new Thread(this, "Ball");
ball.start();
}
public void stop() {
ball = null;
}
public void paint(Graphics g) {
g.fillOval(x - 10, y - 10, 20, 20);
}
public void run() {
Thread thisThread = Thread.currentThread();
while (ball == thisThread) {
try {
thisThread.sleep(100); // sleep 100msec
} catch (InterruptedException e) {
break;
}
if (x <= 10 || x >= 290) dx = -dx;
if (y <= 10 || y >= 90) dy = -dy;
x += dx; y += dy;
repaint();
}
}
}
枠線は Java ではなく HTML の table タグで作りました:
<table border="1"> <tr><td><applet code="Lesson3.class" width="300" height="100"></applet></td></tr> </table>
このようなプログラムは,外からの指示がなくても,独立に動いてくれなければなりません。 他と独立に動くようなプログラムの部分をスレッド (thread) といいます。
スレッドを使うには,最初の
public class Lesson3 extends Applet
の次に
implements Runnable
というオマジナイが必要です。 Runnable とは,他と独立に run する(走る)ような部分を持つということです。
スレッドは変数に入れて使います。そのために,
Thread 型の変数をあらかじめ作っておきます。
その変数には,適当な名前を付けておきます。
ここではボールを動かすスレッドなので ball という名前にしましょう。
Thread ball;
スレッドは一つのプログラム内でいくつ作ってもかまいません。 スレッドが複数ある場合には,
Thread ball1, ball2;
のように,複数の変数を作る必要があります。
ここで作った Thread 型の変数は,作られた当初は null という特別な値を持ちます。
null は「何もないこと」を意味する英語です。
正しい英語の読み方は「ナル」ですが,日本では「ヌル」と読む人も多いようです。
Web ブラウザは,このアプレットを読み込むと,まずこの中の init()
を実行し,次に start() を実行します。
そして,このページを見終わって次のページに移るときは,アプレットの stop() を実行します。
そこで,start() ではスレッドの実行を開始し,stop()
ではスレッドの実行を止めるのが普通です。
そこで,start() メソッドには次のようなことを書いておきます。
public void start() {
if (ball == null)
ball = new Thread(this, "Ball");
ball.start();
}
これは,まだ ball が null(作られていない)なら,ball
に新しいスレッドを代入するという意味です。
new Thread(this, "Ball")
が新しいスレッドを作るためのオマジナイです。
最後の "Ball" はスレッドの名前です(この名前は省略できます)。
stop() では単に
public void stop() {
ball = null;
}
のようにします。
つまり,変数 ball に null を代入します。
スレッドそのものを stop するのは良くないようです。
スレッドの実際に動く部分は,必ず run() というメソッド名にしておきます。
ここでは次のようになっています。
public void run() {
Thread thisThread = Thread.currentThread();
while (ball == thisThread) {
try {
thisThread.sleep(100); // sleep 100msec
} catch (InterruptedException e) {
break;
}
if (x <= 10 || x >= 290) dx = -dx;
if (y <= 10 || y >= 90) dy = -dy;
x += dx; y += dy;
repaint();
}
}
ここではまず自分自身のスレッドを thisThread という変数に代入しています。
while (ball == thisThread) { ... }
は,thisThread が ball スレッドである間ずっと繰返しを続けるという意味です。
ただし,ループを回りっぱなしだと CPU
が他の仕事をするのに支障が出るので,毎回 Thread.sleep(100)
を実行して,100ミリ秒だけ休ませています。
この間に CPU は他の仕事ができるわけです。
Thread.sleep() を実行している間に,他から割り込みがかかることがあります。
ここでは割り込みがかかれば単に100ミリ秒の休止を中断するだけにします:
try {
thisThread.sleep(100); // sleep 100msec
} catch (InterruptedException e) {
break;
}
その次の
if (x == 10 || x == 290) dx = -dx;
if (y == 10 || y == 90) dy = -dy;
x += dx; y += dy;
repaint();
の部分では,x 座標が 10 または 290 なら x 軸に沿っての動く向きを逆にし,また y 座標が 10 または 90 なら y 軸に沿っての動く向きを逆にし,x,y 座標を更新し,最後に repaint() を実行します。
この repaint() は,CPU に余裕ができ次第 paint() を実行する,という意味です。
paint() メソッドは
public void paint(Graphics g) {
g.fillOval(x - 10, y - 10, 20, 20);
}
となっていますので,x,y 座標の値を中心として半径が 10 の円が描かれます。
Last modified: 2005-12-29 10:57:29