RPG Programmieren, label.setLocation funktioniert nicht

Hag2bard

Bekanntes Mitglied
Hallo nochmal,

es geht mal wieder um mein Pokemon Projekt.

Ich habe mein Spielfeld noch nicht fertig, aber das ist erstmal irrelevant.

Java:
package pokemon;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class MainView2 extends JFrame {

    public BufferedImage img = null;

    private BufferedImage img2;
    Bob bob = new Bob(); // Lade Projekt Bob
    Ash ash = new Ash(); //lade ash

    public MainView2() {

        ImageIcon imageIcon = bob.getImageIcon(bob.bild());
        ImageIcon charakter = ash.getImageIcon(ash.ash);

        JLabel label = new JLabel(imageIcon);
        JLabel labelChar = new JLabel(charakter);
        JPanel panel = new JPanel();
        panel.add(label);
        panel.add(labelChar);

        labelChar.setLocation(500,500);
        this.add(panel);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("Bild laden bei Swing");
        this.setSize(800, 860);
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }
}

Der Code ist noch nicht gesäubert, ist im Grunde nur ein Experiment.
Ich erstelle ein ImageIcon aus einem BufferedImage. Dies soll das Spielfeld sein.
Nun erstelle ich ein weiteres ImageIcon (charakter) dies soll die Spielfigur sein.

Dann erstelle ich ein Label und füge das Spielfeld ImageIcon ein.
Dann erstelle ich ein Panel und füge das Label da ein.
Anschließend füge ich das Panel zum JFrame hinzu.

Das funktioniert soweit einwandfrei, aber wie ihr in dem Code seht, mache ich noch was anderes.
Ich erstelle ein weiteres JLabel indem ich ImageIcon (des Charakters) einfüge.
Anschließend füge ich dieses JLabel dem Panel hinzu.

Ergebnis:

bla.png

Das Spielfeld ist wie gesagt noch nicht fertig.
Der Charakter ist nun irgendwo im Bild.
Die Methode labelChar.setLocation(500,500); hat keine Auswirkung auf die Positon des Charakters.

Was habe ich falsch gemacht?

Danke im Voraus
 
Ein Panel hat standardmäßig einen LayoutManager (FlowLayout), der die Komponenten platziert. panel.setLayout(null) könnte helfen.
 
Wenn ich den LayoutManager vom Panel auf null setze, bekomme ich kein Bild mehr

1635001376267.png


Java:
package pokemon;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class MainView2 extends JFrame {

    public BufferedImage img = null;

    private BufferedImage img2;
    Bob bob = new Bob(); // Lade Projekt Bob
    Ash ash = new Ash(); // Lade Ash

    public MainView2() {

        ImageIcon imageIcon = bob.getImageIcon(bob.bild());
        ImageIcon charakter = ash.getImageIcon(ash.ash);

        JLabel label = new JLabel(imageIcon);
        JLabel labelChar = new JLabel(charakter);

        JPanel panel = new JPanel();
        panel.setLayout(null);
        panel.add(label);

       // panel.add(labelChar);

        this.add(panel);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("Bild laden bei Swing");
        this.setSize(800, 860);
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }
}
 
Du musst beim null-Layout auch die Größe der Elemente festlegen, mit setBounds dürfte es am einfachsten funktionieren.
 
Mein Vorschlag hier wäre eh: Bau alles aus einem einzigen Bild auf. Sprich: du erstellst ein BufferedImage mit der Größe der Client Bereiches und das baust du dann regelmäßig neu auf. Wenn sich etwas verändert z.B.

Der UI Thread muss also immer nur das aktuelle Bild anzeigen und wir sehr einfach.

