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

注意点

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

作業について

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

パッケージの名前
j1.review02

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

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

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

新しい内容

今回は復習 (1)の発展課題の内容を使います。そちらを先に解いてください。

ダブルバッファリング

今回はアニメーションのちらつきを抑える方法を紹介します。

package j1.review02;

import gpjava.Canvas;

public class DoubleBufferingS2 {

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

    void start() {
        Canvas.show();
        Canvas.disableAutoRepaint();
        for (int i = 0; i < 10; i++) {
            drawFrame(i);
        }
    }

    void drawFrame(int i) {
        Canvas.clear();
        for (int x = 0; x < 50; x++) {
            for (int y = 0; y < 500; y++) {
                Canvas.drawLine(
                    x + i * 50, y,
                    x + i * 50, y);
            }
        }
        Canvas.forceRepaint();
        Canvas.waitForCountdown(50);
    }
}

前回の発展課題では、キャンバスでアニメーションを行う方法について紹介しました。

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

しかしこの方法は、「描画した内容を消去する」「徐々に描画する」ということを行う過程で毎回キャンバス上に描画した内容が反映されてしまいます。つまり、「徐々に描画する」という途中の状態のものが画面上に表示されてしまいます。

キャンバスには、「Canvas.disableAutoRepaint」と、「Canvas.forceRepaint」の2つの命令を用意しています。前者は「キャンバスに描画した内容を画面上に反映しない」という命令で、後者は「キャンバスに描画した内容を1回だけ画面上に反映する」という命令です。これらを組み合わせて利用すると、好きなタイミングで描画した内容を画面上に表示させられます。つまり、描画している途中のものを隠すことができます。

このプログラムから「Canvas.disableAutoRepaint();」という部分を削除して実行してみてください。描画の途中のものが表示されて画面がちらつくようになるかもしれません。(コンピューターの処理能力にもよりますので、場合によってはちらつきなく表示されます)

このような技術を「ダブルバッファリング」と呼びます。描画した内容を「オフスクリーンバッファー」という画面には表示しない領域に記憶させておいて、特定のタイミングでその内容を画面上に反映させます。

ダブルバッファリングを利用する場合には、下記のように「Canvas.disableAutoRepaint」という命令を最初に1回だけ書き、アニメーションの1コマ分を描画し終わったら毎回「Canvas.forceRepaint」を書くようにします。

Canvas.disableAutoRepaint();


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

すると、キャンバスに対して行った描画は画面上に反映されませんが、「Canvas.forceRepaint」を実行した瞬間に、一気に画面上に反映されるようになります。ちらつきが気になったらこの「ダブルバッファリング」という方法を試してみてください。

問題

動き回るボール

作成するクラスの名前
MovingBallS2

幅300, 高さ400のワクの中で、半径10のボールが動き回るアニメーションをキャンバスに描画するプログラムを作成してください。

ボールは枠に当たると跳ね返って、ワクと逆方向に進みます。今回はボールの摩擦や、重力等を考慮しなくて構いません。また、ボールと壁の反発係数は1として、エネルギーが保存されると仮定してください。

図: ワクとボール

なお、ボールはキャンバスの中央からスタートして、X方向の初速とY方向の初速を入力ダイアログから入力できるようにしてください。初速の単位は自由に決めて構いませんが、「アニメーションの1コマで進む速度」としておくと楽です。

アニメーションは次のように、1000回描画するようにしてください。

for (int i = 0; i < 1000; i++) {
    Canvas.clear();
    … (ボールやワクを描画する) …
    Canvas.waitForCountdown(20);
}

待機の幅を短くしたり、ボールの残像を描画したりするとより滑らかに動くように見えます。余裕があればさまざまな描画方法を試してみてください。また、重力や摩擦を考慮に入れてみるのも面白いと思います。