# Experimente mit Quaxlis Spiel



## Reggi (13. Mai 2012)

Hallo,
ich wollte das Spiel aus dem Tutorial von Quaxli etwas verändern, um mich ein wenig in der Materie nach vorn zu bewegen.
Angefangen hab ich jetzt damit, dass ich von dem blauen Startbildschirm weg will.
Also hab ich mir ein schönes Hintergrundbild ausgesucht, dem einen Button verpasst und Einen ActionListener für den Button eingebaut, der eigentlich doInit...() aufrufen soll, so wie es vorher die Enter-Taste gemacht hat.
Leider passiert rein gar nichts. Hab dann also mal geschaut, ob ich vielleicht den ActionEvent falsch benutzt hab aber der Button funktioniert. Hab auch schon versucht die KeyEvents auf dem Hintergrundpanel aufzurufen geht aber auch nicht. Hier mal die veränderten Ausschnitte aus der Klasse.


```
HintergrundBild hgb = new HintergrundBild("resources/Logo.png");
    JButton b = new JButton("Start");

    public SpielFeld(int w, int h) {
        this.setPreferredSize(new Dimension(w,h));
        this.setBackground(Color.BLUE);
        frame = new JFrame("Flieg Neiko, flieg");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(this);
        frame.add(hgb);
        hgb.add(b);
        frame.addKeyListener (this);
        frame.pack();
        frame.setVisible(true);
        
        Thread th = new Thread(this);
        th.start();
        
        b.addActionListener (new ActionListener() {
            @Override
            public void actionPerformed (ActionEvent e) {
                doInitializiations();
                System.out.println("Hi");
            }
        });
    }
```

Wenn ihr nochwas sehen wollt sagt es.
Sieht jemand warum ich die Methode nichtmehr aufrufen kann?


----------



## Fu3L (13. Mai 2012)

Ich verstehe noch nicht genau, was passiert und was nicht.
Wird "Hi" ausgegeben oder nicht?
Wenn es ausgegeben werden sollte, so wäre es interessant sowohl doInit... als auch die Klasse Hintergrundbild zu sehen.


----------



## Reggi (14. Mai 2012)

Ja wird es deswegen ist es ja so seltsam und das heißt ja dann, dass schonmal der Listener richtig programmiert ist.

Also hier mal die unveränderte doInitializiations():

```
private void doInitializiations() {
        last = System.nanoTime();
        gameover = 0;
        
        BufferedImage[] heli = loadPics("resources/heli.gif", 4);
        rakete = loadPics ("resources/rocket.gif", 8);
        hintergrund = loadPics ("resources/background.jpg", 1) [0];
        explosion = loadPics ("resources/explosion.gif", 5);
        
        actors = new Vector<Sprite>();
        painter = new Vector<Sprite>();
        copter = new Heli(heli,400,300,100,this);
        actors.add(copter);
        
        createWolken();
        
        timer = new Timer (3000, this);
        timer.start();
        
        started = true;
    }
```

Und hier meine Hintergrundklasse, die nicht aus dem Tutorial ist.:


```
package spiel;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class HintergrundBild extends JPanel {
       private BufferedImage bg;
 
   public HintergrundBild(String name) {
      try {
         bg = ImageIO.read(getClass().getResource(name));
         setPreferredSize(new Dimension(bg.getWidth(), bg.getHeight()));
      }
      catch(IllegalArgumentException iae) {
         JOptionPane.showMessageDialog(this,
            "Das Hintergrundbild konnte nicht gefunden werden!",
            "java.lang.IllegalArgumentException",
            JOptionPane.ERROR_MESSAGE);
      }
      catch(IOException ioe) {
         JOptionPane.showMessageDialog(this,
            "Das Hintergrundbild konnte nicht geladen werden!",
            "java.io.IOException",
            JOptionPane.ERROR_MESSAGE);
      }
   }
 
    @Override
   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      if(bg != null) {
         g.drawImage(bg, 0, 0, this);
      }
   }
}
```

Achso vielleicht ist das Detail noch interessant, dass auch wenn ich einfach nur ein Frame mit dem Hinweis bitte Enter drücken raufmale die Enter-Anweisung auch nciht mehr ging und Escape auch nicht.
Würde mich echt interessieren mit was das zusammenhängt.


----------



## Quaxli (14. Mai 2012)

Reggi hat gesagt.:


> Hallo,
> ich wollte das Spiel aus dem Tutorial von Quaxli etwas verändern, ...


Man kauft sich doch auch keinen Picassso und malt noch dran rum? 

