0

私はJavaが初めてです。小惑星のクローン ゲームを作ろうとしていますが、問題が発生しています。

graphics2d オブジェクトを jframe に戻す方法がわかりません。どんな助けでも大歓迎です。あと、いろいろ追加していく予定ですので、見づらかったらすみません。
現在、jframe は描画されますが、内部にオブジェクトがありません。

メインクラス

import java.applet.*;
import javax.swing.*;

public class Program extends JApplet
{
public void init()
{
    String[] s = new String[0];
    main(s);
};

public static void main(String[] args)
{
    System.out.println("Launching Window");
    Window w = new Window();
    w.setSize(700, 600);
    w.setLocation(50,50);
    w.setVisible(true);
    w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    System.out.println("Launching Game");
    Game g = new Game();

    while(g.play)
    {
        System.out.println("Looping");
        g.tick();
        w.repaint();
    };
}
};

Gui スタッフ (これが必要か、game.java とマージするかは不明)

import javax.swing.*;

public class Window extends JFrame
{
    private JPanel panel;

    public Window()
    {
        panel = new JPanel();
        add(panel);
    };

};

Game.java、プログラムのメイン ロジック、まだ完全ではありません

import java.applet.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class Game implements KeyListener
{
    public static int xmax = 800;
    public static int ymax = 600;

    private LinkedList<Rock> rocks = new LinkedList();
    private LinkedList<Laser> lasers = new LinkedList();
    private Ship ship;

    private int score = 0;
    public boolean play = true;

    public Game()
    {
        ship = new Ship(xmax/2, ymax/2);    //Game objects
        rocks.add(new Rock(50, 50, 50));
    };

    public void reinit()
    {
        ship = null;
        rocks.clear();
        lasers.clear();
        score = 0;
    };

    public void tick()
    {
        for(int i = 0; i < rocks.size(); i++)   //Check to see if bullets hit unit, remove that unit
        {
            for(int j = 0; j < lasers.size(); j++)
            {
                if(rocks.get(i).hit(rocks.get(j)))
                {
                    if(rocks.get(i).size > 20)  //if rocks bigger than 20 spawn some more rocks
                    {
                        rocks.add(new Rock(rocks.get(j).x, rocks.get(j).y, rocks.get(j).size/3));   //add three rocks on hit
                        rocks.add(new Rock(rocks.get(j).x, rocks.get(j).y, rocks.get(j).size/3));
                        rocks.add(new Rock(rocks.get(j).x, rocks.get(j).y, rocks.get(j).size/3));
                    };
                    rocks.remove(j);                                                                //remove hit rock
                    lasers.remove(i);                                                               //remove laser
                };
            };
        };

        for(int i = 0; i < rocks.size(); i++) //move units
        {
            rocks.get(i).tick();
        };

        for(int i = 0; i < lasers.size(); i++) //move bullets
        {
            lasers.get(i).tick();
        };

        ship.tick();
    };

    public void keyPressed(KeyEvent e) 
    {
        if(e.getKeyCode()==KeyEvent.VK_SPACE)
            lasers.add(new Laser(ship.x, ship.y, ship.angle));
        if (e.getKeyCode()==KeyEvent.VK_UP)
            ship.thrust();
        if (e.getKeyCode()==KeyEvent.VK_LEFT)
            ship.left();
        if (e.getKeyCode()==KeyEvent.VK_RIGHT)
            ship.right();
        if (e.getKeyCode()==KeyEvent.VK_Q)
            play = false;
    };

    public void keyReleased(KeyEvent e)
    {

    };

    public void keyTyped(KeyEvent e)
    {

    };

};

オブジェクトを保持するジェネリック クラス

import java.lang.Math;

public class Coords
{
    public static double RAD = 0.0174532925;
    public static int xmax = 800;
    public static int ymax = 600;

    public double x     = 0.0;
    public double y     = 0.0;
    public double dx    = 0.0;
    public double dy    = 0.0;
    public double vel   = 0.0;
    public double size = 0.0;
    public double angle= 0.0;
    public double da    = 0.0;

    public Coords()
    {
    };

    public void reinit()
    {
        x       = 0.0;
        y       = 0.0;
        dx      = 0.0;
        dy      = 0.0;
        vel     = 0.0;
        size    = 0.0;
        angle   = 0.0;
        da      = 0.0;
    };

    public void rot()
    {


    };

    public boolean oob(int xmax, int ymax)
    {
        if((x < xmax) && (x > 0) && (y < ymax) && (y > 0))
            return true;
        return false;
    };

    public boolean hit(Coords in)
    {
        if((in.x + in.size > x) && (in.x < x + size) && (in.y + in.size > y) && (in.y < y + size))
            return true;
        return false;
    };

    public void tick()
    {
        x = (dx + x) % xmax;
        y = (dy + y) % ymax;
        angle = (angle + da) % 360;
    };
};

宇宙船クラス

import java.applet.*;
import java.lang.Math;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;

public class Ship extends Coords
{
    private ImageIcon imageIcon;
    private Image image;

    public Ship(double x_in, double y_in)
    {
        imageIcon = new ImageIcon(getClass().getResource("images/ship.png"));
        image = imageIcon.getImage();

        x = x_in;
        y = y_in;
    };

    public void thrust()
    {
        dx = dx + (vel * Math.sin(angle * RAD));  //Move points based on speed
        dy = dy + (vel * Math.cos(angle * RAD));
    };

    public void left()
    {
        da--;
    };

    public void right()
    {
        da++;
    };

    public void draw(Graphics graphics)
    {
        Graphics2D g = (Graphics2D)graphics;
        g.rotate(angle);
        g.drawImage(image, (int)x, (int)y, null);
    };
};

