Also mal einfach von Anfang an:
a) Kritik an dem Tutorial solltest Du nicht auf Dich beziehen.
b) Was an dem Tutorial schlecht ist: Java ist eine Objektorientierte Sprache. Daher sollte man verstehen, was eben Objekte sind. Und dazu gehört, das man dann auch z.B massiv auf das Schlüsselwort "static" verzichtet. Anfängern hier im Forum empfehlen wir oft, auf dieses Schlüsselwort komplett (bis auf das "static void main") zu verzichten. Denn das verhindert nach meiner Erfahrung massiv die Erlernung einer Objektorientierten Sprache.
c) Dein Code - mögliche Fehler.
c1) Eine Vermutung ist, dass Du in der Logik etwas falsch machst. Evtl. stimmt die Reihenfolge von Aufrufen nicht oder etwas, das Du gerne aufrufen möchtest, wird nicht aufgerufen. Hier bietet sich die Nutzung eines Debuggers an. Oder wenn Dir das noch zu kompliziert ist: Bau mehr Ausgaben ein.
c2) Die Vermutung, die auch geäußert wurde, ist, dass Du die Daten in einen Stream schreibst. Dieser puffert die Daten zwischen (und schreibt diese nicht sofort) und dann kommt der Garbage Collector und zerstört das Objekt, ehe die Daten geschrieben werden konnten.
d) Dein Code - was daran unschön ist (und damit eine direkte Kritik an dem Tutorial ist!)
Nehmen wir uns nur einmal die main Methode um zu sehen, was die Applikation macht:
public static void main(String[] args) throws IOException {
// write your code here
new Gui(); //die Gui wird erstellt, wenn das Programm startet
new Var(); //die Var wird erstellt, wenn das Programm startet
new Label(); //das Label wird erstellt, wenn das Programm startet
new KeyHandler(); //der KeyHandler wird erstellt, wenn das Programm startet
new Background(); //das Background-Verhalten wird erstellt, wenn das Programm startet
new PlayerMovement();
new FlammenAnimation();
new GegnerMovement();
new SchrottMovement();
new GegnerKollision();
new SchrottKollision();
new Explosion();
new ActionHandler();
new SpeicherVorgang();
}
Du erstellst eine ganze Reihe an Instanzen, aber keine Instanz scheint Dich wirklich zu interessieren, denn die erstellten Instanzen speicherst Du nicht.
Was mich daran massiv stört ist:
Das Erstellen einer neuen Instanz soll nur eine neue Instanz erzeugen. Wenn ich sage: Ich habe hier einen Bauplan von einem Haus, das Haus baue ich mir. Dann wird lediglich das Haus gebaut. Und danach möchte ich das erzeugte Haus haben. Bei Deinem Code ist das: Bau mir ein neues Haus und dann schmeiss es direkt weg.
Dann ist das "new House()" einfach ein erzeugen eines neuen Hauses. Da sind erst einmal keine Aktionen inbegriffen wie: Ich gehe in die Küche und koche eine Gulasch. Klar, das kann man technisch machen. Aber wenn ich jemandem sage "Ich baue mir ein Haus", dann erwartet niemand in dieser Aussage, dass ich einen Topf Gulasch koche. ==> Jemand der den Code sieht, will ja wissen, was in dem Code passiert. Und das sieht man in dem Code nicht, weil Du Aktionen in dem Construktor zu verstecken scheinst.
Also konkretes Beispiel wäre z.B. ein JFrame. "new JFrame()" erzeugt ein JFrame Objekt. Aber damit wird noch nichts gemacht. Das wird noch nicht angezeigt oder so. Keine versteckten Aktionen sind im "new Frame()" enthalten.
Also nur noch einmal zum Verständnis:
Klassen sind vergleichbar mit Bauplänen. Mit den Bauplänen erzeugst Du Objekte und diese nutzt Du. Also Du nutzt den Bauplan Notizblock um einen Notizblock zu erzeugen. Und en erzeugten Notizblock nutzt Du dann um da was rein zu schreiben. Du fängst doch nicht an, auf dem Bauplan rum zu kritzeln!
Dann weiter zum Verständnis: Deine Klasse Var hat nur einen Inhalt: eine statische Variable. Es macht also keinen Sinn, davon eine neue Instanz zu erzeugen. ein "new Var()" ist also einfach sinnlos. Das ist so etwas wie: Hier ist ein leerer Bauplan - auf dem habe ich zwar etwas notiert, aber sonst ist er einfach leer. Nun bau mir bitte nach diesem Bauplan ein neues Objekt ....
(Und da Du eine Instanzen davon erzeugst, ist - wie schon erwähnt wurde - das Serializable Sinnlos. Du willst sozusagen, dass die Objekte, die vom leeren Bauplan erzeugt werden, auch mit der Post versendet werden können.)
Ein Punkt, der auch wichtig ist, weil es ein mögliches Problem sein könnte:
In Java gibt es einen Müllmann (Garbage Collector). Der geht regelmäßig alles durch und sucht nach Objekten, die niemand mehr in der Hand hält. Und die zerstört er einfach.
Wenn Du also ein Objekt erzeugst, dann solltest Du es immer "in der Hand" behalten. Das bedeutet unter dem Strich, dass ein Thread auf dieses Objekt zugreifen können muss. Das muss nicht direkt sein - das geht auch über Umwegen. Also wenn ein Thread ein Objekt kennt, dass das fragliche Objekt kennt dann ist das auch ok.
Und dann das Problem mit dem BufferedStream:
Du willst etwas wegbringen. Aber damit Du nicht für jedes Paket extra zur Post rennen musst, hast Du eine Kiste, und in die wirfst Du alle Pakete. Und hin und wieder bringst du dann alle Pakete aus der Kiste zur Post. Nun mit dem, was ich davor geschrieben haben: Du wirfst es in die Kiste, aber dann interessiert dich die Kiste nicht mehr. Dann kommt der Müllmann und wirft die Kiste mit allen Paketen in den Müll - und dann kommen die Pakete nie zur Post.
Konkret bedeutet dies:
public static void writeHighscoreToFile () throws IOException
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("SpielDaten.bin"));
oos.write(Var.Highscore);
}
Du erzeugst eine Variable oos und rufst write auf. Danach ist die Methode zu Ende und damit die Instanz in oos vergessen und wird ein Fall für den Müllmann (Garbage Collector). So das, was Du geschrieben hast mit write noch nicht auf die Platte geschrieben hast, bedeutet dies, dass es weg ist.
Die Lösung ist hier einfach und eines der Grundprizipien von Java: Es gibt ein Interface AutoClosable, welches von Streams implementiert wird. Und die einfache Regel wurde schon genannt: Wenn ein Objekt AutoClosable implementiert, dann sollte man dieses schließen. Java hat dafür sogar extra ein Konstrukt: Try with ressources. Damit sähe der Code dann so aus:
public static void writeHighscoreToFile () {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("SpielDaten.bin"))) {
oos.write(Var.Highscore);
} catch (IOException ex) {
System.err.println("Couldn't write highscore: " + ex.getMessage());
ep.printStackTrace();
}
}
Nebenbei noch ein paar Dinge mehr eingebaut:
- Java Coding Style: { gehört in die gleiche Zeile.
- das throws habe ich raus genommen. Gibt doch keinen Grund, das weiter zu reichen ....
- Wenn exception, dann immer alles Ausgeben. Also mindestens die Message und den StackTrace! Eine einfache Aussage wie "Da ist was schief gelaufen" hilft nicht wirklich weiter...
- Und natürlich das try with ressources
e) Meine Empfehlung
Geh ein Lehrbuch durch. Java ist auch eine Insel ist frei und nicht schlecht. Evtl. gibt es auch auf YouTube vernünftige Java Kurse, aber ich hoffe, ich konnte darlegen, was schief läuft.
Und wenn Du gewisse Hinweise nicht verstehst (ist nichts schlimmes), zeigt doch, dass gewisse Grundlagen eben nicht behandelt wurden in dem Tutorial. Und dass wichtige Grundlagen fehlen. Daher die Empfehlung: Schau Dir z.B. das genannte Buch an! So lange Posts wie diesen sind in meinen Augen Unsinn, denn auch ich mache den Fehler, dass ich versuche komplexe Sachverhalte in viel zu kurzer Weise zu erläutern. Und das mal eben so. Dabei gibt es das alles in vernünftiger Form gut überdacht frei Verfügbar im Netz:
http://openbook.rheinwerk-verlag.de/javainsel9/index.htm
Ich hoffe du verstehst nun auch unser Problem mit Deiner Fragestellung: die kurzen, knappen und prägnanten Antworten sind teilweise nicht möglich und die Ansätze haben große Verständnisprobleme.
Du musst meinen Vorschlag auch nicht wahrnehmen. Du kannst gerne auf Discord mit denen reden, die dieses Tutorial toll finden und dieses Vorgehen tatsächlich supporten wollen. Aber zumindest mein Anspruch ist dies nicht. Ich helfe gerne, aber da muss es auch etwas Sinn machen.