Développement de Jeux Java: Graphiques


Je suis nouveau ici. Espérons que vous serez en mesure de vous aider.

Problème: Problème avec l'affichage de l'animation sur JFrame. Il semble que je manque/ne comprends pas assez comment les graphiques de Java fonctionnent.

Idée globale: Disons que je veux faire un jeu/film/clip. Pour cela, j'ai besoin de cette animation (pas)simple.

Un exemple pour cette question: J'ai obtenu class Screen, qui a la déclaration stuff screen du JFrame, configurant sa configuration (taille, fermer opération, etc.) puis en créant les objets de la boîte de classe, à afficher sur le cadre. Vérifiez svp cette image / diagramme des classes (j'espère que je l'ai écrit de la bonne façon): ClassesDiagram

Maintenant, class Box étend JPanel. J'hérite de JPanel la méthode Paint () et la remplace, peignant des boîtes.

Dans la classe Screen, après avoir créé les deux boîtes, je .ajoutez-les () au JFrame. Ensuite, démarre une boucle while(true) et met à jour la position de la boîte tous les 200 milisec en thread dormir ce montant. (dans ce cas, simplement x++ ou y++ dépend de quelle boîte, box1 ou box2).

Problème principal 1): Le programme s'exécute et affiche le JFrame, mais sur le JFrame, il affiche uniquement le dernier objet/composant - box ajouté. Il ne montre pas l'autre. Pourquoi?

J'ai trouvé un sujet, Comment ajouter plusieurs composants d'une JFrame?, et a essayé les conseils le post le plus voté a donné, par jjnguy Nov 15 '10 à 17:02. Pour une raison étrange, pas le d'abord, ni la deuxième astuce n'a fonctionné pour moi.

Problème principal 2): Pour autant que je sache, j'ai besoin du gestionnaire de mise en page. Pourquoi en ai-je besoin, si je veux juste peindre() à X,Y spécifique sur le cadre?

Trouvé un autre article(je ne peux pas le trouver à nouveau)+Les directives d'Oracle sur les mises en page, ont suggéré que je doive envisager d'utiliser setLayout(null); J'ai essayé de le faire, mais il y a à nouveau un problème.

Problème principal 3): {[6] } Le JFrame apparaît, il ne montre que 1 boîte(la verte ne s'affiche pas jusqu'à, tout ce que vous allez faire. Je ne sais pas pourquoi) et quand il bouge - il est effacé de l'autre côté. Ici: Mouvement de boîte

Merci d'avance pour toute aide, conseils et explications! J'espère que le message est clair, organisé et agréable à regarder.


public class Screen {

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

private JFrame window;

public Screen() {
    window = new JFrame("Multiply components panel");
    //window.setLayout(null);
    window.setSize(200, 200);

    window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    Box b1 = new Box(10,10, "box1");
    //b1.setBounds(10, 10, 50, 50);

    Box b2 = new Box(100,100, "box2");
    //b2.setBounds(100, 100, 50, 50);


    window.add(b1);
    //window.add(b2);


    window.setVisible(true);

    while (true){

        b1.update();
        b2.update();

        try {
            Thread.sleep(200);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

}
}

public class Box extends JPanel{

int x, y, w, h;
private String name;

public Box(int x, int y, String name) {
    this.x = x;
    this.y = y;
    this.w = 100;
    this.h = 100;
    this.name=name;
}


public void paint(Graphics g){
    System.out.println(this.name.equalsIgnoreCase("box1"));
    if(this.name.equalsIgnoreCase("box1")){
        g.setColor(Color.BLACK);
        g.fillRect(x, y, w, h);
    }else{
        g.setColor(Color.GREEN);
        g.fillRect(x, y, w, h);
    }


}


public void update() {
    if(this.name.equalsIgnoreCase("box1"))
        x++;
    else
        y++;
    //this.setBounds(x, y, w, h);
    System.out.println("Current "+name+": X: "+x+", Y: "+y+", W: "+w+", H: "+h);
    repaint();
}

}
Author: Community, 2013-06-29

1 answers

Problème principal 1): Le programme s'exécute et affiche le JFrame, mais sur le JFrame il montre seulement le dernier objet ajouté/component - Box. Il n'a pas montrer l'autre. Pourquoi?

Vous le faites window.add(b1); window.add(b2);, par défaut, JFrame a BorderLayout donc vous remplacez la dernière boîte ajoutée lorsque vous faites add(..).

Problème principal 2): Pour autant que je sache, j'ai besoin du gestionnaire de mise en page. Pourquoi ne J'en ai besoin, si je veux juste peindre () à X,Y spécifique sur le cadre?

