- PR -

BufferStrategyとjava.util.timerについて

1
投稿者投稿内容
遊良遊
会議室デビュー日: 2003/04/09
投稿数: 3
投稿日時: 2003-04-09 16:06
始めまして。遊良遊と申します。

早速ですが、BufferStrategyで判らない点が有り質問をさせて頂きます。
↓のSunのチュートリアルなどを参考にしてフルスクリーン表示のプログラムを実験的に作っておりました。
http://java.sun.com/docs/books/tutorial/extra/fullscreen/index.html

このページにあるサンプルでは、for文とsleepを使っているのですが、『ゲームとか作るのにはTimerを使った方が良いかな?』と思い、下記の様なソースを書いてみました。

ところが、『Graphics g = bufferStrategy.getDrawGraphics();』の部分でIllegalStateExceptionが発生してしまいました。
SDKのドキュメントなどをあたってみましたが、解決策を見つけることが出来ませんでした。
この例外は、Windowが表示出来ないときにthrowされるとの事ですが、これをどの様に解決すれば良いのか判りませんでした。

この問題に関する解決策、あるいは、私のソースの問題点が判る方がいらっしゃいましたら、是非ご教授をお願い致します。

なお、device,mainFrame,bufferStrategy,timer,rendererはインスタンス変数となっております。
また、rendererのdorowメソッドは引数Graphics g に対して、描画を行っております。

コード:

try {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
device = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = device.getDefaultConfiguration();
mainFrame = new Frame(gc);
mainFrame.setUndecorated(true);
mainFrame.setIgnoreRepaint(true);
device.setFullScreenWindow(mainFrame);
if (device.isDisplayChangeSupported()) {
device.setDisplayMode(mode);
}
mainFrame.createBufferStrategy(2);
bufferStrategy = mainFrame.getBufferStrategy();
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
try {
Graphics g = bufferStrategy.getDrawGraphics();
if (!bufferStrategy.contentsLost()) {
renderer.drow(g);
bufferStrategy.show();
g.dispose();
}
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}, 1000, 1000 / 15);

} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
device.setFullScreenWindow(null);
}



[ メッセージ編集済み 編集者: 遊良遊 編集日時 2003-04-09 16:09 ]
遊良遊
会議室デビュー日: 2003/04/09
投稿数: 3
投稿日時: 2003-04-09 18:02
失礼しました。馬鹿な質問をしてしまいました。

finalyでwindowを閉じてれば、例外出るのは当たり前ですね。
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2003-04-09 18:03
こんにちは。さくらばです。

引用:

遊良遊さんの書き込み (2003-04-09 16:06) より:

ところが、『Graphics g = bufferStrategy.getDrawGraphics();』の部分でIllegalStateExceptionが発生してしまいました。
SDKのドキュメントなどをあたってみましたが、解決策を見つけることが出来ませんでした。



BufferStrategy を使用するして描画するときには、BufferStrategy を作成した
スレッドでしか使用することができないためです。

Timer を使ってしまうと別スレッドになってしまうので、これをどうにかして
描画部分はメインスレッドで扱えるようにすればいいわけです。

ただ、メインスレッドで for と sleep を使って描画すると時間ずれが発生し
てしまうので、ゲームにはむかないですね。

それではどうしようかということで、wait - notify を使用したサンプルを添
付しておきます。

メインスレッドは描画が終了すると wait 状態に入ります。Timer スレッドでは
定期的にメインスレッドに対して notify をコールして、メインスレッドを起こ
すようにしています。

コード:
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferStrategy;
import java.util.Timer;
import java.util.TimerTask;

public class StrategyBufferTest {
    private static final int WIDTH = 640;
    private static final int HEIGHT = 480;
    private static final int DEPTH = 16;
    private static final int BUFFER_SIZE = 2;

    private static Color[] colors = new Color[] {Color.red, Color.blue};

