ダブル・バッファリングを用いて画面のちらつきを防止します。
"update()"メソッドをオーバーライド
画面がちらつく原因のひとつに"update()"メソッドがあります。"update()"メソッドは"repaint()"メソッドが呼び出されたときに呼び出され、画面をバックグラウンドで塗り潰してからpaint()メソッドを呼び出します。この「画面をバックグラウンドで塗り潰してから」というのがちらつきを起こしている原因です。したがって画面をバックグラウンドで塗り潰さないようにすればよいわけです。その方法は簡単で、以下ののように"update()"メソッドをオーバーライドするだけです。
public void update(Graphics g){ paint(g); }
上記を元に作成した例が次のコードです。
import java.applet.Applet; // アプレット作成時には必須 import java.awt.Graphics; // 画面に描画する時に必要 import java.awt.Color; // 色の設定時に必要 import java.awt.event.KeyAdapter; // キーイベント時に必要 import java.awt.event.KeyEvent; // キーイベント時に必要 import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class ShootingGame09 extends Applet implements Runnable{// Runnableを実装 **** 途中省略 **** // アプレットが停止するときにスレッドを終了させる public void stop(){ if(th != null){ th=null; } } |
public void update(Graphics g){ paint(g); } |
**** 途中省略 **** } |
ダブルバッファリングによるちらつき防止
"update()"メソッドをオーバーライドすることで、ちらつきがかなり改善されましたが、まだちらついている部分が残っています。残りのちらつきを改善するにはダブルバッファリングという手法を用います。これはオフスクリーン(仮想画面)を用意し、すべての画像をいったんこのオフスクリーンに書き込み、この書込みが終了した時点で画面に転送するというものです。
オフスクリーンを作成するには"Image"クラスを使用します。 次のように幅"WIDTH"、高さ"HGITH"のオフスクリーンを作成し、
Image offi = createImage(WIDTH, HEIGHT);次のようにオフスクリーンから"Graphics"クラスのオブジェクトを取得します。
Graphics offg = offi.getGraphics();各描画メソッドは、次のようにこの"offg"に描くようにします。
offg.drawString("Double Buffering");オフスクリーンへのすべての描画終了後、次のようにして画面(ディスプレイ)に転送します。
g.drawImage(offi,0,0,this);
上記を元に作成した例が次のコードです。
import java.applet.Applet; // アプレット作成時には必須 import java.awt.Graphics; // 画面に描画する時に必要 import java.awt.Color; // 色の設定時に必要 |
import java.awt.Image; //オフスクリーンイメージを描画するのに必要 |
import java.awt.event.KeyAdapter; // キーイベント時に必要 import java.awt.event.KeyEvent; // キーイベント時に必要 import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class ShootingGame09a extends Applet implements Runnable{// Runnableを実装 **** 途中省略 **** public void paint(Graphics g){ // 画面に描画するメソッド |
Image offi = createImage(WIDTH, HEIGHT); // オフスクリーンの作成 Graphics offg = offi.getGraphics(); // オフスクリーンからGraphicsオブジェクトを取得 |
// 背景を黒で描画 offg.setColor(new Color(0,0,0)); // 色の設定 offg.fillRect(0,0,300,400); // 幅300、高さ400の四角で塗り潰し if(game_continue){ // ゲーム継続中のみ、各キャラクターを表示する // 自機の描画 myplane.paint(offg); // ミサイルの描画 for(int i=0; i < NUMBER_OF_MISSILE; i++){ // ミサイルの生命数が1であれば描画 if(missile[i].getLife() == 1){ missile[i].paint(offg); } } // 敵機の描画 for(int i=0; i < NUMBER_OF_ENEMY; i++){ // 敵機の生命数が1であれば描画 if(enemy[i].getLife() == 1){ enemy[i].paint(offg); } } } else { // ゲーム継続中でなければ各文字列を表示する offg.setColor(new Color(255,0,255)); // 色の設定 if(high_score_flag) // "HIGH SCORE!!!"の表示 offg.drawString("HIGH SCORE!!!",100,160); offg.setColor(new Color(255,255,255)); // 色の設定 if(game_over) // "GAME OVER!"の表示 offg.drawString("GAME OVER!",100,180); if(game_complete) // "GAME COMPLETE!"の表示 offg.drawString("GAME COMPLETE!",100,180); // "CLICK TO START"の表示 offg.drawString("CLICK TO START",100,200); } // 得点などの表示 offg.setColor(new Color(255,255,0)); //色の設定 offg.drawString("SCORE: " + score,100, 10); //得点の表示 offg.drawString("HIGH SCORE: "+ high_score,200, 10);//最高得点の表示 // 自機の残り数の表示 offg.drawString("LIFE: ",0, 10); for(int i=0;i<myplane.getLife();i++){ offg.setColor(new Color(0,0,255)); offg.fillOval(25+i*11,0,10,10); } |
g.drawImage(offi,0,0,this); // オフスクリーンに描画された画像を画面に転送 |
} } |