1

JFrame 内でゲームを作成しようとしていますが、問題が発生しました。4 つのイメージを 1 つにつなぎ合わせたオブジェクトを作成しました。私の問題は、このオブジェクトを JFrame に描画するにはどうすればよいですか?

コードは次のとおりです。

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.*;

public class t4
{
    static boolean running;

    public static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    public static double width = screenSize.getWidth();
    public static double height = screenSize.getHeight();

    public static int x = ( 250 );
    public static int y = ( 150 );

    public static final int sx = (int)width;
    public static final int sy = (int)height;

    public static void main( String[] args ) throws IOException, InterruptedException
    {
        Image ur = new ImageIcon("redBlock.gif").getImage();
        Image ll = new ImageIcon("redBlock.gif").getImage();
        Image ul = new ImageIcon("blueBlock.gif").getImage();
        Image lr = new ImageIcon("blueBlock.gif").getImage();

        // Create game window...
        JFrame app = new JFrame();
        app.setIgnoreRepaint( true );
        app.setUndecorated( true );

        // Add ESC listener to quit...
        app.addKeyListener( new KeyAdapter()
        {
            public void keyPressed( KeyEvent e )
            {
                if( e.getKeyCode() == KeyEvent.VK_ESCAPE )
                    running = false;
                if((e.getKeyCode()==KeyEvent.VK_LEFT)||(e.getKeyCode()==KeyEvent.VK_KP_LEFT))
                    x-=10;
                if((e.getKeyCode()==KeyEvent.VK_RIGHT)||(e.getKeyCode()==KeyEvent.VK_KP_RIGHT))
                    x+=10;
                if((e.getKeyCode()==KeyEvent.VK_UP)||(e.getKeyCode()==KeyEvent.VK_KP_UP))
                    y-=10;
                if((e.getKeyCode()==KeyEvent.VK_DOWN)||(e.getKeyCode()==KeyEvent.VK_KP_DOWN))
                y+=10;
            }
        });

        // Get graphics configuration...
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gd.getDefaultConfiguration();

        // Change to full screen
        gd.setFullScreenWindow( app );
        if( gd.isDisplayChangeSupported() )
        {
            gd.setDisplayMode(new DisplayMode( sx, sy, 32, DisplayMode.REFRESH_RATE_UNKNOWN ));
        }

        // Create BackBuffer...
        app.createBufferStrategy( 2 );
        BufferStrategy buffer = app.getBufferStrategy();

        // Create off-screen drawing surface
        BufferedImage bi = gc.createCompatibleImage( sx, sy );

        // Objects needed for rendering...
        Graphics graphics = null;
        Graphics2D g2d = null;
        Color background = Color.BLACK;
        Random rand = new Random();

        // Variables for counting frames per seconds
        int fps = 0;
        int frames = 0;
        long totalTime = 0;
        long curTime = System.currentTimeMillis();
        long lastTime = curTime;

        running = true;
        while( running )
        {
            try
            {
                //    wait(500);

                // count Frames per second...
                lastTime = curTime;
                curTime = System.currentTimeMillis();
                totalTime += curTime - lastTime;
                if( totalTime > 1000 )
                {
                    totalTime -= 1000;
                    fps = frames;
                    frames = 0;
                } 
                ++frames;

                // clear back buffer...
                g2d = bi.createGraphics();
                g2d.setColor( background );
                g2d.fillRect( 0, 0, sx, sy );

                // draw some rectangles...
                /* int r = 45;
                int g = 232;
                int b = 163;
                g2d.setColor( new Color(r,g,b) );
                int w = ( 250 );
                int h = ( 150 );
                g2d.fillRect( x+25, y+25, w, h );*/

                if(y<775)
                {
                    y++;
                }
                else
                {
                    y=0;
                }

                // display frames per second...
                g2d.setFont( new Font( "Courier New", Font.PLAIN, 12 ) );
                g2d.setColor( Color.GREEN );
                g2d.drawString( String.format( "FPS: %s", fps ), 20, 20 );

                // Blit image and flip...
                graphics = buffer.getDrawGraphics();
                graphics.drawImage( bi, 0, 0, null );

                graphics.drawImage(ur,x,y,null);
                graphics.drawImage(ll,x+50,y+50,null);
                graphics.drawImage(ul,x,y+50,null);
                graphics.drawImage(lr,x+50,y,null);

                if( !buffer.contentsLost() )
                    buffer.show();

            }
            finally
            {
                // release resources
                if( graphics != null ) 
                    graphics.dispose();
                if( g2d != null ) 
                    g2d.dispose();
            }
        }

        gd.setFullScreenWindow( null );
        System.exit(0);
    }

    public static void wait(int x) throws InterruptedException
    {
        Thread.currentThread().sleep(x);
    }
}

画像 ur、ll、ul、lr を含むオブジェクトを作成し、画面上に描画できるようにしたいと考えています。

4

1 に答える 1

6

これはあなたがすべきことです:

  1. クラスを変更して拡張しjavax.swing.JComponentます。
  2. オーバーライドしpaintComponent(Graphics)ます。
  3. javax.swing.Timerフレーム レートを管理する を作成します。
  4. オーバーライドしgetPreferredSize()ます。

最初に (DavidB の要求に応じて)なぜこれらのことを行うべきかについて説明し、次にその方法を示します

