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

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

新規登録して質問してみよう
ただいま回答率
85.47%
Java Development Kit

Java Development Kit(JDK)とは、Javaでの開発のために要するソフトウェアをまとめたパッケージです。コンパイラの「Javac」やクラスライブラリの「jar」など、Java開発者向けツールが含まれています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

Q&A

解決済

1回答

287閲覧

Java OpenGL フルスクリーン時の不具合

ShunKitajima

総合スコア5

Java Development Kit

Java Development Kit(JDK)とは、Javaでの開発のために要するソフトウェアをまとめたパッケージです。コンパイラの「Javac」やクラスライブラリの「jar」など、Java開発者向けツールが含まれています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

0グッド

0クリップ

投稿2024/01/12 12:51

編集2024/01/14 08:47

実現したいこと

GPUを用いて(パフォーマンスを落とすことなく)描画をしながらも、アプリケーションでフルスクリーン表示をした時も正常に描画されるようにしたい

発生している問題・分からないこと

Eclipseを用いてエクスポートした実行可能jarファイルを、jpackageを使ってJVM引数を-Dsun.java2d.opengl=Trueと設定してインストーラを作り、それを使ってアプリケーションをインストールして実行すると、以下のメソッドを使ってフルスクリーン表示させた時に、Jpanelインスタンス上にdrawImageやdrawStringを用いて描画したものが表示されなくなる。加えて、カーソルも表示されない。しかし、jarファイルをコマンドプロンプトで実行した時(JVM引数は同じ)は、正常に描画される。-Dsun.java2d.opengl=Falseと設定してインストーラを作った時にも正常に描画される。

該当のソースコード

Java

