今度は自動的にボールが跳ね返るようにしました。
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