説明

  • コンポーネントを JFrame に追加しようとしているので、コンポーネントのクラスが JFrame のaddメソッドと互換性がある必要があります (実際には に属してContainerいますが、それはあまり重要ではありません)。のJavaDocドキュメントをadd見ると、それが受け入れないことがわかりますObjectComponentむしろ、a (またはそのサブクラス)のインスタンスが必要です。の代わりにサブクラス化できますが、Swing アプリケーションよりも AWT アプリケーション向けです。要するに、それをパラメーターとして受け入れるようにサブクラス化します。ComponentJComponentComponent
    JComponentJFrame.add
  • をサブクラス化JComponentしたら、実際にウィンドウ マネージャに何を描画するかを指示する必要があります。描画コードはどこにでも置くことができますが、何かが実際にそのメソッドを呼び出さない限り、呼び出し(使用) されないことに注意してください。描画プロセスを開始するためにグラフィックス環境が呼び出すメソッドは、paintComponent* と呼ばれます。このメソッドをオーバーライドすると、グラフィックス環境によってカスタム ペイント コードが呼び出されます。
    要するにpaintComponent、グラフィック環境が気にするのはオーバーライドです。
  • ゲームでアニメーション化する可能性が最も高いため、一定のフレーム/秒レートを維持する必要がありますよね? そうしないと、多くの要因 (コンピューターの処理能力、実行中の他のアプリケーション、描画の複雑さなど) が原因で、フレーム レートが狂ってしまう可能性があります。これを行うには、repaintメソッドを 1 秒間に指定された回数 (フレームごとに 1 回) 呼び出す必要があります。これがスイングタイマーのポイントです。コードのブロックとミリ秒数を指定すると、指定された間隔が経過するたびにそのコードが実行されます。
    要するに、フレームレートを一定に保ち、制御できるように、スイングタイマーを使用します。
  • ワード プロセッシング アプリケーションがあるとします。上部にメニュー バー、中央にドキュメント ウィンドウ、下部にツールバーがあります。明らかに、メニュー バーとツールバーを小さくし、ドキュメントができるだけ多くのスペースを占有するようにしたいと思いますよね? これが、各コンポーネントに、推奨サイズと呼ばれるそのサイズを指定させる必要がある理由です。オーバーライドgetPreferredSizeを使用すると、必要なサイズを返すことができるため、コンポーネントのサイズを制御できます。**
    要するにgetPreferredSize、ウィンドウ マネージャーとグラフィックス環境がすべてのサイズを正しく取得できるようにオーバーライドします。

* 実際にpaintComponent呼ばれているわけではありません。ですpaint。ただし、paintメソッドはpaintComponentpaintBorder、および を呼び出しpaintChildrenます。

このメソッドは、ペイントの作業を、3 つの保護されたメソッド (paintComponent、paintBorder、および paintChildren) に実際に委譲します。それらはリストされた順序で呼び出され、子がコンポーネント自体の上に表示されるようにします。一般的に言えば、コンポーネントとその子は、境界線に割り当てられたインセット領域に描画されるべきではありません。いつものように、サブクラスはこのメソッドをオーバーライドできます。UI (ルック アンド フィール) デリゲートの paint メソッドを特殊化するだけのサブクラスは、paintComponent をオーバーライドする必要があります。

(ソース: JavaDoc )

** オーバーライドgetPreferredSizeは、コンポーネントが表示されるサイズであることを実際に保証するものではありません。表示するサイズを指定するだけです。一部のレイアウト マネージャーは、これを無視することを選択します (BorderLayout など)。ただし、packウィンドウのサイズを正しく設定するために呼び出すと、このサイズに従って適切なサイズが計算されます。

手順

JComponent の拡張

クラスが JComponent を拡張するようにするには、クラスのシグネチャを次のように変更します。

import javax.swing.JComponent;

public class MyGameDisplay extends JComponent {
    ...
}

オーバーライドpaintComponent

java.awt.Graphicsクラスをインポートする必要があります。の使用方法については、次のサンプル コードを参照してくださいpaintComponent

import javax.swing.JComponent;
import java.awt.Graphics;

public class MyGameDisplay extends JComponent {
    // Some code here

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g); // this line is crucial; see below
        g.drawString(100,100,"Hello world");
    }
}

: 上記で、メソッドsuper.paintComponent内からの呼び出しの必要性について述べました。paintComponentこれは、以前に表示したすべてのグラフィックが (とりわけ) クリアされるためです。したがって、たとえば、プログラムが画面上を移動する円を描画する場合、 を呼び出さない限り、描画の各反復には前の描画からの円の軌跡も含まれますsuper.paintComponent

を使ってTimer

必要な FPS レートを取得するには、次のように、クラスを変更して Swing タイマーを含めます。

// Include these imports:
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class MyGameDisplay extends JComponent {
    private Timer t;
    public MyGameDisplay() {
        ActionListener al = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                repaint();
            }
        }
        t = new Timer(1000 / 30 /* frame rate */, al);
        t.start();
    }
}

オーバーライドgetPreferredSize

オーバーライドする理由getPreferredSizeは、レイアウト マネージャーがコンテナーのサイズを適切に設定する方法を認識できるようにするためです。

サイズを計算する実際のロジックを記述するのは難しいかもしれませんが、オーバーライドgetPreferredSize自体はそうではありません。次のようにします。

@Override
public Dimension getPreferredSize() {
    return new Dimension(400, 400); // for example
}

すべて完了したら、次のコードを実行するだけです。

import javax.swing.JFrame;

public class Test {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        MyGameDisplay mgd = new MyGameDisplay();
        frame.add(mgd);
        frame.pack();
        frame.setVisible(true);
    }
}
于 2012-05-23T21:05:35.300 に答える