Si vous utilisez JPanel s comme objets dans le jeu, ce serait le seul moment d'utiliser setLayout(null)car nous voulons un contrôle total sur le placement de JPanel.

Problème principal 3): Le JFrame apparaît, il n'affiche que 1 boîte (le vert on ne se présentera pas, quoi que vous fassiez. Je ne sais pas pourquoi) et quand il BOUGE-il est effacé de l'autre côté. Ici: Mouvement de boîte

Parce que vous faites cela g.fillRect(x,y,w,h), cela devrait être g.fillRect(0,0,w,h)

D'Autres problèmes:

1) je pensez qu'un problème majeur que vous avez est ici:

public class Box extends JPanel{

    ...

    public void paint(Graphics g){

       ...
    }

}

, Vous devez remplacer paintComponent de JPanel, et n'oubliez pas d'appeler super.paintComponent(g) comme premier appel de méthode redéfinie.

3) vous devez remplacer getPreferredSize de JPanel et renvoyer les dimensions correctes qui correspondent à l'image ou au contenu du JPanel

4) n'appelez pas setSize sur JFrame utilisez correctement Layoutmanager et/ou remplacez getPreferredSize des conteneurs nécessaires que d'appeler simplement pack() sur JFrame avant de le définir visible.

5) comme dit par @MadProgrammer a une lecture surConcurrence dans Swing mais fondamentalement tous les composants Swing doivent être créés/manipulés sur EDT via SwingUtilities.inokeXXX bloc.

6) faire cela est définitivement mauvais:

while (true){

    b1.update();
    b2.update();

    try {
        Thread.sleep(200);
    } catch (Exception e) {
        // TODO: handle exception
    }
}

Comme vous ne créez pas seulement une boucle continue, mais appelez également Thread.sleep sur le thread que vous avez créé, votre interface graphique semblera donc geler. Jetez un oeil à Comment utiliser Swing Minuteries, voir aussi ce question similaire.réponse sur le sujet ci-dessus.

Ici le code avec les correctifs ci-dessus est-il implémenté:

entrez la description de l'image ici

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Screen {

    private JFrame window;

    public static void main(String[] args) {

        //creat UI on EDT
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Screen();
            }
        });
    }

    public Screen() {
        window = new JFrame("Multiply components panel") {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(600, 400);
            }
        };

        window.setLayout(null);//only reason this is warrented is because its a gmae using JPanels as game objects thus we need full control over its placing
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//changed from DISPOSE to EXIT so Timers  will be exited too

        final Box b1 = new Box(10, 10, 50, 50, "box1");

        final Box b2 = new Box(100, 100, 50, 50, "box2");

        window.add(b1);
        window.add(b2);

        window.pack();
        window.setVisible(true);

        Timer timer = new Timer(200, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                b1.update();
                b2.update();
            }
        });
        timer.setInitialDelay(0);
        timer.start();

    }
}

class Box extends JPanel {

    int x, y, w, h;
    private String name;

    public Box(int x, int y, int w, int h, String name) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.name = name;
        setBounds(x, y, w, h);//let the Box class handle setting the bounds more elegant OOP
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println(this.name.equalsIgnoreCase("box1"));
        if (this.name.equalsIgnoreCase("box1")) {
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, w, h);
        } else {
            g.setColor(Color.GREEN);
            g.fillRect(0, 0, w, h);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(w, h);
    }

    public void update() {
        if (this.name.equalsIgnoreCase("box1")) {
            x++;
        } else {
            y++;
        }
        this.setBounds(x, y, w, h);//set the new bounds so box may be updated
        System.out.println("Current " + name + ": X: " + x + ", Y: " + y + ", W: " + w + ", H: " + h);
        revalidate();
        repaint();
    }
}

Enfin, jetez un oeil à mon tutoriel/extrait de code Boucle de développement de jeu, Logique et détection de collision Java Swing 2D.

Il a tout ce dont vous avez besoin pour démarrer un jeu 2D simple, comme la boucle de jeu, la logique, la détection de collision de pixels , l'animation (c'est-à-dire l'échange entre plusieurs sprites pour créer une animation de l'ensemble de sprites), et plus encore, la différence fondamentale est qu'il utilise des objets la classe contiendra toutes les informations nécessaires pour qu'un objet soit dessiné, IMO c'est ainsi que les jeux doivent être faits, une chose pourrait devenir graphiquement intense et avoir de nombreux JPanels se demandant l'écran va certainement baisser FPS global

 3
Author: David Kroukamp, 2017-05-23 12:05:26