発展課題 (r1:キャンバス)

注意点

このページは復習 (1)の発展課題を掲載しています。発展課題については「復習回の課題について」をよく読んでから取り掛かってください。

作業について

今回の課題は以下のパッケージに作成してください。

パッケージの名前
j1.review01

作成するクラスの名前は問題ごとに指示があります。下記を参照してください

課題の提出方法については下記を参照してください。

また、別のコンピューター上に移動する際には、下記を参考にプログラムを持ち帰ってください。

新しい内容

一定時間待機する

1つ目はプログラムを一定時間待機する方法について紹介します。

package j1.review01;

import gpjava.Canvas;

public class CountdownS2 {

    public static void main(String[] args) {
        new CountdownS2().start();
    }

    void start() {
        Canvas.show();

        Canvas.drawOval(200, 200, 100, 100);
        Canvas.waitForCountdown(1000);

        Canvas.drawOval(50, 50, 100, 100);
        Canvas.waitForCountdown(500);

        Canvas.drawOval(350, 50, 100, 100);
        Canvas.waitForCountdown(500);

        Canvas.drawOval(350, 350, 100, 100);
        Canvas.waitForCountdown(500);

        Canvas.drawOval(50, 350, 100, 100);
    }
}

プログラムを実行すると、まず中央付近に円が描画されます。

図: 最初の状態

約1秒後に左上に円が描画されます。この「1秒後」というのは「Canvas.waitForCountdown」という命令を使って待機しています。引数の「1000」は待機している「1000ミリ秒」のことを表しています。

図: 1000ミリ秒後の状態

続けて、0.5秒おきに左上、右下、左下の順に円が描画されます。それぞれ、500ミリ秒ずつ待機してから描画を行っています。

図: 最終的な状態

待機時間を短くしていくと、より滑らかに描画が進んでいくように見えるはずです。実際にコンピューターでは1秒間に60回から100回程度、映画では1秒間に25回程度の描画を行ってただの絵をすばやく切り替えることでものが動いているように見せかけています。

まとめると、「Canvas.waitForCountdown」という命令を使うと一時的にプログラムの実行を待機できます。これを短い時間ですばやく繰り返すことで、キャンバスを使ってアニメーションを表示できます。

Canvas.waitForCountdown([待機する時間(ミリ秒)]);

描画した内容の消去

2つ目はキャンバスに描画した内容を消去する方法について紹介します。

package j1.review01;

import gpjava.Canvas;

public class ClearS2 {

    public static void main(String[] args) {
        new ClearS2().start();
    }

    void start() {
        Canvas.show();

        Canvas.drawOval(200, 200, 100, 100);
        Canvas.waitForCountdown(1000);

        Canvas.clear();
        Canvas.drawOval(50, 50, 100, 100);
        Canvas.waitForCountdown(500);

        Canvas.clear();
        Canvas.drawOval(350, 50, 100, 100);
        Canvas.waitForCountdown(500);

        Canvas.clear();
        Canvas.drawOval(350, 350, 100, 100);
        Canvas.waitForCountdown(500);

        Canvas.clear();
        Canvas.drawOval(50, 350, 100, 100);
    }
}

これは先ほどのプログラムと似通っていて、プログラムを実行するとまず中央付近に円が描画されます。

図: 最初の状態

約1秒後に左上に円が描画されます。ただし、このとき「Canvas.clear」という命令を使って、中央の円を消去した後に左上の円が描画されます。

図: 1000ミリ秒後の状態

同様に、0.5秒おきに左上、右下、左下の順に円が描画されます。いずれも、直前までの描画内容を消去してから新しく円を描画します。

図: 最終的な状態

このように、先ほどの待機と、今回の消去を組み合わせると、さまざまなアニメーションをキャンバスに表示できます。アニメーションを行うには、1コマ目の最初に「Canvas.clear」という命令でこれまでの内容を消去して、そのコマの最後に「Canvas.waitForCountdown」という命令で一定時間待機させます。

Canvas.clear();
… (アニメーションの1コマ分を描画する) …
Canvas.waitForCountdown([待機する時間(ミリ秒)]);

問題

回転する星

作成するクラスの名前
AnimationS2

正5角形の対角線だけを描画したような星が、18度ずつ回転するようなアニメーションを表示するプログラムを作成してください。

まず、キャンバスに下記のような星の図形を描画してください。

図: 星の図形

次に、100ミリ秒程度待機したら、ここまでの描画内容を消去して先ほどの図形を時計回りに18度(1/20回転)した図形を描画してください。このとき、図形の中心をずらさないようにしてください。

図: 100ミリ秒後の図形

あとはこれの繰り返しで、18度回転して100ミリ秒程度待機、というものを合計で20回行います。

図: 200ミリ秒後の図形

18度回転させることを20回繰り返すと、元の図形に戻ります。そこでアニメーションを終了させてください。

図: 360度回転した図形

なお、正弦は「Math.sin([角度])」、余弦は「Math.cos([角度])」でそれぞれ計算できます。角度には次のようにラジアンで指定してください。

double s = Math.sin(0.5 * 3.14);
double c = Math.cos(1.5 * 3.14);

ヒント

今回は回転をアニメーションで描画するので、極座標系をキャンバス上の直交座標系(XY座標)に変換すると楽です。極座標とは原点から伸びた線分(動径)と、その動径の傾き(偏角)で平面上の位置を表すものです。

動径が1のとき、偏角とXY座標の関係は次のようになります。

偏角 (ラジアン) x y
0.0 * 3.14 +1 0
0.5 * 3.14 0 +1
1.0 * 3.14 -1 0
1.5 * 3.14 0 -1

今回は、(250, 250)を原点として、長さ200の動径を使って正5角形の頂点の座標を計算することになります。キャンバス中央上部の点は偏角「1.5 * 3.14」となり、X座標, Y座標は次のように計算できます。

double x = 250 + 200 * Math.cos(1.5 * 3.14);
double y = 250 + 200 * Math.sin(1.5 * 3.14);

なお、これは次のように書くこともできます (y座標の計算に – を使っているところに注意してください)。

double x = 250 + 200 * Math.sin(0.0 * 3.14);
double y = 250 - 200 * Math.cos(0.0 * 3.14);

上記を踏まえて、正五角形の頂点の座標を計算してみましょう。

ヒント

以下の説明は適切でなかったため、一つ手前の「ヒント」を参考にしてください。

今回は回転をアニメーションで描画するので、極座標系をキャンバス上のXY座標系に変換する必要があります。(250, 250)を原点として長さ200の円と偏角rがあるとき、X座標は次のように計算できます。

double x = 250 + 200 * Math.sin(r);