9 アニメーション入門(いままで作ったものを動かそう)

9.1 学習目標

9.2 アニメーションの基本

ここからはオブジェクト指向プログラミングを使って、アニメーションを作っていきたいと思います。

9.2.1 回る家

まず、下のプログラムを実行してみましょう。

リスト 9.2.1.1 RotateHouse.java
  1: /**
  2:  * タートルで書いた絵をまわすプログラム
  3:  * 
  4:  * Yoshiaki Matsuzawa
  5:  * 2003/06/16
  6:  */
  7: public class RotateHouse extends Turtle {
  8: 
  9: 	//起動処理
 10: 	public static void main(String[] args) {
 11: 		Turtle.startTurtle(new RotateHouse());
 12: 	}
 13: 
 14: 	//タートルを動かす処理
 15: 	public void start() {
 16: 
 17: 		House house = new House(); //家を生成
 18: 
 19: 		//アニメーションループ
 20: 		while (true) {
 21: 
 22: 			//待つ
 23: 			sleep(0.1); //0.1秒
 24: 
 25: 			//処理を行う
 26: 			house.rt(5);
 27: 
 28: 			//再描画する
 29: 			update();
 30: 		}
 31: 
 32: 	}
 33: 
 34: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

ここでは、Houseのプログラムオブジェクトとして生成しています。 つまり、いままでタートルで作った絵を使うことができるのです。

タートルを使って自分の作ったオブジェクトを生成するには、次のようなプログラムを書きます。

図 9.2.1.1 オブジェクトの生成
使うオブジェクトを書くプログラムは同じフォルダに置く

例えば、RotateHouse.javaアニメーションで、House.javaを使う場合は、 その2つを同じフォルダに置く必要があります。

同じフォルダに置いていないとコンパイルエラーが出るので注意してください。

9.2.2 アニメーションの基本構造

RotateHouse.javaをもう一度よく見てみましょう。 特に、

while(true){
	//待つ
	
	//処理
	
	//再描画
}
				

ここの部分が、今までと異なる所で、アニメーションをするプログラムの特徴です。 どのようなアニメーションをするプログラムでも基本構造は同じです。 図解すると下のようになります。

図 9.2.2.1 アニメーションプログラムの構造
図 9.2.2.2 アニメーションプログラムの構造(具体的)

ちなみに、House.javaは次のようなプログラムでした。

リスト 9.2.2.1 House.java
  1: /*
  2:  * 家を書くプログラム
  3:  * 2003/05/08
  4:  * Yoshiaki Matsuzawa
  5:  */
  6: public class House extends Turtle {
  7: 
  8: 	//起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new House());
 11: 	}
 12: 
 13: 	//タートルを動かす処理
 14: 	public void start() {
 15: 
 16: 		//屋根を書く
 17: 		rt(30); //30度右を向く
 18: 		fd(50); //50歩前に進む
 19: 		rt(120);
 20: 		fd(50);
 21: 		rt(120);
 22: 		fd(50);
 23: 
 24: 		//本体を書く
 25: 		lt(90);
 26: 		fd(50);
 27: 		lt(90);
 28: 		fd(50);
 29: 		lt(90);
 30: 		fd(50);
 31: 		lt(90);
 32: 		fd(50);
 33: 
 34: 	}
 35: 
 36: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

9.2.3 アニメーションをするための新しい命令

sleep( ?? )
??秒眠り(止まり)ます。1を入れれば1秒止まり、0.1入れれば0.1秒止まります。
update()
画面を書き換えます。画面を書き換えないと、fd(5)などで移動しても、画面は書き換わらない(動かない)ので注意してください。
何秒眠るか

sleep()命令の中の数字を小さくすることによって、アニメーションを早くすることができます。 しかし、コンピュータの能力にも限界があります。 軽いアニメーションならば0.01秒(秒間100コマ)ぐらいまでならなんとか動きますが、 画像などを使うといくら小さい値を入れても、コンピュータの計算が追いつかなくなります。

人間が目に分かるのは、秒間30コマまでといわれています(テレビがそれぐらいです)ので、 それぐらいを目安に数値を決めると良いでしょう。

9.2.4 円を描く家

オブジェクトになっても、基本的なタートルの命令はどれでも使うことができます。 次のプログラムは、円を描く家のプログラムです。

リスト 9.2.4.1 CircleHouse.java
  1: /**
  2:  * 家で円を描くプログラム
  3:  * 
  4:  * Yoshiaki Matsuzawa
  5:  * 2003/06/16
  6:  */
  7: public class CircleHouse extends Turtle {
  8: 
  9: 	//起動処理
 10: 	public static void main(String[] args) {
 11: 		Turtle.startTurtle(new CircleHouse());
 12: 	}
 13: 
 14: 	//タートルを動かす処理
 15: 	public void start() {
 16: 
 17: 		House house = new House(); //家を生成
 18: 
 19: 		//赤い軌跡を描く準備
 20: 		house.color(java.awt.Color.red);
 21: 		house.down();
 22: 
 23: 		//アニメーションループ
 24: 		while (true) {
 25: 
 26: 			//待つ
 27: 			sleep(0.1); //0.1秒
 28: 
 29: 			//処理を行う
 30: 			house.rt(5);
 31: 			house.fd(5);
 32: 
 33: 			//再描画する
 34: 			update();
 35: 		}
 36: 
 37: 	}
 38: 
 39: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

down() 命令で、ペンを下ろして軌跡が描かれるようになっています。

図 9.2.4.1 円を描く家
初期値

いままでのタートルでは、down()命令をしなくても、 最初はペンを下ろした状態から始まっていました。

しかし、アニメーションでは、軌跡は要らないことが多いので、 初期値がペンを上げた状態になっています。

プログラムを書くときには、"最初の状態"を意識する必要があります。 これを「初期値」や「デフォルト値」といいます。

9.3 座標の制御

9.3.1 上向きのまま右に動かす

次に示すのは、家が右に動いていくプログラムです。

リスト 9.3.1.1 MoveRightHouse1.java
  1: /**
  2:  * 家を右に動かすプログラム
  3:  * 其の1 : 右に向けて動かす方法
  4:  * 
  5:  * Yoshiaki Matsuzawa
  6:  * 2003/06/16
  7:  */
  8: public class MoveRightHouse1 extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new MoveRightHouse1());
 13: 	}
 14: 
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 
 18: 		House house = new House(); //家を生成
 19: 
 20: 		house.rt(90); //右に向ける
 21: 
 22: 		//アニメーションループ
 23: 		while (true) {
 24: 
 25: 			//待つ
 26: 			sleep(0.1); //0.1秒
 27: 
 28: 			//処理を行う
 29: 			house.fd(5);
 30: 
 31: 			//再描画する
 32: 			update();
 33: 		}
 34: 		
 35: 	}
 36: 
 37: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