    public StrategyBufferTest(){

        GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice device = env.getDefaultScreenDevice();
        GraphicsConfiguration gc = device.getDefaultConfiguration();
        DisplayMode mode = new DisplayMode(WIDTH, HEIGHT, DEPTH,
                                           DisplayMode.REFRESH_RATE_UNKNOWN);

        Frame frame = new Frame(gc);
        frame.setLayout(null);
        frame.setIgnoreRepaint(true);
        frame.setUndecorated(true);
        device.setFullScreenWindow(frame);
        device.setDisplayMode(mode);

        try{
            frame.createBufferStrategy(BUFFER_SIZE);
            BufferStrategy bufferStrategy = frame.getBufferStrategy();

            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask() {
                public void run() {
                    synchronized (StrategyBufferTest.this) {
                        StrategyBufferTest.this.notifyAll();
                    }
                }
            }, 1000L, 1000L);

            while(true){
                try {
                    for (int i = 0 ; i < BUFFER_SIZE ; i++) {
                        Graphics g = bufferStrategy.getDrawGraphics();
                        if(!bufferStrategy.contentsLost()){
                            g.setColor(colors[i]);
                            g.fillRect(0, 0, WIDTH, HEIGHT);
                            g.setFont(new Font("Helvetica", Font.PLAIN, 24));
                            g.setColor(Color.black);
                            g.drawString("Buffer No." + i, 10, HEIGHT / 2);
                            bufferStrategy.show();
                            g.dispose();
                        }

                        synchronized (this) {
                            try {
                                wait();
                            } catch (InterruptedException ex) {
                                ex.printStackTrace();
                            }
                        }
                    }
                }catch (IllegalStateException ex){
                    ex.printStackTrace();
                    break;
                }

            }

        } finally {
            device.setFullScreenWindow(null);
        }
    }

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


遊良遊
会議室デビュー日: 2003/04/09
投稿数: 3
投稿日時: 2003-04-09 19:03
さくらば様。ありがとうございます。

IllegalStateExceptionが発生するのは単にfinallyでフルスクリーンを閉じてしまっている事が原因でした。
メインスレッドでWindowを非表示にしてしまっているにも関わらず、Timerスレッドの方でBufferStrategyのgetDrawGraphics()を呼び出している為に例外がしていました。
これは、for文を使用したsunのサンプルをコピペした時に、そのまま残してしまった物でした。

finally節を削除したところ期待通りの動作となり、ご指摘頂きました別スレッドからの呼び出しに関しましては、特に問題は見受けられませんでした。
これは、別スレッドからBufferStrategyを参照しても大丈夫という事なのか、それとも別の問題が発生する可能性が有るのでしょうか?


ところで、突然で大変不躾ですが実はさくらば様の「J in the Box」の1.4の新機能に関する記事を読んだことがきっかけで有ると共に、参考とさせて頂きました。

[ メッセージ編集済み 編集者: 遊良遊 編集日時 2003-04-09 19:11 ]
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2003-04-09 22:50
こんにちは、さくらばです。

引用:

遊良遊さんの書き込み (2003-04-09 19:03) より:

IllegalStateExceptionが発生するのは単にfinallyでフルスクリーンを閉じてしまっている事が原因でした。
メインスレッドでWindowを非表示にしてしまっているにも関わらず、Timerスレッドの方でBufferStrategyのgetDrawGraphics()を呼び出している為に例外がしていました。
これは、for文を使用したsunのサンプルをコピペした時に、そのまま残してしまった物でした。

finally節を削除したところ期待通りの動作となり、ご指摘頂きました別スレッドからの呼び出しに関しましては、特に問題は見受けられませんでした。
これは、別スレッドからBufferStrategyを参照しても大丈夫という事なのか、それとも別の問題が発生する可能性が有る
のでしょうか?



あっ、本当ですね。
スレッドに関しては、以前、同じような現象を経験したことがあったのです。
でも、よく思い出してみたら、そのときは J2SE 1.4 のベータの時だったので、
もしかしたら変わっていたのかもしれません。

なにはともあれ、通常に動作してよかったですね。

引用:

ところで、突然で大変不躾ですが実はさくらば様の「J in the Box」の1.4の新機能に関する記事を読んだことがきっかけで有ると共に、参考とさせて頂きました。

[ メッセージ編集済み 編集者: 遊良遊 編集日時 2003-04-09 19:11 ]



ありがとうございます。最近、雑誌への執筆や、セミナなどが重なって、Web は
あまり更新していないのですが、今月の終わりぐらいからは時間が取れそうなの
で、更新していきたいと思っています。
1

スキルアップ/キャリアアップ(JOB@IT)