1 public static void toggleScreenMode(final boolean fullScreen) { 2 3 if (gameFrame != null) {gameFrame.dispose();} 4 gameFrame = new JFrame(); 5 setFrameDefaultValue(gameFrame); 6 7 //フルスクリーンにする 8 if (fullScreen == true) { 9 gameFrame.setUndecorated(true); // タイトルバーを削除 10 if (device.isFullScreenSupported()) { 11 device.setFullScreenWindow(gameFrame); // フルスクリーンに設定 12 } 13 14 isFullScreen = true; 15 } 16 //フルスクリーン解除する 17 else if (fullScreen == false) { 18 gameFrame.pack(); //サブコンポーネントの推奨サイズおよびレイアウトに合わせて、ウィンドウサイズを変更 19 gameFrame.setLocationRelativeTo(null); 20 gameFrame.setVisible(true); 21 22 isFullScreen = false; 23 } 24 25 }

Java

1 2// Threadのインスタンスのstartメソッドから呼び出される 3// 1/60秒ごとにupdateメソッドとrepaintメソッドを実行する 4@Override 5public void run() { 6 7gameIsRunning = true; //gameIsRunningがtrueの時のみキーを操作可能にする 8 9while(gameThread != null) { 10currentTime = System.nanoTime(); 11if (currentTime - lastTime >= drawInterval) { //drawInterval == 1000000000.0/60.0 12update(); //各インスタンスのupdateメソッドを実行する 13repaint(widthOfBlackScreen, 0, monitorWidth-2*widthOfBlackScreen, monitorHeight); //paintComponentメソッドを呼び出す(widthOfBlackScreenは、ゲーム画面が描画される部分を横:縦=3:4にするために両脇に表示させる黒い部分の幅) 14lastTime = currentTime; 15} 16} 17} 18

Java

1 2@Override 3public void paintComponent(final Graphics g) { 4super.paintComponent(g); //コンポーネントの背景をクリア 5 6g2 = (Graphics2D)g; 7 8// Debug 9drawStartNanosecond = 0; 10if (keyH.getDrawTimeIsBeingChecked() == true) {drawStartNanosecond = System.nanoTime();} 11 12// Background 13bgHandler.draw(g2); 14 15 16if (gameState != titleState) { 17// タイルの描画 18tileM.draw(g2); 19 20// Itemのサブクラスのインスタンスの描画 21for (int i = 0; i < item.length; i++) { 22if (item[i] != null) {item[i].draw(g2);} 23} 24 25// worldYによってentitiesの描画する順番を変える 26entities[0] = player; 27for (int i = 1; i < 1+npc.length; i++) { 28if (npc[i-1] != null) {entities[i] = npc[i-1];} 29} 30for (int i = 1+npc.length; i < 1+npc.length+animatePicture.length; i++) { 31if (animatePicture[i-1-npc.length] != null) {entities[i] = animatePicture[i-1-npc.length];} 32} 33for (int i = 1+npc.length+animatePicture.length; i < entities.length; i++) { 34if (obj[i-1-npc.length-animatePicture.length] != null) {entities[i] = obj[i-1-npc.length-animatePicture.length];} 35} 36UtilityTool.sort(entities, this); 37for (int i = 0; i < entities.length; i++) { 38if (entities[i] != null) {entities[i].draw(g2);} 39} 40} 41 42// UI描画 43uiDrawer.draw(g2); 44 45// Debug 46if (keyH.getDrawTimeIsBeingChecked() == true) { 47drawEndNanosecond = System.nanoTime(); 48passedNanosecond = drawEndNanosecond - drawStartNanosecond; 49g2.setColor(Color.white); 50g2.setFont(uiDrawer.maruMonica.deriveFont(50F)); 51String s = (Integer.toString((int)passedNanosecond)); 52g2.drawString("DrawingTime: "+s+"ns"+"("+monitorWidth+":"+monitorHeight+")", widthOfBlackScreen+tileSize/2, UtilityTool.getCenteredTextY(s.toString(), this, g2)); 53} 54 55g2.dispose(); 56}

簡略化したソースコード(+ エラーをtxtファイルに出力する)

Main.java

Java

1package main; 2 3import java.awt.GraphicsDevice; 4import java.awt.GraphicsEnvironment; 5import java.io.FileWriter; 6import java.io.IOException; 7 8import javax.swing.JFrame; 9 10public class Main { 11 12 private static JFrame gameFrame = new JFrame(); 13 private static final GamePanel gp = new GamePanel(); 14 private static GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); 15 private static GraphicsDevice device = env.getDefaultScreenDevice(); 16 17 private static FileWriter fileWriter; 18 19 public static void main(String[] args) { 20 try { 21 try { 22 fileWriter = new FileWriter("該当フォルダのパス\\Debug_Main_main.txt", true); 23 fileWriter.write("Start"); 24 fileWriter.close(); 25 } catch (IOException e) { 26 e.printStackTrace(); 27 } 28 29 gameFrame = new JFrame(); 30 gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 31 gameFrame.add(gp); 32 33 gameFrame.setUndecorated(true); 34 device.setFullScreenWindow(gameFrame); 35 36 gp.startGame(); 37 38 } catch (Exception e) { 39 try { 40 fileWriter = new FileWriter("該当フォルダのパス\\Debug_Main_main.txt", true); 41 fileWriter.write(e.getMessage()); 42 fileWriter.close(); 43 } catch (IOException e1) { 44 e1.printStackTrace(); 45 } 46 } 47 48 } 49}

GamePanel.java

Java

1package main; 2 3import java.awt.Graphics; 4import java.awt.Graphics2D; 5import java.io.FileWriter; 6import java.io.IOException; 7 8import javax.swing.JPanel; 9 10public class GamePanel extends JPanel implements Runnable { 11 //FPS 12 public final int FPS = 60; 13 private final double drawInterval = 1000000000.0/FPS; 14 long lastTime = 0; 15 long currentTime = 0; 16 17 // SYSTEM 18 private Graphics2D g2; 19 private Thread gameThread; 20 private FileWriter fileWriter; 21 22 public void startGame() { //Mainクラスから呼び出される 23 try { 24 //パネルのThreadを開始 => run() 25 gameThread = new Thread(this); 26 gameThread.start(); 27 } catch (Exception e) { 28 try { 29 fileWriter = new FileWriter("該当フォルダのパス\\Debug_GamePanel_startGame.txt", true); 30 fileWriter.write(e.getMessage()); 31 fileWriter.close(); 32 } catch (IOException e1) { 33 e1.printStackTrace(); 34 } 35 } 36 } 37 38 @Override 39 public void run() { 40 while(gameThread != null) { 41 try { 42 currentTime = System.nanoTime(); 43 if (currentTime - lastTime >= drawInterval) { 44 repaint(0, 0, 1920, 1080); 45 lastTime = currentTime; 46 } 47 } catch (Exception e) { 48 try { 49 fileWriter = new FileWriter("該当フォルダのパス\\Debug_GamePanel_run.txt", true); 50 fileWriter.write(e.getMessage()); 51 fileWriter.close(); 52 } catch (IOException e1) { 53 e1.printStackTrace(); 54 } 55 } 56 } 57 } 58 59 //repaintメソッドから呼び出される 60 @Override 61 public void paintComponent(final Graphics g) { 62 try { 63 super.paintComponent(g); 64 65 g2 = (Graphics2D)g; 66 67 g2.drawString("A", 960, 540); 68 69 g2.dispose(); 70 } catch (Exception e) { 71 try { 72 fileWriter = new FileWriter("該当フォルダのパス\\Debug_GamePanel_paintComponent.txt", true); 73 fileWriter.write(e.getMessage()); 74 fileWriter.close(); 75 } catch (IOException e1) { 76 e1.printStackTrace(); 77 } 78 } 79 } 80} 81

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果
  • Googleで「Java OpenGL フルスクリーン」などと調べ、setExtendedStateメソッドを使ったフルスクリーンの方法も試したが、解決しなかった。
  • ChatGPT(GPT-4)を用いて以上の質問を入力し、以下のような結果がいくつか得られたが、解決には至らなかった。

[ChatGPTの回答]
問題の状況について理解しました。jpackageを用いて作成したJavaアプリケーションでフルスクリーン時に問題が発生するが、コマンドプロンプトから同じJVM引数で実行すると問題が発生しないということですね。この問題は、jpackageでパッケージ化されたアプリケーションの設定や環境が、直接コマンドプロンプトから実行する場合と異なることに起因している可能性があります。

以下にいくつかの改善策を提案します。

  1. JVM引数の確認

jpackageで作成したアプリケーションのJVM引数が正しく設定されているかを再確認してください。パッケージ化のプロセスで引数が適切に引き継がれているか、特に-Dsun.java2d.opengl=Trueが含まれているかを確認します。
2. 環境設定の確認
パッケージ化されたアプリケーションが実行される環境(パス、依存関係など)が、コマンドプロンプトから実行する環境と同じかどうかを確認します。異なる環境設定が影響している場合があります。
3. 描画関連のコードの確認
Graphics2DのdrawImageメソッドに関連するコードが、OpenGLとの互換性を持つように最適化されているかを確認します。特にフルスクリーンモードでの描画方法に注意してください。
4. グラフィックス設定の確認
使用しているグラフィックスカードの設定やドライバーが、OpenGLとの互換性を持つように設定されているかを確認します。ドライバーの更新や設定の変更が必要な場合があります。
5. デバッグ情報の利用
アプリケーションをデバッグモードで実行し、フルスクリーンモード時に発生するエラーや警告を確認します。ログ出力を増やして、問題の原因を特定する手がかりを探します。
6. 他のJVMオプションの試行
他のJVMオプションを試してみるのも一つの方法です。例えば、-Dsun.java2d.noddraw=trueや-Dsun.java2d.d3d=falseなど、異なるグラフィックス関連のオプションを試してみると良いでしょう。
7. jpackageの設定の再確認
jpackageを使用する際の設定やコマンドラインオプションを再確認し、必要な設定が漏れていないか確認します。
これらのステップを踏むことで、問題の原因を特定し、適切な解決策を見つけることができるはずです。また、問題が解決しない場合は、Javaの開発者コミュニティやフォーラムで支援を求めることも検討してください。

補足

開発や実行はすべてWindows11(64ビット)を用いて行い、JDK17とEclipseを用いてJava17のライブラリのawtとswingを使って2Dゲームを作成。awtのrepaintメソッドが1秒間に60回実行される(以下のrunメソッド参照)ことで、Graphics2DのdrawImageやdrawStringを用いた描画(paintComponentメソッドは以下参照)。jpackageを使うにあたってWiXのv3.11.2.4516をダウンロードし、以下のようなコマンドをコマンドプロンプトで実行してインストーラを作成。
「jpackage --type exe --vendor "Shun" --win-menu --win-dir-chooser --win-shortcut --win-shortcut-prompt --input Jarファイルがあるディレクトリのパス --name MyGame --main-jar MyGame.jar --main-class main.Main --java-options "-Dsun.java2d.dpiaware=true" --java-options "-Dsun.java2d.uiScale=1.0" --java-options "-Xmx2048m" --java-options "-Dsun.java2d.opengl=True" --dest Jarファイルがあるディレクトリのパス」

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2024/01/13 15:40

どのようなライブラリ・バージョン・環境を作って、ご提示のコードを使ってどのような jar を作り、 jpackage でどのようなインストーラを作って何の OS で実行すれば再現出来ますか。
ShunKitajima

2024/01/14 01:14

ご返答ありがとうございます。 開発や実行はすべてWindows11(64ビット)を用いて行い、JDK17とEclipseを用いてJava17のライブラリのawtとswingを使って2Dゲームを作成しました。awtのrepaintメソッドが1秒間に60回実行される(以下のrunメソッド参照)ことで、Graphics2DのdrawImageやdrawStringを用いた描画をしています(paintComponentメソッドは以下参照)。jpackageを使うにあたってWiXのv3.11.2.4516をダウンロードし、以下のようなコマンドをコマンドプロンプトで実行してインストーラを作りました。 「jpackage --type exe --vendor "Shun" --win-menu --win-dir-chooser --win-shortcut --win-shortcut-prompt --input Jarファイルがあるディレクトリのパス --name MyGame --main-jar MyGame.jar --main-class main.Main --java-options "-Dsun.java2d.dpiaware=true" --java-options "-Dsun.java2d.uiScale=1.0" --java-options "-Xmx2048m" --java-options "-Dsun.java2d.opengl=True" --dest Jarファイルがあるディレクトリのパス」 説明不足がございましたら申し訳ありません。 -------------------------------------------------- ''' // Threadのインスタンスのstartメソッドから呼び出される // 1/60秒ごとにupdateメソッドとrepaintメソッドを実行する @Override public void run() { gameIsRunning = true; //gameIsRunningがtrueの時のみキーを操作可能にする while(gameThread != null) { currentTime = System.nanoTime(); if (currentTime - lastTime >= drawInterval) { //drawInterval == 1000000000.0/60.0 update(); //各インスタンスのupdateメソッドを実行する repaint(widthOfBlackScreen, 0, monitorWidth-2*widthOfBlackScreen, monitorHeight); //paintComponentメソッドを呼び出す(widthOfBlackScreenは、ゲーム画面が描画される部分を横:縦=3:4にするために両脇に表示させる黒い部分の幅) lastTime = currentTime; } } } ''' -------------------------------------------------- ''' @Override public void paintComponent(final Graphics g) { super.paintComponent(g); //コンポーネントの背景をクリア g2 = (Graphics2D)g; // Debug drawStartNanosecond = 0; if (keyH.getDrawTimeIsBeingChecked() == true) {drawStartNanosecond = System.nanoTime();} // Background bgHandler.draw(g2); if (gameState != titleState) { // タイルの描画 tileM.draw(g2); // Itemのサブクラスのインスタンスの描画 for (int i = 0; i < item.length; i++) { if (item[i] != null) {item[i].draw(g2);} } // worldYによってentitiesの描画する順番を変える entities[0] = player; for (int i = 1; i < 1+npc.length; i++) { if (npc[i-1] != null) {entities[i] = npc[i-1];} } for (int i = 1+npc.length; i < 1+npc.length+animatePicture.length; i++) { if (animatePicture[i-1-npc.length] != null) {entities[i] = animatePicture[i-1-npc.length];} } for (int i = 1+npc.length+animatePicture.length; i < entities.length; i++) { if (obj[i-1-npc.length-animatePicture.length] != null) {entities[i] = obj[i-1-npc.length-animatePicture.length];} } UtilityTool.sort(entities, this); for (int i = 0; i < entities.length; i++) { if (entities[i] != null) {entities[i].draw(g2);} } } // UI描画 uiDrawer.draw(g2); // Debug if (keyH.getDrawTimeIsBeingChecked() == true) { drawEndNanosecond = System.nanoTime(); passedNanosecond = drawEndNanosecond - drawStartNanosecond; g2.setColor(Color.white); g2.setFont(uiDrawer.maruMonica.deriveFont(50F)); String s = (Integer.toString((int)passedNanosecond)); g2.drawString("DrawingTime: "+s+"ns"+"("+monitorWidth+":"+monitorHeight+")", widthOfBlackScreen+tileSize/2, UtilityTool.getCenteredTextY(s.toString(), this, g2)); } g2.dispose(); } '''
jimbe

2024/01/14 04:26

説明が不足していました。 ここは質問へのコメント欄ですので、質問に関する情報は質問を編集して追加・変更してください。 スレッドとペイントのコードを戴きましたが、これらから実行出来るコードを構築するには多数の変数やクラスを想像で書かなければなりません。相続が間違っていれば同じ現象が発生する可能性も低くなり、発生しても同じ原因かどうかも分からなくなります。 先ずはお手元のプロジェクトをコピーして、例えば paintComponent では "A" を表示するだけにするとかスレッドでは 1 秒スリープして update/repaint を呼ぶだけにするとか、構造はあまり変えずに各部の処理を簡略化・最小化してはインストーラを作ってテストを繰り返し、再現する最小のコードを作って見てください。 その過程で再現しなくなったら、直前に弄った部分が問題に関係している可能性がありますし、再現する最小のコードなら全文を質問にご提示戴けるかもしれません。 また、デバッグ情報をファイルに出力させる構造を作れば、画面に書かれなくても何が起きているのかを調べることが出来ます。
ShunKitajima

2024/01/14 08:45 編集

ご回答ありがとうございます。ソースコードを問題が再現できる最小のものまで簡略化し、当該フォルダのテキストファイルにエラーを出力するプログラムを加えたものと、コメント欄のソースコードを追記しました。 このプログラムをEclipseで同様にエクスポートし、実行可能jarファイルを同じ方法で実行した時も同様の問題が起き、インストーラを作成してインストールしたアプリケーションを開いた場合も、問題は同様に起こりました。また、どちらの場合にも、出力ファイルには(書き込みが正常に行われているか確認するための)「Start」のみ出力されていて、エラーは出力されていませんでした。 ご確認よろしくお願い致します。
jimbe

2024/01/14 13:04 編集

ありがとうございます。後ほど試してみようと思います。 Windows10 上でインストーラ作成・インストールしているのですが、 JFrame 自体が表示されず調査中です。 今の所 Eclipse での実行や、実行可能 jar を作成してコマンドラインでの実行では、 opengl=true にしても表示されています。もちろんエラー出力もありません。
jimbe

2024/01/20 16:42

sun.java2d.opengl の true/True はこちらの環境ではフレーム自体が出たり出なかったりとか不安定な感じです。出た時はちゃんと表示されます。 あちこち探し回った感じでは OS 等を含む OpenGL の環境に因ってどうなるか分からないような部分が(まだ?)ありそうです。 OpenGL を使うなら明示的に JOGL のようなライブラリを使って行うのが良いのかもしれません。
ShunKitajima

2024/01/29 01:54 編集

諸々丁寧に対応していただきありがとうございます。 後日、JOGLを用いて該当コードを書き換え、動作確認をしてみます。 JOGLについて調べているうちに解決することができました!ありがとうございます!
guest

回答1

0

自己解決

実行したいjarファイルを実行するためのプログラム(ランチャー)を作り、そのインストーラを作る際に実行したいjarファイルが入ったフォルダもまとめてインストールさせ、間接的にjarファイルを実行する方針で進めるとうまくいきました。

以下は、MyGameLauncher.jar(ランチャー)のインストーラを作成する際にコマンドプロンプトから実行したjpackageコマンドの例と、ランチャーのプログラムです。ここでは、実行したいjarファイルの名前はMyGame.jarとしています。

Command

1jpackage --type exe --win-menu --win-shortcut --win-shortcut-prompt --input MyGame.jarが入っているディレクトリのパス --name MyGameLauncher --main-jar MyGameLauncher.jarが入っているディレクトリのパス\MyGameLauncher.jar --main-class ランチャーのメインクラス

Java(MyGameLauncher.java)

1package main; 2import java.io.IOException; 3 4public class Launcher { 5 public static void main(String[] args) { 6 try { 7 // JARファイルのパス 8 String jarPath = "app\\MyGame.jar"; 9 10 // ProcessBuilderにコマンドラインオプションを設定 11 ProcessBuilder processBuilder = new ProcessBuilder( 12 "java", 13 "-Dsun.java2d.opengl=True", 14 "-jar", 15 jarPath 16 ); 17 18 // プロセスの開始 19 Process process = processBuilder.start(); 20 21 // プロセスの終了を待つ 22 process.waitFor(); 23 24 } catch (IOException e) { 25 e.printStackTrace(); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 Thread.currentThread().interrupt(); 29 } 30 } 31} 32

投稿2024/01/29 01:51

ShunKitajima

総合スコア5

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問