質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.23%

ダブルバッファリングしたら重くなりました

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 278

Swingを使って2Dスクロールゲームを作るときに、ダブルバッファリングを実装したのですが、バッファイメージのサイズを大きくすると動きが遅くなってしまいました。以下はその詳細です。何か分かることがございましたら、アドバイスをお願いします。

ダブルバッファリング実装方法

クラス[変数名]
JFrameにおいてインスタンス生成時に、createImage(this.getWidth(), this.getHeight())でバッファイメージImage[back]back.getGraphics()でそのグラフィクスGraphics[buffer]を変数として取得しておく。
・paint(Graphics g)をオーバーライドしてbufferに描画して、最後にgraphics.drawImage(back, 0, 0, this)でバッファイメージを描画する。
・componentResizedをオーバーライドしてImage[back]Graphics[buffer]を変更(更新)する。
・update(Graphics g)はオーバーライドしていない。

問題点

・実行してみて、画面を大きくすると動きが遅くなることに気がついた。
・フレームレートを測定すると、画面の大きさに比例して時間が遅くなっていた。
・試しに、graphics.drawImage(back, 0, 0, this)だけをコメントアウトすると画面は変わらないが、フレームレートは速くなった。
・試しに、paint(Graphics g)において、先頭でbuffer = g;を書くと(ダブルバッファリングしないようにすると)ちらつくが速くなった。
・試しに、インスタンス生成時にcreateImage(2000, 2000)とするとずっと遅くなった。

修正(該当のコード)

package orgmarigo.test;

import javax.swing.*;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;

import orgmarigo.util.Vector2;
import orgmarigo.util.TimeMeasure;//フレームレートを測定するクラス
import orgmarigo.util.MyUtilities;

public class ScreenTest extends JFrame implements ActionListener, ComponentListener{
  static public final Vector2 INITIAL_WINDOW_SIZE = new Vector2(630, 560);
  static public TimeMeasure timeMeasure = new TimeMeasure(100);
  static public final int FPS = 100;

  private Timer timer;
  private Image back;
  private Graphics buffer;
  private Image titleImage;

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

  public ScreenTest(){
    this.setTitle("ScreenTest");
    this.setBounds(300, 200, (int)INITIAL_WINDOW_SIZE.getX(), (int)INITIAL_WINDOW_SIZE.getY());
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    this.addComponentListener(this);

    this.setVisible(true);

    timer = new Timer(1000 / FPS, this);
    back = createImage(this.getWidth(), this.getHeight());//バッファイメージ
    buffer = back.getGraphics();//イメージのグラフィクス
    titleImage = MyUtilities.getImage("../images/title/TitleImage.jpg");

    timer.start();
  }

  @Override
  public void paint(Graphics graphics){
    if(buffer != null){
      //イメージの更新、描画
      buffer.clearRect(0, 0, this.getWidth(), this.getHeight());
      buffer.drawImage(titleImage, 0, 0, this.getWidth(), this.getHeight(), null);
    }

    graphics.drawImage(back, 0, 0, this);
  }

  @Override
  public void actionPerformed(ActionEvent e){
    Object source = e.getSource();

    if(source == timer){
      timeMeasure.Update();
      repaint();//再描画
    }
  }

  @Override
    public void componentHidden(ComponentEvent e) {}

    @Override
    public void componentMoved(ComponentEvent e) {}

    @Override//リサイズしたとき
    public void componentResized(ComponentEvent e) {
    back = createImage(this.getWidth(), this.getHeight());
    buffer = back.getGraphics();
  }

    @Override
    public void componentShown(ComponentEvent e) {}
}

その他

・ネットで調べて、setDoubleBuffered(boolean)を見つけたが使い方がわからなかった。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

0

バッファイメージのサイズを大きくすると動きが遅くなってしまいました。

ダブルバッファリングも"処理"ですから, 対象が多くなれば遅くなるのは当然かと思います.
ダブルバッファリングのコードの問題とお考えであれば, 「JFrameにおいてインスタンス生成時に~」という日本語説明で無く, コードをご提示ください.

setDoubleBuffered(boolean)を見つけた

Swing はコンポーネントの描画の為にダブルバッファリングを(うろ覚えですが) JComponent のレベルで実装・実行しています.
ただ個々のコンポーネントがダブルバッファリングしても意味はありませんので, 個々のコンポーネントのデフォルトは Off となっており, JFrame の ContentPane のレベルが On になっています.
その On/Off を設定するためのメソッドが setDoubleBuffered だったと思います.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/03/30 12:16

    分かりました。最初は、paint関数の引数も、バッファイメージも同じGraphicsなのに、なぜ遅くなるんだろうと思っていたのですが、2つのGraphicsは何か違うみたいですね。問題の「重くなった」のは、ダブルバッファリングの「代価」ということですか。エラーみたいに何かを追加したり、文法が間違っているといった問題ではなく、仕方がないものであるということがわかって、良かったです。ウィンドウのサイズを固定化するなどして対応してみます。

    キャンセル

  • 2020/03/30 13:20

    > paint関数の引数も、バッファイメージも同じGraphicsなのに、なぜ遅くなるんだろうと思っていた
    同じなのは「出来ることが同じ」だからで, 作用する先が違うということです.
    同じペンを使っても, 役所への提出資料にも広告の裏にも書けるのと同じです.
    ダブルバッファリングにつきましては多数情報があると思いますので, 再度確認・調査されたらと思います.

    キャンセル

  • 2020/03/30 15:22

    丁寧に教えていただき、ありがとうございました

    キャンセル

0

実メモリー不足では?
実装されているメモリーに対し、アプリが使用するメモリー量が多すぎると、ページングと言ってその時点で使用していないメモリーの一部を一時的にディスクに書き出して実メモリー不足を補って処理します。
これが多発すると処理速度が目に見えて落ちます。
ダブルバッファーとすることでメモリー不足が発生している可能性があります。
メモリー量(実装量と、アプリが動作する前の時点でのOS等の使用量、アプリの使用量)を確認してください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

ダブルバッファの目的は、ユーザビリティの向上であり、データを集めている間にすでに集まっているデータを利用して処理をすることで、ユーザの応答性が向上することが主な目的になります。並行して処理を行うことにより返って処理が重くなることはあり得る問題です。

画面を大きくすると動きが遅くなる

画面サイズによりということは、例えば画素単位での処理がある場合に処理が増大したりしますし、バッファサイズに影響を与えている可能性もあります。

画面の大きさに比例して時間が遅くなっていた

これも一フレームあたりの処理が遅くなるためでしょう。

graphics.drawImage(back, 0, 0, this)だけをコメントアウトすると画面は変わらないが、フレームレートは速くなった

drawImage自体は描画を行うが、画像サイズに比例して描画時間が増大することは考えられなくは無いですね。

ですので、一画面の処理をある程度高速化するなりしないと改善が難しいと思いますし、それをするためには、その処理のパフォーマンス測定、プロファイルが必要かと思います。
また、その速度が十分に高速になれば、ダブルバッファも不要になるかもしれません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る