update(Graphics g) と paint(Graphics g)

   2012/07/15

プログラミングができるようになったらゲームを作りたいと
思っている人は多いと思います。

毎度、管理人イガジーです。

(パソコン上で動く)Java自体は、グラフィックの描画が
あまり速くないので、シューティングゲームの様な動きの激しいものは
あまり向いていないと思います(工夫の余地はあるかもしれませんが)。

Javaのグラフィック描画は、repaint() を発行すると、update()が呼ばれ
次にpaint()が呼ばれるようになっています。

隠れていた窓が(クリックされたりして)表に出た時などは
自動的に repaint()が発行されます。
グラフィック描画をしたつもりなのに、表示に反映されない時は
他の窓で隠して再度表示させると、表示が更新されたりします。
こういう場合はたいてい repaint() 忘れです。

repaint()を頻繁に発行するとちらついたりするのですが、その理由は
update(Graphics g) が一旦全体をクリアしてから paint(Graphics g) を
呼ぶからです。
ですから、もしも、クリア不要であれば update() を Override して
paint()を呼ぶようにするとチラツキを抑えることができる場合があります。
ただし、きちんと描画されないケースが出てくる可能性が生じます。
テスト用にタイマーで描画するプログラムを作ってみました。

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.Timer;
import java.util.TimerTask;

public class AnimationTest {
	final int bww=30, bhh=30;
	Frame f;
	MyCanvas cv;
	Timer tmr;

	AnimationTest() { // constructor
		f=new Frame("AnimationTest");
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent ev) {
				System.exit(0);
			}
		});
		cv=new MyCanvas();
		f.add(cv,BorderLayout.CENTER);
		Button btn=new Button("Stop");
		btn.addActionListener(new DbgBtn());
		f.add(btn,BorderLayout.SOUTH);
		tmr=new Timer();
		tmr.schedule(new MyTimer(), 1000, 100);
		f.setSize(300,300);
		f.setVisible(true);
	}
	class MyTimer extends TimerTask {
		int vx=4;
		int vy=2;
		public void run() {
			cv.x+=vx;
			cv.y+=vy;
			if ((cv.x<=0)||(cv.x>=200)) vx=-vx;
			if ((cv.y<=0)||(cv.y>=160)) vy=-vy;
			cv.repaint();
		}
	}
	class DbgBtn implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent arg0) {
			tmr.cancel();
		}
	}
	class MyCanvas extends Canvas {
		private static final long serialVersionUID = 1L;
		BufferedImage b;
		Graphics g;
		int x,y;
		MyCanvas() {
			x=y=0;
			b=new BufferedImage(bww,bhh, BufferedImage.TYPE_INT_RGB);
			g=b.getGraphics();
			g.setColor(Color.YELLOW);
			g.fillRect(4, 4, bww-8, bhh-8);
			this.setBackground(Color.BLACK);
		}
		@Override
		public void update(Graphics g0){
			paint(g0);
		}
		@Override
		public void paint(Graphics g0) {
			g0.drawImage(b,x,y,f);
		}
	}

	public static void main(String[] args) {
		new AnimationTest();
	}
}

黄色の■をタイマーで100msごとに動かすプログラムです。
update()をOverrideしていますが、それをやめると、即ち

@Override
public void update(Graphics g0){
	paint(g0);
}

を削除すると、チラツクと思います。チラツクというより、全く
描画されなくなるタイミングも生じます。(Linux上でしか試していないので
Windowsではどうなるか不明ですが)。
タイマー周期の
tmr.schedule(new MyTimer(), 1000, 100);の部分を変えて試してみてください。
(あまり小さくすると処理が追いつかなくなって不具合が起きるかもしれません。)
※ 上記のコードの改良版は、→こちら をご覧ください。

この記事へのコメントはこちら

メールアドレスは公開されませんのでご安心ください。
また、* が付いている欄は必須項目となりますので、必ずご記入をお願いします。

内容に問題なければ、下記の「コメント送信」ボタンを押してください。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)