今までの方法では、前か後ろにしか進めませんが、 家は上向きのまま、右に動かしたい場合があります。

いままでの方法でも、下のように工夫することによって目的は達成できますが、 ここでは、warp命令を使ったエレガントな解決方法を考えます。

リスト 9.3.1.2 MoveRightHouse2.java
  1: /**
  2:  * 家を右に動かすプログラム
  3:  * 其の2 : 上に向いたまま右に動かす
  4:  * 
  5:  * Yoshiaki Matsuzawa
  6:  * 2003/06/16
  7:  */
  8: public class MoveRightHouse2 extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new MoveRightHouse2());
 13: 	}
 14: 
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 
 18: 		House house = new House(); //家を生成
 19: 
 20: 		//アニメーションループ
 21: 		while (true) {
 22: 
 23: 			//待つ
 24: 			sleep(0.1); //0.1秒
 25: 
 26: 			//処理を行う
 27: 			house.rt(90);
 28: 			house.fd(5);
 29: 			house.lt(90);
 30: 
 31: 			//再描画する
 32: 			update();
 33: 		}
 34: 
 35: 	}
 36: 
 37: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

9.3.2 ワープを使う

warp命令を使うと、回転せずに、好きな所にオブジェクトを移動することができます。

リスト 9.3.2.1 WarpHouse.java
  1: /**
  2:  * 家を右に動かすプログラム
  3:  * 其の4 : 右端に行ったら左端に戻す(ワープを使う)
  4:  * 
  5:  * Yoshiaki Matsuzawa
  6:  * 2003/06/16
  7:  */
  8: public class WarpHouse extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new WarpHouse());
 13: 	}
 14: 
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 
 18: 		House house1 = new House(); //家1を生成
 19: 		House house2 = new House(); //家2を生成
 20: 		House house3 = new House(); //家3を生成
 21: 		House house4 = new House(); //家4を生成
 22: 
 23: 		//アニメーションループ
 24: 		while (true) {
 25: 
 26: 			// --- 待つ ---
 27: 			sleep(0.1); //0.1秒
 28: 
 29: 			// --- 処理を行う ---
 30: 			house1.warp(100, 100);
 31: 			house2.warp(100, 200);
 32: 			house3.warp(200, 100);
 33: 			house4.warp(200, 200);
 34: 
 35: 			// --- 再描画する ---
 36: 			update();
 37: 		}
 38: 
 39: 	}
 40: 
 41: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

