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

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

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

図 9.3.2.1 WarpHouse.javaの実行結果
座標に関する新しい命令
warp([x座標, y座標])
指定された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. 星を増やす