Was du dann aber noch hast ist eine Logik, die halt sicher stellt, dass du mit mund. zwei Bildern arbeitest: ein Bild wird gerade angezeigt und ein anderes Bild wird gerade vom Spiel Thread neu erzeugt. Wenn ein Bild neu erzeugt wurde, dann wird es dem UI Thread zur Verfügung gestellt und ein Reprint wird aufgerufen. Wenn der UI Thread das neue Bild nimmt, dann wird das alte Bild frei und kann wieder verwendet werden.

Das ist die Logik, die ich in der Regel verwende. Auch um ein flackern und so zu vermeiden.
 
Vielen Dank für die Antworten,

Ok, also nochmal für Dumme zum Mitschreiben:

Also ist folgende Idee performancetechnisch gut?:

Ich habe ein BufferedImage mit der Map, welches so bleibt. (mapImage)
Dann habe ich ein weiteres BufferedImage (showedImage) , welchem ich das mapImage zuweise und darauf dann meinen Charakter BufferedImage zeichne, je nachdem welche Position ich gerade möchte.
Wenn sich der Charakter durch ein Tastendruck auf z.b. rechts um 1 Feld nach rechts bewegt, dann weise ich dem showedImage wieder das mapImage zu und zeichne darauf dann meinen Charakter an der neuen Position.

Ist das so richtig?

Und wenn ich dann den Charakter noch animieren möchte (ich hab 3 Bilder, bei einem steht er, bei einem ist der linke Fuß vorne, beim anderen der rechte) dann mache ich also folgendes:

showedImage mit Charakter an Position 400x400 (16 Pixel = 1 Block)
showedImage wird zurückgesetzt (showedImage = mapImage)
showedImage mit Charakter an Position 408x400 (mit rechtem Fuß vorne)
showedImage wird zurückgesetzt (showedImage = mapImage)
showedImage mit Charakter an Position 416x400 (Charakter steht)

Ist das so in Ordnung?
Ich dachte es wäre performanter ein JLabel zu bewegen anstatt immer wieder das BufferedImage zu zeichnen.

Dann würde ich jetzt erstmal im Laufe der nächsten Zeit meine Map fertig stellen, schauen dass ich die Charakter Bilder habe (3 Stück pro Richtung) und dann müsste ich euch nochmal fragen, wie ich das ganze mit den Threads aufbaue.
 
Ich dachte es wäre performanter ein JLabel zu bewegen anstatt immer wieder das BufferedImage zu zeichnen.
Das wäre duchaus denkbar. Swing optimiert durchaus das Zeichnen von dirty-Regions, ich weiß allerdings nicht, ob JLabel das auch unterstützt. Daher würde ich das selbst implementieren.

Und wenn ich dann den Charakter noch animieren möchte (ich hab 3 Bilder, bei einem steht er, bei einem ist der linke Fuß vorne, beim anderen der rechte) dann mache ich also folgendes:
Du zeichnest einfach von hinten nach vorne, also zuerst das Hintergrundbild, dann was "auf" dem Hintergrundbild liegt. Bei einer Animation kannst Du repaint ein Rechteck mitgeben, dann hast Du den betreffenden Ausschnitt und musst nur diesen neu zeichnen.
 
Performancetechnisch bist du besser dran, wenn du direkt ins Bild zeichnest, sobald sich die Position ändert.
Swing-Komponenten kommen da performancetechnisch nicht ran, die machen noch eine Menge mehr. Das Positionieren eines JLabels löst eine Menge Events aus, im Label selbst, im Ancestor und wahrscheinlich auch in allen Sub-Kompenenten des Ancestors.

Bei dem, was du hier vorhast, fällt das alles aber nicht ins Gewicht. Mach das, was weniger Aufwand ist.
Oder aber bau für das Ganze mal einen Wrapper, der die Methoden bietet, die du ansprechen willst (positionieren, Auslösen von Neuzeichnen z.B.). Darin verwende erst mal ein JLabel. Falls die Performance nicht passt, kannst du dann dort immer noch was schnelleres implementieren, ohne den eigentlichen Spielcode zu ändern.
 

Zurück
Oben