このプログラムの実行結果は以下のようになります。

図 9.3.2.1 WarpHouse.javaの実行結果
座標に関する新しい命令
warp( ?? , ??)
x, yの位置そのオブジェクトをワープさせます。命令に数字2つ必要なので、カンマで区切るのを忘れずに。
getX()
現在のx座標を取得します。
getY()
現在のy座標を取得します。

ちなみに、一般にコンピュータ環境では、数学とはちょっと違った座標体系が使われます。 タートルの場合もそうです。以下のようになっているので気をつけてください。

図 9.3.2.2 タートルの座標体系

さあ、ワープを使って、家を右に移動しましょう。

リスト 9.3.2.2 MoveRightHouse3.java
  1: /**
  2:  * 家を右に動かすプログラム
  3:  * 其の3 : 上に向いたまま右に動かす(ワープを使う)
  4:  * 
  5:  * Yoshiaki Matsuzawa
  6:  * 2003/06/16
  7:  */
  8: public class MoveRightHouse3 extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new MoveRightHouse3());
 13: 	}
 14: 
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 
 18: 		House house = new House(); //家を生成
 19: 
 20: 		int x; //x座標を入れる変数
 21: 		int y; //y座標を入れる変数
 22: 
 23: 		//アニメーションループ
 24: 		while (true) {
 25: 
 26: 			//待つ
 27: 			sleep(0.1); //0.1秒
 28: 
 29: 			//処理を行う
 30: 			x = house.getX(); //家のx座標を取得する
 31: 			y = house.getY(); //家のy座標を取得する
 32: 			house.warp(x + 5, y); //右に移動
 33: 
 34: 			//再描画する
 35: 			update();
 36: 		}
 37: 
 38: 	}
 39: 
 40: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

さらに、右端までいったら左端にワープするように改造します。

リスト 9.3.2.3 MoveRightHouse4.java
  1: /**
  2:  * 家を右に動かすプログラム
  3:  * 其の4 : 右端に行ったら左端に戻す(ワープを使う)
  4:  * 
  5:  * Yoshiaki Matsuzawa
  6:  * 2003/06/16
  7:  */
  8: public class MoveRightHouse4 extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new MoveRightHouse4());
 13: 	}
 14: 
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 
 18: 		House house = new House(); //家を生成
 19: 
 20: 		int x; //x座標を入れる変数
 21: 		int y; //y座標を入れる変数
 22: 
 23: 		//アニメーションループ
 24: 		while (true) {
 25: 
 26: 			// --- 待つ ---
 27: 			sleep(0.1); //0.1秒
 28: 
 29: 			// --- 処理を行う ---
 30: 			x = house.getX(); //家のx座標を取得する
 31: 			y = house.getY(); //家のy座標を取得する
 32: 
 33: 			//右に移動
 34: 			house.warp(x + 5, y);
 35: 
 36: 			//右端だったら左端にワープ
 37: 			if (x >= 300) {
 38: 				house.warp(0, y);
 39: 			}
 40: 
 41: 			// --- 再描画する ---
 42: 			update();
 43: 		}
 44: 
 45: 	}
 46: 
 47: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

だんだんアニメーションらしくなってきました。

9.4 大きさの変更(拡大/縮小)

9.4.1 大きさを変更するプログラム

オブジェクトは、大きさを変更することもできます。

リスト 9.4.1.1 LargeHouse.java
  1: /**
  2:  * 家を大きくするプログラム
  3:  * 其の1 : 大きさを測る
  4:  * 
  5:  * Yoshiaki Matsuzawa
  6:  * 2003/06/16
  7:  */
  8: public class LargeHouse extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new LargeHouse());
 13: 	}
 14: 
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 
 18: 		House house = new House(); //家を生成
 19: 
 20: 		//アニメーションループ
 21: 		while (true) {
 22: 
 23: 			// --- 待つ ---
 24: 			sleep(0.1); //0.1秒
 25: 
 26: 			// --- 処理を行う ---
 27: 
 28: 			//家を大きくする
 29: 			house.size(200, 200);
 30: 
 31: 			// --- 再描画する ---
 32: 			update();
 33: 		}
 34: 
 35: 	}
 36: 
 37: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