Es fehlt mir hier ein bißchen Code, aber ich vermute mal aus dem Bauch raus, daß das Problem daran liegt, daß Deine Hintergrund-Klasse von JPanel erbt (was imho auch unnötig ist). Wie bindest Du die denn ein?
Es gibt ja schon eine BufferedImage als Instanz-Variable, wozu da eine Klasse?


----------



## Reggi (14. Mai 2012)

> Man kauft sich doch auch keinen Picassso und malt noch dran rum?



Ja ich weiß, aber so ganz recht trau ich mich doch noch nicht loszulegen, da dacht ich ein wenig mit was fertigem probieren schadet nie.
Ich binde die mit dem ersten Code oben mit 
	
	
	
	





```
frame.add(hgb);
```
Die Klasse hab ich gemacht, weil ich die schon ab und zu mal benutzt hab und die funktioniert. Aber du hast recht ich hätte mich vllt an dem anderen Hintergrundbild, was für den Spielbildschirm geladen wird orientieren sollen und das dann vor der doInitializiations() aufrufen.
Muss ich heut Abend nach der Arbeit glatt mal weiter dran rumtüfteln.

Edit:


> Es gibt ja schon eine BufferedImage als Instanz-Variable, wozu da eine Klasse?



Die Instanzvariable mit dem Hintergrundbild da oben ist ja das, was im Spiel benutzt wird. Ich will doch auf dem noch blauen Startbildschirm eins haben.


----------



## Quaxli (14. Mai 2012)

Dann liegt's wirklich daran, daß Deine Klasse von JPanel erbt. 
Du könntest es z. B. wie folgt machen:
- lade das Bild und "verdrahte" es ebenfalls mit einer Instanz-Variable (analog dem Hintergrundbild)
- in der paint-Methode des GamePanels fragst Du ab, ob das Spiel gestartet wurde oder nicht und zeichnest je nachdem einen anderen Hintergrund.

1 neue Instanz-Variable, 1 weitere Zeile zum Laden des Bildes und eine if-Bedingung (mit else-Zweig). Fertig ist der Lack.


----------



## Reggi (15. Mai 2012)

Wow vielen danke schonmal dafür .
Vielleicht sollte ich nicht so ungeduldig sein und mich mehr konzentrieren. Ist gar nicht so einfach eine Programmiersprache zu lernen. Meinen Respekt an alle, die es können.
Ich bleib auf jeden Fall am Ball und hoffe ich nerv nicht zu dolle .

Allerdings bleibt da jetzt nochwas offen, weil eigentlich wollte ich ja einen Startbutton einfügen, aber geht das ja scheinbar überhauptnicht. Also war wirklich das JPanel schuld an allem, aber JButton und JLabel verursachen den gleichen Fehler.
Wär nett, wenn mir jemand mal erklären könnte warum soetwas öglich ist.
Immerhin wird ja das Fenster eigentlich nur überwacht, kann es da dem Programm nicht völlig egal sein, ob auf dem Fenster noch ein Button oder änliches ist? ???:L


----------



## Quaxli (15. Mai 2012)

Ich würde sagen, Du denkst zu sehr in Swing, um es mal so auszudrücken 

Du hast ein JFrame und ein JPanel. Das JPanel ist die Zeichenfläche - und zwar immer, egal ob jetzt der Startbildschirm oder das eigentliche Spiel angezeigt wird. Da wechselt nichts. Alles was Du an Modifikation einbauen willst, sollte sich an dieses Konzept anlehnen bzw. es berücksichtigen.
Du möchtest da temporär Swing-Komponenten einbauen. Das ist zwar möglich, aber es wäre doch etwas umständlich (wie Du an dem Beispiel mit dem Bild gesehen hast).

Bau es mal ganz simpel nach, dann wird es vermutlich transparanter: Nimm ein JFrame, füge ein JPanel hinzu und versuche auf dieses JPanel temporär einen Button zu bekommen oder noch ein JPanel einzufügen. 

Das was Du machst würde ich etwas anders angehen. 
a) Man könnte ein bißchen mit Layouts rumspielen, z. B. CardLayout (vgl. API). 
b) Ein separates Panel hinzufügen z. B. unten über ein BorderLayout. (ebenfalls vgl. API)
c) Ich selbst würde es vermutlich einfacher halten: Nämlich den "Button" einfach auf den Startbildschirm malen und im MouseListener abfragen, ob in der Gegend, wo ich den Button hingemalt habe, rumgeklickt wurde. Das wäre halt nicht animiert... 
d) Bei einem Spiel das komplett über Tastatur gesteuert wird, würde ich gar keine Maussteuerung einbauen.