レーザークラス

import java.applet.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;

public class Laser extends Coords
{
    private ImageIcon imageIcon;
    private Image image;

    public Laser(double x_in, double y_in, double angle_in)
    {
        imageIcon = new ImageIcon(getClass().getResource("images/laser.png"));
        image = imageIcon.getImage();

        angle = angle_in;

        vel = 20;
    };

    public void draw(Graphics graphics)
    {
        Graphics2D g = (Graphics2D)graphics;
        g.rotate(angle);
        g.drawImage(image, (int)x, (int)y, null);
    };
};

小惑星クラス

import java.applet.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.Random;

public class Rock extends Coords
{
    private ImageIcon imageIcon;
    private Image image;

    public Rock(double x_in, double y_in, double size_in)
    {
        imageIcon = new ImageIcon(getClass().getResource("images/rock.png"));
        image = imageIcon.getImage();

        x = x_in;
        y = y_in;
        size = size_in;

        Random random = new Random();
        int r = random.nextInt();
        angle = r % 360;
        vel = r % 5;
    };

    public void draw(Graphics graphics)
    {
        Graphics2D g = (Graphics2D)graphics;
        g.rotate(angle);
        g.drawImage(image, (int)x, (int)y, null);
    };
};
4

1 に答える 1

1

この問題にアプローチする方法はいくつか考えられます。発生する最大の問題は、更新を同期して、レンダリングの開始中にモデルが更新されないようにすることです。

基礎

妥当な結果を得るには、モデル、ビュー、およびドライバー/コントローラーが必要になります。

モデルは、ゲーム アセットの状態を維持する責任があります。ビューはモデルを画面にレンダリングする役割を担い、コントローラーはモデルとビューを更新し、入力を調整する役割を果たします。

多かれ少なかれ、これらの基本的な概念のセットアップが完了しました。

私は変わるかもしれないと思います。

  • 私はsを使用したキーバインディングKeyListenerを好みます。キー バインディングは、KeyListenerフォーカス管理に関する制限を克服します。
  • JPanel最上位のコンテナ (JFrameまたはなど) に直接描画する代わりに、 (または他の同様のコンテナ) を使用しJAppletます。これには多くの利点があります。Swing コンテナはデフォルトでダブル バッファリングされており、選択した最上位コンテナにゲーム パネルを追加するだけでデプロイを選択できるようになりました。
  • ゲーム パネルからキー イベントをコントローラーに送信します (コントローラーをリスナーとしてビューに直接アタッチするのではなく)。これは主に個人的な選択ですが、受信イベントをキューに入れ、それらの入力の処理方法をより適切に制御する機能を提供します

必要なもの

  • ドライバーはスレッド化する必要があります。これは、ドライバがThreadイベント ディスパッチ スレッドの外側の独自の 内で実行されることを意味します。これにより、ドライバーがモデルを更新し、出力を準備して入力を処理している間に、UI を更新し続けることができます。サイクル間でフレーム レートを維持する (そして UI がそれ自体を描画できるようにする) ために、スレッドは "待機" する必要がある場合があります。

画面とその先へ

ゲームを画面に表示することは、一部の人が考えるよりもややこしいことです。

最も基本的な方法は、単純にモデルを更新し、repaintそれを描画するコンポーネントを呼び出してから、レンダラーに単純paintにモデルを任せることです。

このアプローチの問題は次のとおりです。

  1. 塗装が実際にいつ行われるかを知ることは不可能です
  2. 再描画が行われている間にモデルが変更される可能性があります。これにより、ペイントが汚れたり、モデルとビューの間に矛盾が生じたりする可能性があります

必要なのは、ビューを生成し、そのビューを画面に更新する方法です。

BufferedImage基本的な考え方は、コントローラーが要求できるバッキング バッファー ( など) をビューに生成させることです。コントローラは、モデルからの情報を使用してこのバッファを更新します。次に、このバッファでビュー自体を更新するように要求します。

ビューは、ペイント サイクル内で仮想ビュー間の切り替えが実行されないように、要求を同期する必要があります。

これが一般的に意味することは、コントローラーがビューに影響を与えることなくペイント サイクル間で多数の「更新」を生成できることであり、ビューは常に最新の「フレーム」を (可能な限り近くで) ペイントする必要があります。

スイッチを同期するために、保護されたコード ブロック (synchronizedステートメント内のコード ブロック) を使用できます。これに関する問題は、ペイント方法も必要になることですsynchronize。これは決して良い考えではありません。

代わりに、 を使用する必要がありますSwingUtilities#invokeAndWait。これは、ビューの switch メソッドを呼び出すために使用され、最新のバッファーを渡します。これにより、更新リクエストがイベント ディスパッチ スレッド内で発生することが保証されます。つまり、ペイント メソッドを実行することはできません (イベント ディスパッチ スレッド内でも実行されるため)。また、切り替えが行われている間、コントローラーを「停止」します。

個人的には、 のプールをセットアップしますBufferedImage(通常は 2 つですが、必要に応じて拡大および縮小できる必要があります)。アイデアは、コントローラーが「バッファー」を要求したときに、キューの一番上のバッファーをポップして返すというものです。キューに何も存在しない場合は、新しいものを作成して代わりに返します。

バッファーが返される (そしてそれらを切り替える) と、このバッファーがキューに返されます。

不必要にメモリを消費しないように、定期的にプールをクリーンアップする (余分なバッファを削除する) タイマーをバックグラウンドで起動しますが、それは私だけです ;)

于 2012-11-15T19:35:19.590 に答える