大きさに関する新しい命令
size( ?? , ??)
そのオブジェクトを横、縦の大きさにします。命令に数字2つ必要なので、カンマで区切るのを忘れずに。
getWidth()
現在の横幅を取得します。
getHeight()
現在の縦幅を取得します。

9.4.2 徐々に大きくする

アニメーションループをうまく利用すれば、徐々に大きくなっていくプログラムが書けます。

リスト 9.4.2.1 LargerHouse.java
  1: /**
  2:  * 家を大きくするプログラム
  3:  * 其の1 : 大きさを測る
  4:  * 
  5:  * Yoshiaki Matsuzawa
  6:  * 2003/06/16
  7:  */
  8: public class LargerHouse extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new LargerHouse());
 13: 	}
 14: 
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 
 18: 		House house = new House(); //家を生成
 19: 
 20: 		int width; //width座標を入れる変数
 21: 		int height; //height座標を入れる変数
 22: 
 23: 		//アニメーションループ
 24: 		while (true) {
 25: 
 26: 			// --- 待つ ---
 27: 			sleep(0.1); //0.1秒
 28: 
 29: 			// --- 処理を行う ---
 30: 
 31: 			width = house.getWidth(); //家の横の長さを取得する
 32: 			height = house.getHeight(); //家の縦の長さを取得する
 33: 
 34: 			//家を大きくする
 35: 			house.size(width + 2, height + 2);
 36: 
 37: 			// --- 再描画する ---
 38: 			update();
 39: 		}
 40: 
 41: 	}
 42: 
 43: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

大きくなりすぎたら、小さく戻してあげましょう。

リスト 9.4.2.2 LargerHouse2.java
  1: /**
  2:  * 家を大きくするプログラム
  3:  * 其の2 : 大きくなりすぎたら小さくする
  4:  * 
  5:  * Yoshiaki Matsuzawa
  6:  * 2003/06/16
  7:  */
  8: public class LargerHouse2 extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new LargerHouse2());
 13: 	}
 14: 
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 
 18: 		House house = new House(); //家を生成
 19: 
 20: 		int width; //width座標を入れる変数
 21: 		int height; //height座標を入れる変数
 22: 
 23: 		//アニメーションループ
 24: 		while (true) {
 25: 
 26: 			// --- 待つ ---
 27: 			sleep(0.1); //0.1秒
 28: 
 29: 			// --- 処理を行う ---
 30: 
 31: 			width = house.getWidth(); //家の横の長さを取得する
 32: 			height = house.getHeight(); //家の縦の長さを取得する
 33: 
 34: 			//家を大きくする
 35: 			house.size(width + 2, height + 2);
 36: 
 37: 			//横幅が大きくなりすぎたら小さくする
 38: 			if (width >= 300) {
 39: 				house.scale(0.25); //0.25倍の大きさにする
 40: 			}
 41: 			//縦幅が大きくなりすぎたら小さくする
 42: 			if (height >= 300) {
 43: 				house.scale(0.25); //0.25倍の大きさにする
 44: 			}
 45: 
 46: 			// --- 再描画する ---
 47: 			update();
 48: 		}
 49: 
 50: 	}
 51: 
 52: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

大きさ変更に便利な命令
scale(??)
そのオブジェクトを??倍します。
large(??)
現在の大きさを横??、縦??大きくします。
small(??)
現在の大きさを横??、縦??小さくします。
wide(??)
現在の横幅を??大きくします。
narrow(??)
現在の横幅を??小さくします。
tall(??)
現在の縦幅を??大きくします。
little(??)
現在の縦幅を??小さくします。

9.5 練習問題

9.5.1 流れ星アニメーションを作ろう

星を書くプログラム(Star.java)を使って、流れ星のプログラムを書いてみて下さい。

ダウンロードはこちらから

流れ星は、次の手順で進めていくとうまくできます。

  1. Star.javaをダウンロードして動かしてみる
  2. ShootingStar.javaを新しく作る(Star.javaは変更しないこと)
  3. ShootingStar.javaに、Starオブジェクトを生成して表示するプログラムを書く
  4. 星を回してみる
  5. 座標を使って、星を右に動かしてみる
  6. 一番右端にいったら、左端に戻るようにする
  7. 星を下にも動かす
  8. 一番下にいったら、上に戻るようにする
  9. 星の大きさを変える
  10. 星を増やす