----------



## Reggi (16. Mai 2012)

Hey danke für die Tipps .
Ich werd dann mal morgen mit einer eingehenden Studie anfangen, was das betrifft. Das könnte mir warscheinlich wirklich helfen ich hab mir auch schon ein paar Gedanken gemacht, was ich dabei alles testen möchte. Und ich bin mir zwar nicht sicher, aber ich glaub ich weiß woran das mit dem Button liegt für das Spiel selbst werd ich wohl den Hintergrund einfach nochmal mit Paint bearbeiten und raufschreiben zum Starten bitte Enter drücken .
Ich meld mich wenn ich etwas neues hab. Denke mal frühstens morgen, wenn ich dann endlich wieder Zeit genug hab .


----------



## Reggi (22. Mai 2012)

Hallöchen,
jetzt hatte ich mal ein wenig Zeit zum Nachdenken und hab erstmal ein einfaches Fenster nachgebaut.
Außerdem hab ich darüber nachgedacht warum ich zu viel in swing denke.
Ich versuch das mal zu beantworten. Ich hoffe es ließt mal jemand durch und sagt mir, ob ich das richtig verstanden hab wär echt lieb .
Und zwar ist es eigentlich logisch, wenn man sich statt auf den PC, mal auf ein normales Stück Papier konzentriert. (Soll ein Panel darstellen ) Als Button nehm ich mir dazu in Gedanken einen Stein oder was auch immer.
Naja und wenn man nun versucht das Blatt Papier auszutauschen ist der Stein natürlich im Weg und man müsste ihn ERST runternehmen. Bzw, wenn ich auf dem Panel, auf dem ich arbeite ein 2 drauflege, kann es ja nicht gehorchen, weil der Listener horcht nur auf das erste Panel, das ist aber verdeckt.
Was ich damit sagen will ist:


Klar funktioniert das mit dem Button nur temporär, weil bevor ich mein Panel veränder muss ich den Button "löschen".
Und wenn ich mir das mit den Cardlayouts so angucke hört sich das echt interessant an, weil ich so einen Startbildschirm machen könnte und zum Spielen eine andere Karte "ziehe" und den Stzartbildschirm nach unten verlege.
Das mit dem Panel unterhalb ist auch super, nur würde mich stören, dass ich ja dann das ganze Spiel lang den Button sehe .


Wirklich drauf gekommen bin ich, nachdem ich mir das mit den Stein vorgestellt hab und mich an das Tutorial erinnert hab, wo man mit dem Button die Farbe vom Panel ändert.
Der Button bleibt ja drauf.
Wie gesagt würd mich freuen wenn jemand etwas dazu sagt. Ich würd es nämlich wirklich gern verstehen und hoffe, dass es so die richtige Logik hat. Auch wenn meine Logik manchmal etwas seltsam ist.


----------



## Spacerat (22. Mai 2012)

Hab' mir jetzt nicht alles durchgelesen, vermutlich probierst das ja schon aus...
Ansonsten müsstest du dir doch eigentlich nur die Instanz des Buttons merken (irgendwo als Membervariable) und bei Bedarf kann man diesen dann mit [c]<Container>.remove(myButton);[/c] entfernen. Ein JPanel erweitert ja über JComponent einen Container, von daher sollte diese oder eine ähnliche Methode dort zur Verfügung stehen. Evtl. genügt ja auch ein simples [c]<JButton>.setVisible(false)[/c].
[EDIT]





Reggi hat gesagt.:


> Auch wenn meine Logik manchmal etwas seltsam ist.


Ist dir das mit der Logik etwa peinlich? Du kennst meine noch nicht... :lol:[/EDIT]


----------



## Fu3L (22. Mai 2012)

Das mit dem Stein ist eine unpassende Metapher. Stell dir lieber vor, du klebst einen anderen Zettel drauf. Entfernst du das Blatt, geht auch der draufgeklebte Zettel automatisch weg. Einfach fenster.remove(panel); fenster.add(newPanel);


----------



## Reggi (22. Mai 2012)

Naja entscheidend ist ja die allgemeine Logik die dahinter steht.
Und wenn ich die Antworten richtig interpretiere, dann hab ich es also verstanden.
WIE das ganze geht war ja nebensache. In dem Fall fand ich die Hintergründe wichtiger.
Vielen Dank :toll:


----------

