Ein zweidimensionales Array halte ich für unnötig kompliziert.

Der eigentliche Zustand eines GunGame-Spielers ist nur sein Level. Daraus ergibt sich dann auch seine Ausrüstung.

Dein Spielerdatenobjekt könnte dementsprechend so aussehen:

GunGamePlayer
- level: int
+ GunGamePlayer(level: int)
+ getLevel(): int
+ levelUp(): void
+ resetLevel(): void

und dann hast du noch ein Managerobjekt, welches alle Spieler über eine Map verwaltet:

GunGameManager
- players: Map<UUID, GunGamePlayer>
+ getGunGamePlayer(playerId: UUID): GunGamePlayer
+ registerPlayer(player: Player): void

Wenn ein Spieler seinen Level ändert, holst du dir das zugehörige GunGamePlayer-Objekt und aktualisierst dessen Zustand. Im Anschluss kannst du seine Ausrüstung ermitteln:

var gunGamePlayer = getGunGamePlayer(player.getUniqueId());
gunGamePlayer.levelUp();

var equipment = EquipmentManager.getEquipment(gunGamePlayer.getLevel());
var inventory = player.getInventory();
inventory.clear();

for (var item : equipment.getItems()) {
  inventory.addItem(item);
}

Im EquipmentManager würde sich sicherlich ein einfaches Array lohnen, welches bestimmt, welches Equipment welchem Level (= Arrayindex) zugeordnet ist.

EquipmentManager
- equipment: Equipment[]
+ getEquipment(level: int): Equipment

Equipment
- items: ItemStack[]
+ getItems(): ItemStack[]

Mein Modell ist soweit recht abstrakt gehalten, um später möglichst flexibel zu sein. Wenn du merkst, dass du diese Flexibilität nicht brauchst, kannst du es noch vereinfachen. Wenn du je Spieler bspw. wirklich nur das Level speicherst und sonst keine weiteren Zustände, könntest du im GunGameManager auch eine Map verwenden, die nur Spieler-ID und Level speichert.

...zur Antwort

Wenn du in Java ein neues Objekt kreieren möchtest, brauchst du dessen Konstruktor. Er wird also bei der Objekterzeugung immer mit aufgerufen und kann genutzt werden, um den Anfangszustand des Objekts zu setzen.

Beispiel:

class Cat {
}

class Dog {
  private String color;
  private String name;

  public Dog(String name) {
    this.color = "yellow";
    this.name = name;
  }
}

// in main:
var garfield = new Cat(); // default constructor call
var odie = new Dog("Odie"); // custom constructor call

Wenn kein expliziter Konstruktor (wie in Dog) für die Klasse definiert wird, hat die Klasse einen Standardkonstruktor, der zum Einsatz kommt. Der macht dann aber auch nichts besonderes. Bei Dog siehst du, dass der Konstruktor beide Felder vorbelegen kann.

In deinem Fall:

private final GunGamePlugin plugin;

public ItemManager(GunGamePlugin plugin) {
  this.plugin = plugin;
}

sicherst du über den Konstruktor ab, dass mit Erstellen des Objekts, auch dessen plugin-Feld definitiv definiert wird. Da es sich hier um eine Konstante handelt, musst du es sogar über den Konstruktor tun. Konstanten brauchen immer von Anfang an einen Wert (s.u.).

(...) und dann über Main.getplugin() auf die Main zugreifen?

Zunächst einmal ist das this in dieser Zeile:

this.plugin = plugin;

irreleitend. Es ist in der Syntax zwar nicht falsch, aber bei plugin handelt es sich um kein objektgebundenes Feld. Es ist statisch. Das heißt, alle Instanzen der Klasse Main teilen sich das Feld bzw. zeigen dann auf das gleiche Objekt (plugin).

Besser wäre diese Formulierung im Code:

Main.plugin = plugin;

Diese Lösung ist im Gegensatz zu der Lösung via Konstruktor unsicherer, denn du hast keine Absicherung, wann das Feld besetzt wird und schaffst zudem eine globale Abhängigkeit (jeder bekommt Zugriff auf plugin, kann also dessen Zustand ändern). Es handelt sich um ein klassisches Antipattern.

Wenn du in der Entwicklung die obige Zeile vergisst oder es zu irgendeiner Konstellation kommt, in der diese Zeile später ausgeführt wird, als der Aufruf von getPlugin, landest du schnell bei einer NullPointerException.

Bei Projektbeginn oder einem generell kleinen Projekt mag alles noch übersichtlich genug sein, sodass du das noch praktisch sicher handhaben kannst, wann und von wem ein Zugriff erfolgt. Mit zunehmender Projektkomplexität wird es wiederum schwerer, solche Fälle im Auge zu behalten und wenn sie für Probleme sorgen, die Ursache zu finden.

(...) wieso muss man oben alle dinge als private final nochmal definieren (...)

Das:

private final GunGamePlugin plugin;

ist eine Deklaration, keine Definition.

Bei einer Definition wird eine Variable mit einem expliziten Wert belegt. Konstanten (gekennzeichnet mit dem final-Modifier) brauchen von Beginn an einen expliziten Wert. Entweder man initialisiert sie:

private final GunGamePlugin plugin = new GunGamePlugin();

oder gibt ihnen spätestens im Konstruktor einen Wert.

In deinem Fall ist der Weg über den Konstruktor die logische Wahl, denn das Feld soll ja auf ein bestimmtes GunGamePlugin-Objekt zeigen.

Der Konstruktor dient also dem Zweck, das bei Anlegen eines GunGameListener-Objekts alle Konstanten jeweils mit einem Wert besetzt werden. Diese Werte werden vom Aufrufer bestimmt wird.

Um es nochmal anhand des obigen Dog-Beispiels zu verdeutlichen:

var lassie = new Dog("Lassie");
var odie = new Dog("Odie");
var rex = new Dog("Rex");

Drei Dog-Objekte werden erzeugt, für jedes Objekt wird ein anderer Name an den Konstruktor überreicht. Der Konstruktor schreibt diesen Wert in das name-Feld der jeweiligen Objekte.

...zur Antwort
Jetzt zu meiner Frage: gibt es ein Grund warum man nicht einfach den ganzen Hash zur Seite schickt?

Damit die API-Anwendung nicht darauf zurückschließen kann, welches Passwort du gerade prüfst.

Wenn du ein beliebiges Passwort via SHA-1 hashst, erhältst du als Resultat immer den gleichen Hashwert. Ein Anbieter wie haveibeenpwned kennt zu all den bereits kompromittierten Passwörtern auch den Hash, könnte also in dem Moment, in dem du deinen kompletten Hash herüberschickst, abgleichen, für welches Passwort du gerade nachschaust.

Generell ist zu berücksichtigen, das der SHA-1-Algorithmus ziemlich schnell berechenbar ist. Du könntest von einem Computer innerhalb von Sekunden Hashlisten mit Millionen bis Milliarden Einträgen vorberechnen lassen. Umso schwächer das Passwort gewählt ist, umso einfacher/schneller geht das.

Deshalb sieht das Prinzip von haveibeenpwned vor, dass du nur einen Präfix schickst und die API dir daraufhin die Menge an Hashes zurückgibt, die ebenso mit diesem Präfix beginnen. Du kannst dann auf deiner Seite prüfen, ob einer dieser Hashes mit deinem übereinstimmt.

Die Präfixlänge ist übrigens auf 5 beschränkt (~ 16^5 Möglichkeiten), um die Antwort auf der einen Seite nicht allzu groß zu gestalten, aber dennoch eine ausreichend große Anonymitätsmenge zu bewahren.

Die API kennt also allerhöchstens einen Suchraum an Hashes, die zutreffen könnten. Selbst bei nur einen zurückgegebenen Listenwert wäre unsicher, ob dein Hash überhaupt darauf passt - dein Passwort könnte ja noch zu den nicht kompromittierten gehören.

if local_suffix in response.text:

Statt auf einen Teilstring (contains) zu prüfen, wäre es sicherer, nach einem exakten Match zu suchen, indem du das Ergebnis aufsplittest. Das Response-Format wird in der API-Dokumentation gezeigt.

Hatte beim Header irgendwas reingeschrieben, da stand name des Programms, das hab ich noch nicht ganz verstanden (...)

Der User Agent gibt in dem Fall an, dass die Anfrage von Password Manager kam.

Die API verlangt für diesen Header eine möglichst aussagekräftige Angabe, um Requests einfacher einordnen zu können. Die Informationen eignen sich, um Statistiken anzulegen, für Logs/Monitoring und gegebenenfalls um Missbrauch zu erkennen.

...zur Antwort

Ich denke, deiner Seite fehlt es an Konsistenz. Links/Buttons, Überschriften, Bilder, Hintergründe, ... - auf jeder Seite sieht es immer wieder anders aus. Die ungünstige Platzaufteilung von verschiedenen Elementen verstärkt diese Unruhe. Dazu gesellen sich Unfeinheiten im Positionieren und Anordnen einiger Inhalte. So wirkt die Seite oft nicht ästhetisch.

Zuallererst würde ich dir empfehlen, dir zu überlegen, welchen Stil du denn nun vertreten möchtest und was tatsächlich zu dir passt. Wenn ich mir den Header anschaue, erwarte ich zuerst ein eleganteres Auftreten. Die Farben und die Schrift lassen sich zu einem Musiker der Klassik gut zuordnen. Wenn ich nun auf die About-the-artist-Seite gehe, schlägt mir plötzlich ein völlig anderer, jugendlicherer Stil entgegen. Ohne Kontext könnte man vielleicht das Electronic-Musikgenre vermuten. Dazu steuert nicht nur dein nächtliches Profil mit Kapuze bei. Es sind vor allem die unterschiedlichen Schriftstile, die hier verwendet werden.

Suche Stichworte, die dich / deine Musik tatsächlich repräsentieren und schau dann, welche Farben/Farbstimmungen und Schriftstile dazu passen könnten. Das wird ein wenig Ausprobieren erfordern, evt. kann Adobe Color dabei helfen. Lass dich ebenso von anderen Künstlerportfolios inspirieren, die sich deinem Style ähneln.

Es sollte nur nicht mehr alles je Seitenelement gegeneinander laufen.

Ein Negativbeispiel sind bei dir die Bilder, die manchmal an den Ecken abgerundet sind, manchmal wiederum nicht, ohne dass sich daraus eine Logik ableiten lässt.

Ein zweites großes Konsistenzproblem liegt in der Gestaltung von Navigationselementen und der Texthierarchie.

Bei dir wechselt sich der Style für Überschriften von Seite zu Seite, Sektion zu Sektion immer wieder ab. Mal ist die Überschrift unterstrichen, mal hat sie eine andere Farbe, mal besteht sie nur aus Großbuchstaben, mal ist es ein anderer Schriftstil, mal ist sie linksbündig - dann wieder zentriert. Im HTML-Code sieht es an der Stelle ebenfalls nicht gut aus. Ebenen (z.B. h1, h2, h4) werden übersprungen und HTML-Elemente wie strong oder u zweckentfremdet (sie sind nicht dazu da, Überschriften zu kennzeichnen!).

Gehe all deine Seiten besser noch einmal durch, sammel die Inhaltsmodule, die du verwenden möchtest (Linklisten, Teaser, einfache Textmodule) und schaffe dazu ein einheitliches Modell, bei dem die Texthierarchie deutlich wird (sowohl im Markup, als auch visuell - bspw. mittels Schriftgröße und Farbe). Vermeide nach Möglichkeit Sprünge zwischen Schriftstilen, horizontaler Ausrichtung und Farben.

In dem Zuge könntest du zugleich die CTAs (Buttons, Links) überarbeiten, sodass immer klar erkennbar ist, dass es sich gerade um die Navigationselemente der Seite handelt. Plane Status wie Hover, Fokus mit. Es hilft Nutzern ungemein, wenn ein interaktives Element bei Interaktion seinen visuellen Status anzeigt.

Auffällig ist zudem, dass du oftmals nicht geprüft hast, ob ein Mindestkontrast zwischen Vorder- und Hintergrundfarbe gegeben ist. Schwarz auf Schwarz, Rot auf Graubraun - das beißt sich. Generell würde ich die Hintergrundfarbe nicht je Seite immer wieder ändern und auf Farbverläufe gänzlich verzichten.

Einige weitere Punkte zum Design/Inhalt, die mir beim Durchschauen der einzelnen Seiten aufgefallen sind (ich habe mir nur die englische Sprachversion angesehen):

  • Der BCP47-Wert des HTML-Dokuments (lang-Attribut auf html-Element), der die Sprache angibt, ist (da habe ich doch einmal kurz geprüft) in fast allen Sprachversionen wohl nicht ganz richtig. Für EN ist es en-PH (philippinisches Englisch), für DE ist es de-AT, in ES ist es es-AR. Das solltest du nochmal unter die Lupe nehmen. Berücksichtige dabei deine URL-Struktur. Wenn du z.B. explizit de-AT anbieten möchtest, würde ich der Eindeutigkeit halber die URLs auch auf /de-AT/ ändern.
  • Der Menüpunkt Home ist eigentlich überflüssig, da bereits das Logo auf die Startseite verlinkt.
  • Die Menüpunkte in der mobilen Navigation nach rechts zu positionieren, statt linksbündig oder zentriert mit Klickfläche über die komplette Breite, halte ich für keine gute Idee. Es ist schwieriger, Untermenüs zu öffnen.
  • Deine Inhalte sind nicht nach dem ersten Viewport ausgerichtet, was vor allem bei der Stage auffällt. Das heißt, ich muss erst scrollen, bevor ich den Titel "Pianist / Artist..." sehen kann. Auf einigen anderen Seiten (z.B. About-the-artist, Gallery, Upcoming-music-projects) könntest du die Inhalte weiter nach oben ziehen. Auf diese Weise hältst du Besucher eher auf der Seite, da sie einen früheren Einstiegspunkt zu deinen Inhalten finden.
  • Die Erzählperspektive (He...) ist etwas distanziert. Überlege doch einmal, ob es nicht besser passen würde, dich aus der Ich-Perspektive zu präsentieren. Es schafft jedenfalls eher eine Bindung zum Leser.
  • Die Follow-zigapiano-on-Seite würde ich vermutlich löschen. Im Footer würde ich die Icons für die Social Links nutzen, jedoch in der Breite deutlich gestaucht. Die Icons auf der Stage würde ich des Weiteren entfernen, denn sie passen dort inhaltlich nicht wirklich hin.
  • Die Boxen auf Listen-to-zigapiano sehen ehrlich gesagt grausam aus. Sie wirken wie lieblos eingefügte Fremdkörper. Der Button ist unverständlicherweise immer wieder anders positioniert, obwohl sich die Höhe der Boxen eigentlich nicht ändert und die generelle Anordnung ist ungünstig, denn sie zwingt den Nutzer zum Scrollen, obwohl der Inhalt selbst auf den ersten Viewport passen würde. Als allgemeine Maßnahme würde ich die Links zu einer zusammenhängenden vertikalen Liste zusammenfassen, evt. in einer horizontal zentrierten Box. Die 37 weiteren Musikplattformen... wären vielleicht trotzdem (in einer Aufzählung in einem Paragraph) erwähnenswert? Warum findet sich so eine Detailinformation nur im FAQ?
  • Die Teaser auf Releases sind in ihrer Form nicht einheitlich (unterschiedliche Bildgrößen und Bildeckvarianten, ungeordnete Texte und Buttons).
  • Die Recording-session-Seite ist in ihrem Stil eine der geordnesten Seiten. Allerdings sind die Textboxen unter den Bildern nicht auf gleicher vertikaler Linie, "Take a look at the Studio" ist entgegen der Erwartungshaltung kein CTA und der rote Pfeil davor wirkt wie ein Fragment, welches besser komplett entfernt werden sollte. Beim Übergang von der untersten Inhaltssektion zum Footer fehlt eine visuell trennende Kante, da beide Sektionen die gleiche Hintergrundfarbe verwenden.
  • Die Bildauswahl ist ab und an nicht optimal. Einige Bilder sind verpixelt (Bsp.: erstes Bild unter Home Session oder verzerrt - siehe Releases). Bei gleichen Inhaltselementen (s. Upcoming-releases) würde ich möglichst gleiche Bildschnitte verwenden.
  • In der Gallerie würde ich alle Fotos entfernen, die du schon auf anderen Unterseiten verwendest. Fotos, die sich nicht direkt auf dein Fokusthema (deine Musik) beziehen, würde ich vermutlich streichen oder in einen anderen Kontext setzen. Wenn deine Musik beispielsweise von einer Reise besonders inspiriert war, könnte man das entsprechend präsentieren. Wenn es dir wichtig ist, deinen Hund zu zeigen, würde ich das dennoch auf ein Bild reduzieren, welches ihn evt. im Studio zeigt und das dann unter die anderen Studiobilder mischen. So integrierst du Persönlichkeit, aber verlierst dennoch nicht den inhaltlichen Fokus. Das Chill-time-Foto würde ich entfernen, denn es erscheint qualitativ besser als alle anderen Bilder - ein merkwürdiger, ganz sicher ungewollter Kontrast.
  • Manchmal gibt es große leere Bereiche (z.B. am Footerende oder unter Orchester Recording) und einige Abstände zwischen Sektionen könnten stärker reduziert werden. Auf Upcoming-releases würde ich den Abstand zwischen Songname und Bild etwas vergrößern.
  • Einige Menüpunkte beginnen mit einem Kleinbuchstaben.
  • Auf Upcoming-music-projects ist am Ende der ersten Sektion aufgrund eines fehlenden Stylings ein kompletter Satzteil nicht sichtbar.
  • Denn Sinn des FAQ würde ich deutlich hinterfragen. Die meisten Fragen beantwortest du bereits auf deinen Unterseiten. In gewisser Weise nimmst du so den Anreiz, überhaupt auf eine der Detailseiten zu gehen.
  • Schöner wäre es, Songs direkt über einen Musikplayer einzubinden, statt auf eine externe Seite zu verweisen. So wird ein Nutzer nicht von deiner Seite weggeleitet. Spotify bietet Embeds an.
  • Die Kontaktformulare würde ich zu einem Formular zusammenführen. Eine Auswahlbox kann dazu dienen, den Zweck auszuwählen.
  • Die Platzhaltertexte deiner Formularfelder sollten sich farblich stärker vom Hintergrund abheben. Im Grunde könntest du sie aber auch gleich entfernen, denn sie bieten keinen Mehrwert. Platzhalter sind eigentlich dazu da, zu verdeutlichen, welcher Typ an Eingabe bzw. welches Format erwartet wird (z.B. mittels eines Beispielswerts). Die Feldbeschriftung übernimmt das Label.
  • I agree to the Privacy Policy*: Ich würde den Text als Label für die Checkbox wählen. Zu dem Sternchen gibt es übrigens keine Fußnote.
  • Den E-Mail-Link unter deinem Formular kann man nicht selektieren oder anklicken. Zudem zeigt er auf ein falsches Ziel https://). Verwende eine mailto-Adresse.
  • Der Footer ist zu sehr durch Links aufgebläht, die bereits in der oberen Navigation vorhanden sind. Das macht bei Seiten mit so wenig Scrollfläche keinen Sinn. Bezüglich der Textmarke würde ich zum einen hinterfragen, ob es sie braucht (der Name wird im Header und auf der Stage erwähnt) und wieso sie dort in Großbuchstaben geschrieben wird. Gerade bei Künstlernamen ist es doch besser, Klarheit zu haben, welche Schreibweise denn nun richtig ist.
  • Der Legal-Notice-Link im Footer verweist auf /impressum (Deutsch). Richtig wäre /legal-notice.
  • Zum Impressum: Schau dir die unteren Paragraphen an. Der Text startet oftmals auf der falschen Zeile.

Ein paar zusätzliche rechtliche Hinweise:

  • Dein Hinweis über Google Fonts auf Privacy-Policy ist ungenügend, denn ich habe keine Möglichkeit, diesem Tracking zu widersprechen. Wenn ich mir die aktuelle Lage aber anschaue, werden die Schriftdateien stattdessen über cdn.zyrosite.com eingebunden.
  • Es macht keinen guten Eindruck, wenn ich direkt sehe, dass deine Legal-Texte mit Copilot zusammengebaut wurden.

Auf Ebene der technischen Umsetzung sieht es leider auch nicht gut aus. Das HTML ist voller Fehler (z.B. falsche Verschachtelungen, invalide/fehlende Attribute und Attributwerte), wie bereits oben angesprochen, werden einige Elemente zweckentfremdet, die Texthierarchie ist falsch und das DOM ist überhäuft mit Inline-Styles und leeren Kommentaren. Da du offensichtlich Zyro nutzt, hast du darauf sicherlich nur begrenzt Einfluss. Prüfe zumindest überall, wo du selbst HTML eingefügt hast, ob es valid ist.

Für Textunterstreichungen wäre CSS vorzuziehen:

<span style="text-decoration:underline">Some text</span>

Das u-Element dient für Fälle, in denen du bspw. einen Eigennamen oder ein Fremdwort in einem Text besonders kennzeichnen möchtest.

Bei deinen Bildern wäre außerdem zu prüfen, in welcher Form du sie einsetzt und ob sie dementsprechend eine Bildbeschreibung (alt/Alternative Text) brauchen. Grundsätzlich gilt: Wenn das Bild aktiv zum Inhalt beiträgt (also nicht dekorativ ist), braucht es einen Alternativtext. Das wäre zum Beispiel bei all deinen Bildern aus der Gallerie der Fall. Der Alternativtext sollte kurz, prägnant beschreiben, was auf dem Bild zu sehen ist. Zum einen wird er angezeigt, sollte das Bild beim Nutzer aus irgendeinem Grund nicht geladen werden und zum anderen wird er von Screenreadern (Hilfsmittel für Menschen mit Sehschwäche, Blindheit) erfasst.

...zur Antwort

Wenn du grundsätzliche Verständnisschwierigkeiten bei den von dir aufgezählten Themen hast, wäre es wohl gut, wenn du dir zuallererst entsprechende Wissensquellen suchst, mit denen du all das aufarbeitest. Das können Bücher sein, Lernkurse (z.B. von Hyperskill/JetBrains Academy, RealPython, Udemy, Codecademy), natürlich die vom Dozenten zur Verfügung gestellten Materialien oder du schaust in deinem Umfeld: Im Studium sollte es nicht schwerfallen, Lerngruppen zu bilden oder Unterstützung/Nachhilfe von Kommilitonen zu erhalten. Zum Teil hängt es natürlich von deinem Lerntypus ab, doch generell bewährt sich auch oft ein Mix.

Bei konkreten Fragen (oder meinetwegen einer Frageliste für konkrete Probleme) kannst du definitiv auch Gutefrage als Plattform nutzen.

Bezüglich der Praxisübung: Ich denke, du kannst mehrere dieser Themen ziemlich gut miteinander verbinden.

Beispiel:

  1. Überlege dir ein Softwareprojekt (Konsolenprogramm), in dem es darum geht, mehrere Daten kategorisch zu verwalten (hinzufügen, lesen, bearbeiten, entfernen). Das könnte eine Liste an Filmen sein (unterteilt nach Genre, Jahr, o.ä.), die du noch unbedingt sehen möchtest oder ein Kontaktbuch. Als Schnittstelle, um von außen mit dem Programm zu kommunizieren, nutzt du Konsolenargumente und die Daten werden in einer Datei gespeichert. Überlege dir dazu ein Speicherformat (CSV, INI, JSON, ...).
  2. Zerlege deine Aufgabe in die klassischen Phasen der Softwareentwicklung (Planung, Implementation, Testphase) und gehe die so auch strikt durch. Das heißt, du stellst im ersten Schritt die Anforderungen zusammen, baust dir UML-Diagramme, Programmablaufpläne, etc.., die in der Implementationsphase absolute Grundlage für deinen Programmcode sind. Spätestens im letzten Abschnitt testest du mit verschiedenen Testverfahren, ob sich deine Anwendung entsprechend verhält.
  3. Für die Speicherung der Daten wählst du eine Datenstruktur (wie Dictionary, Set, Stack, Tree, einfach/doppelt verkettete Liste, Queue, Graph). Egal worauf deine Wahl fällt, später solltest du diese Struktur auch nochmal gegen andere austauschen, einfach, um sich mit mehreren beschäftigt zu haben. Von besonderem Interesse dabei ist, inwiefern sich diese Strukturen im Verhalten unterscheiden. Zudem liegen einige von den genannten nicht in der Standardbibliothek vor, also müsstest du sie selbst implementieren. Das ist eine gute zusätzliche Übung, Algorithmen zu bauen.
  4. Für das Lesen der Daten würde ich zwei Funktionen unterscheiden: Einmal das Lesen eines bestimmten Eintrags und einmal das Lesen aller Einträge. Letztere Fall sollte ausschließlich durch Iteration/Rekursion erfolgen.
  5. Als zusätzliche Anforderung nimmst du auf, die Daten unterschiedlich sortiert ausgeben zu können (alphabetisch aufwärts/abwärts, sortiert nach ihrer Kategorie, ...). Für jede Art Sortierung implementierst du eine eigene Methode, die ein jeweils anderes Sortierverfahren nutzt. Sei es Bubblesort, Quicksort, Insertionsort, o.a.. Wichtig an der Stelle ist, zu verstehen, wie sie funktionieren, um ihre Vor-/Nachteile zu erfassen.
  6. Wenn du auf Probleme stößt (z.B. deine Items falsch sortiert werden), nutze als erstes Hilfsmittel den Debugger einer IDE (Pythons IDLE, PyCharm, Thonny, ...), statt Konsolenausgaben.

Die Übungsaufgaben, die dir vorliegen, würde ich an deiner Stelle natürlich ebenfalls praktisch durchgehen. Wichtig wäre dabei, dass du nicht direkt auf die Lösungen schaust, sondern versuchst, eigene Lösungswege zu finden. Das kann auch etwas dauern, gerade für den Anfang ist das Bilden von Programmalgorithmen nicht leicht. Mache so etwas definitiv nicht mit geöffnetem Code-Editor vor der Nase. Bau dir immer erst einen Ablaufplan (Programmablaufplan, Struktogram, Skizze, Pseudocode, o.ä.). Mehr zum Erstellen von Algorithmen habe ich schon einmal hier geschrieben.

Mache dir im Übrigen einen Lernplan, mit dem du sicherstellen kannst, regelmäßig zu üben. Es genügen sicherlich schon kleine Aufgaben oder du bastelst dir ähnliche Fälle wie bei meinem Beispiel zusammen.

Einige Übungsaufgaben für Anfänger kannst du online beispielsweise auf CodingBat, Edabit, Exercism oder w3resource finden.

...zur Antwort

Eines möchte ich voranstellen: Screenreader sind Tools, die Blinden und Sehbehinderten eine alternative Möglichkeit bietet, mit einer Benutzeroberfläche interagieren zu können. SEO hat damit nichts zutun. Dennoch denke ich, aufgrund deiner Beschreibung, dass es dir eigentlich nur um den Einbau versteckter Texte für SEO geht und du von den Crawlern von Suchmaschinen redest. Ein Umbau einer Webseite, sodass sie die gängigen Kriterien für Barrierefreiheit erfüllt, wäre etwas komplexer, als nur an ein paar Stellen unsichtbare Texte einzufügen.

Bei WordPress würde ich für eine SEO-Optimierung wohl zuerst ein Plugin wie Yoast SEO oder Rank Math einsetzen und abseits davon mich natürlich auf gut strukturierte, sichtbare Inhalte fokussieren. Versteckte Texte, auf die normale Nutzer nicht zugreifen können, werden von Suchmaschinen potentiell eher abgewertet.

Wenn du dennoch unsichtbare Texte einbinden möchtest, kannst du das Code-Modul verwenden, um deine Inhalte in Form von HTML einzufügen.

<p aria-hidden="true" class="visually-hidden">My hidden text.</p>

Das aria-hidden-Attribut verhindert, dass der Text von Screenreadern gelesen wird (Blinde/Sehbehinderte sollten von diesen Texten ja nicht die Zielgruppe sein), die Klasse wird im Folgeschritt in CSS definiert. Gehe dazu unter Divi > Theme Options > Custom CSS.

.visually-hidden {
  border: 0;
  clip: rect(0, 0, 0, 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}
...zur Antwort
Wie löscht man doppelte Zeilen in Excel mit C#?

Bei der täglichen Datenverarbeitung muss man häufig doppelte Zeilen in Excel-Tabellen entfernen. Ich möchte diese Funktionalität in einem kleinen Tool umsetzen. Die Datenmenge ist nicht riesig, aber der Code sollte möglichst einfach sein und keine Office-Installation voraussetzen.

Ich habe eine Lösung mit Free Spire.XLS gefunden (kostenlose Version, kein Office nötig). Hier ist mein Testcode, der anhand der ersten Spalte (Spalte A) doppelte Zeilen erkennt und nur das erste Vorkommen behält:

using Spire.Xls;
using System.Linq;

namespace RemoveDuplicateRows
{
    class Program
    {
        static void Main(string[] args)
        {
            Workbook workbook = new Workbook();
            workbook.LoadFromFile("Test.xlsx");

            Worksheet sheet = workbook.Worksheets[0];
            var range = sheet.Range["A1:A" + sheet.LastRow];

            var duplicatedRows = range.Rows
                   .GroupBy(x => x.Columns[0].DisplayedText)
                   .Where(x => x.Count() > 1)
                   .SelectMany(x => x.Skip(1))
                   .Select(x => x.Columns[0].Row)
                   .ToList();

            for (int i = 0; i < duplicatedRows.Count; i++)
            {
                sheet.DeleteRow(duplicatedRows[i] - i);
            }

            workbook.SaveToFile("RemoveDuplicateRows.xlsx");
        }
    }
}

Dieser Code funktioniert, aber ich würde gerne von erfahrenen Entwicklern wissen:

  • Welche Bibliotheken könnt ihr sonst empfehlen? Zum Beispiel EPPlus, ClosedXML, oder direkt mit OLEDB auslesen, die Duplikate entfernen und zurückschreiben?
  • Wenn die Datenmenge etwas größer ist (mehrere zehntausend Zeilen), gibt es leistungsmäßig etwas zu beachten?
  • Gibt es vollständig quelloffene und leichtgewichtige Alternativen, um die Einschränkungen der kostenlosen Version einer kommerziellen Bibliothek zu umgehen?

Ich bin für jeden Vorschlag oder jedes Codebeispiel sehr dankbar!

...zum Beitrag
Welche Bibliotheken könnt ihr sonst empfehlen? Zum Beispiel EPPlus, ClosedXML, oder direkt mit OLEDB auslesen, die Duplikate entfernen und zurückschreiben?

Ich würde zwischen ClosedXML, EPPlus oder NPOI tendieren. Alle drei Bibliotheken sind grundsätzlich erst einmal kostenlos und nicht schwer zu bedienen. EPPlus dürfte bei der Bearbeitung großer Dateien (~ hundertausend Zeilen und mehr) schneller/effizienter als die anderen agieren. Du solltest allerdings bedenken, dass die Bibliothek ab Version 5 nicht mehr frei für eine kommerzielle Nutzung ist. Auch für NPOI wurde in der Hinsicht inzwischen ein Bezahlmodell eingeführt.

Wenn die Datenmenge etwas größer ist (mehrere zehntausend Zeilen), gibt es leistungsmäßig etwas zu beachten?

Bei diesen Datenmengen eher nicht.

Was du gegenüber deinem aktuellen Ansatz allerdings besser machen könntest, wäre es, auf Löschoperationen zu verzichten (da du dir somit auch das Verschieben von Zeilen sparst) und stattdessen einfach nur die Zeilen, die du brauchst, in ein neues Worksheet zu kopieren. Den Gesamtwert, der für die Duplikatprüfung relevant ist, kannst du in ein Set ablegen. Wenn dieses Set den Wert bereits beinhaltet, weißt du, ob die aktuelle Zeile übersprungen werden muss oder nicht.

Wenn du die Daten mit CSV abbilden kannst, könntest du die Daten ebenso erst in dieses Format exportieren, dann deine Löschoperation durchführen und die Daten im Anschluss neu importieren. Dann bräuchtest du keine extra Excel-Bibliothek, die reine Textverarbeitung läuft schneller. Den Weg würde ich allerdings nur in Erwägung ziehen, wenn du tatsächlich auf Performanceprobleme stößt.

Gibt es vollständig quelloffene und leichtgewichtige Alternativen, um die Einschränkungen der kostenlosen Version einer kommerziellen Bibliothek zu umgehen?

Für deinen genannten Anwendungsfall sind die oben genannten Optionen ausreichend. Ansonsten wäre erst einmal fraglich, welche konkreten Features du noch erwartest, aber aktuell nicht abdecken kannst.

...zur Antwort
Warum lädt Firefox devtools im Wasserfall das Headerbild zwei Mal?

Mein headerbild hat ein komplexes <picture> mit mehreren sources/Media Queries und wird analog dazu für die verschiedenen Viewports im head preloaded. Die Codes sollten stimmen (habe ich hier bei GF vorgestellt).

Im Chrome devtools wird je nach Viewport und DPR das korrekte Bild ausgewählt und erscheint als preload auch ganz oben im Wasserfall.

Die FF devtools allerdings laden zwei Headerbilder. Zum einen das korrekte, das aber weit unten im Wasserfall, mit Priority low, erscheint. Und oben im Wasserfall, als preload, eine falsche Version und zwar immer das große desktop-default-Bild (desktop-first). Es hat als Initiator "lazy-imageset", obwohl ich nichts mit lazy mache. Der Ladevorgang ist auch tatsächlich schlecht, da das Bild lange Zeit einen leeren Platz belegt.

Laut Google ist das Verhalten von FF bekannt:

The scenario where two images load instead of one is a common issue when combining <link rel="preload"> with complex responsive image (<picture> or srcset) logic.

Preload vs. Picture Evaluation Conflict: The preload scanner in the browser head often runs before the browser has finalized the viewport dimensions. If a <link rel="preload" media="..."> tag has a query that doesn't perfectly match the final computed <source media="..."> in the <picture> tag, the browser will preload one image, realize it's wrong, and download the correct one later.

Ich vermute, das geschieht auch bei mir? Ich habe schon ein paar Sachen probiert, um einen möglichst "perfectly match" zu erreichen, aber leider ohne Erfolg. Zum Beispiel das scr im picture-img gelöscht oder dessen Bild testweise in eines der sources angelegt. Außerdem media="(min-width: 961px)" im untersten preload tag für das default img gelöscht (existiert ja nicht im picture-img).

<picture> 
<source media="(max-width: 429px)" srcset="430x172-1x.jpg 1x, 860x344-2x.jpg 2x" width="430" height="172">
<source media="(min-width: 430px) and (max-width: 499px)" srcset="500x200-1x.jpg 1x, 1000x400-2x.webp 2x" width="500" height="200">
<source media="(min-width: 500px) and (max-width: 670px)" srcset="670x268-1x.jpg 1x, 1340x536-2x.webp 2x" width="670" height="268">
<source media="(min-width: 671px) and (max-width: 829px)" srcset="930x372schmal-1x.webp 1x, 1395x558-15x.webp 1.5x" width="930" height="372">
<source media="(min-width: 830px) and (max-width: 960px)" srcset="930x372schmal-1x.webp 1x, 1395x558-15x.webp 1.5x" width="930" height="372">
<img class="..." src="930x300breit-1x.webp" srcset="930x300breit-1x.webp 1x, 1860x600breit-2x.webp 2x" width="930" height="300" alt="...">
</picture>
<link rel="preload" as="image" fetchpriority="high" media="(max-width: 429px)" imagesrcset="430x172-1x.jpg 1x, 860x344-2x.jpg 2x">
  <link rel="preload" as="image" fetchpriority="high" media="(min-width: 430px) and (max-width: 499px)" imagesrcset="500x200-1x.jpg 1x, 1000x400-2x.webp 2x">
  <link rel="preload" as="image" fetchpriority="high" media="(min-width: 500px) and (max-width: 670px)" imagesrcset="670x268-1x.jpg 1x, 1340x536-2x.webp 2x">
  <link rel="preload" as="image" fetchpriority="high" media="(min-width: 671px) and (max-width: 829px)" imagesrcset="930x372schmal-1x.webp 1x, 1395x558-15x.webp 1.5x">
  <link rel="preload" as="image" fetchpriority="high" media="(min-width: 830px) and (max-width: 960px)" imagesrcset="930x372schmal-1x.webp 1x, 1395x558-15x.webp 1.5x">
  <!-- default-img desktop, desktop-first  -->
  <link rel="preload" as="image" fetchpriority="high" imagesrcset="930x300breit-1x.webp 1x, 1860x600breit-2x.webp 2x">

...zum Beitrag

Dein letzter link-Tag hat kein media-Attribut, was das Verhalten erklärt, welches auf dem Screenshot zu sehen ist. Der Browser lädt in jedem Fall einen Kandidaten aus dem Sourceset vor, das wird ja explizit gefordert. Dem Tag solltest du also einen Media Query zuordnen, der das verhindert.

Wenn das Problem dann immer noch auftritt, könnte es tatsächlich sein, dass der speculative parser von Firefox sich zu früh dazu entscheidet, ein Bild vorzuladen. Es kann sein, dass zu dem Zeitpunkt, wo er auf den Preload stößt, noch nicht alle Informationen vorliegen, die er eigentlich bräuchte.

Ich würde den Preload spätestens in dem Fall dann auch entfernen. Wenn er dir nichts bringt, bzw. negativ ausschlägt, ist es nicht sinnvoll, ihn weiter einsetzen zu wollen. Stattdessen könntest du schauen, ob ein fetchpriority-Attribut auf deinem img-Element etwas bringt.

...zur Antwort
Was ist in diesem Code der Fehler?
import { world, system } from "@minecraft/server";
import { ActionFormData, ModalFormData } from "@minecraft/server-ui";

world.beforeEvents.itemUse.subscribe(data => {
  let player = data.source
  let title = "§6§lVillages and cities"
  if (data.itemStack.typeId == "minecraft:compass") system.run (() => main(player))
    //Main Menu
    function main() {
      const form = new ActionFormData()
      .title(title)
      .body (`Welcome ${player.nameTag}!`)
      .button(`§6§lCreate village\n §r[ Make sure you already built the village before founding it here ]`)
      .button(`§a§lJoin village or city`)
    form.show(player).then(r => {
      if (r.selection == 0) CreateVillage(player)
      if (r.selection == 1) JoinVillageOrCity(player)
    })
  } 

  //Create Village
  function CreateVillage() {
    new ActionFormData()
    .title("Create a village")
    .button(`§a§lCreate`)
    .button(`§4§lBack`)
    .show(player).then(r => {
      if (r.selection == 0) {
        world.sendMessage("§6Village of ... was officially founded by ...")
        player.runCommandAsync("tag @s add leader")
      }
    })
  }
})

Das ist der Code den ich habe für eine GUI in Minecraft Bedrock. Mir wird ständig die Fehlermeldung "[Scripting][error]-[Ino faction GUI BP] Unhandled promise rejection: TypeError: not a function  at <anonymous> (gui/index.js:32)" ausgespuckt. Die funktion player.runCommandAsync wird also nicht ausgeführt. Was ist da der fehler?

...zum Beitrag

Nur auf deinen Code bezogen sehe ich nicht, wo JoinVillageOrCity definiert wird.

...zur Antwort
Ist der <picture>-Code korrekt und die dazugehörigen preload tags?

Hallo,

meine responsive Website hat fünf media queries ("desktop-first") und der <picture>-Code für mein Headerbild ist recht komplex geworden, da jedes media query seine eigene Headerbildgröße hat und zusätzlich ein höher aufgelöstes Bild (1.5x oder 2x).

Außerdem soll auch im default <img> ein zweites, höher aufgelöstes Bild ("x") angeboten werden. Das Bild dort ist das desktop-Bild (desktop-first). Dieses hat ein anderes Seitenverhältnis (3.1) als die Bilder in den media queries (2.5), deshalb dort width/height überall.

Ist der folgende picture-Code korrekt, insbesondere das default-img und die Reihenfolge der sources? Dass das Bild für die beiden großen MQ dasselbe ist, ist Absicht und auch die drei expliziten MQ(min- und max-width-Bedingung gemeinsam).

<picture> 
      <source media="(max-width: 26.8125em)" srcset="bild-430x172-1x.jpg 1x, bild-860x344-2x.jpg 2x" width="430" height="172">
      <source media="(max-width: 31.1875em)" srcset="bild-500x200-1x.jpg 1x, bild-1000x400-2x.webp 2x" width="500" height="250">
      <source media="(min-width: 31.25em) and (max-width: 41.875em)" srcset="bild-670x268-1x.jpg 1x, bild-1340x536-2x.webp 2x" width="670" height="268">
      <source media="(min-width: 41.9375em) and (max-width: 51.8125em)" srcset="bild-930x372schmal-1x.webp 1x, bild-1395x558-15x.webp 1.5x" width="930" height="372">
      <source media="(min-width: 51.875em) and (max-width: 60em)" srcset="bild-930x372schmal-1x.webp 1x, bild-1395x558-15x.webp 1.5x" width="930" height="372">
      <img class="headergrafik" src="./grafiken/headerbild-930x300breit-1x.webp" srcset="./grafiken/headerbild-930x300breit-1x.webp 1x, ./grafiken/headerbild-1860x600breit-2x.webp 2x" width="930" height="300" alt="...">
</picture>

Wenn das soweit passen sollte, stellt sich die Frage, wie genau die preload tags für dieses headerbild im picture aussehen müssen. Ich habe es mal nachfolgend probiert. Stimmt das so, vor allem der letzte tag für das default desktop-Bild?

<link rel="preload" as="image" fetchpriority="high" media="(max-width: 26.8125em)" imagesrcset="bild-430x172-1x.jpg 1x, bild-860x344-2x.jpg 2x">
<link rel="preload" as="image" fetchpriority="high" media="(max-width: 31.1875em)" imagesrcset="bild-500x200-1x.jpg 1x, bild-1000x400-2x.webp 2x">
<link rel="preload" as="image" fetchpriority="high" media="(min-width: 31.25em) and (max-width: 41.875em)" imagesrcset="bild-670x268-1x.jpg 1x, bild-1340x536-2x.webp 2x">
<link rel="preload" as="image" fetchpriority="high" media="(min-width: 41.9375em) and (max-width: 51.8125em)" imagesrcset="bild-930x372schmal-1x.webp 1x, bild-1395x558-15x.webp 1.5x">
<link rel="preload" as="image" fetchpriority="high" media="(min-width: 51.875em) and (max-width: 60em)" imagesrcset="bild-930x372schmal-1x.webp 1x, bild-1395x558-15x.webp 1.5x">
<!-- Für das default-img bzw. desktop-Bild bei desktop-first  -->
<link rel="preload" as="image" fetchpriority="high" media="(min-width: 60.0625em)" imagesrcset="bild-930x300breit-1x.webp 1x, bild-1860x600breit-2x.webp 2x">
...zum Beitrag

Vorweg: Praktisch musst du es selbst prüfen und ob die Bildgrößen so für deinen Fall passend sind, weißt natürlich auch nur du allein.

1) Du arbeitest mit konkreten Bilddimensionen, der Browser entscheidet auf Basis der Viewportbreite. Daher würde ich bei den Media Queries auch mit Pixelangaben statt em arbeiten. Es ist einfacher bei der Definition und der Wartung. Aktuell könnte man beispielsweise beim ersten Lesen annehmen, dass zwischen deinen Breakpoints ungeschlossene Minilücken liegen, was sich erst bei Umrechnung in Pixelwerte entkräftet.

2) Der Wert von height bei deinem zweiten source-Element ist falsch. Statt 250 wäre 200 richtig.

3) Die beiden letzten source-Elemente sowie die beiden dazugehörigen link-Elemente kann man jeweils zu einem zusammenfassen, denn die Bildquellen unterscheiden sich nicht.

4) Ich würde die Breakpoints so anpassen, dass sie immer konsistent auf ganze Pixelgrenzen enden. Das macht es wieder leichter les- und wartbar. Der letzte Breakpoint müsste demzufolge bei 959px enden, das Standardbild kann bei >= 960px ins Spiel kommen.

...zur Antwort

Erstell dir ein Template. Zusätzlich brauchst du Custom Fields, über die du deine dynamischen Daten (Link URL, Image URL, etc.) je Beitrag setzen kannst. An der Stelle würde ich dir ein Plugin wie ACF empfehlen, das extra Feldtypen für Link oder Dateiselektion mit sich bringt.

PS.: Das center-Element gehört nicht zum HTML5-Standard. Du kannst es leicht via CSS (margin: 0 auto oder Flexbox/Grid) ersetzen.

...zur Antwort

Eine erste Eingrenzung kannst du auf technischer Ebene vornehmen. Für den Fall, dass bereits ein Webhost festgelegt ist, kommen nur CMS infrage, die mit diesem Setup kompatibel sind. Ebenso spielt dein Know-how eine Rolle: Einem PHP-Entwickler würde ich beispielsweise eher ein CMS empfehlen, das auch auf PHP basiert. Vor allem, da du ja selbst schreibst, dass ein schneller Einstieg für dich wichtig ist.

Ein paar bekannte CMS-Optionen wären Drupal, Sanity, Strapi oder WordPress.

Einen stärkeren Einfluss auf SEO und Performance könntest du erlangen, indem du die CMS nur als Datenspeicher/Content-API (headless) nutzt. Das Frontend würde ich in dem Fall mit NextJS, Nuxt oder SvelteKit umsetzen.

Wenn du nicht headless arbeiten möchtest, bleibt dir bei klassischen CMS (wie WordPress) normalerweise der Weg über Templates oder Themes. Dieser ist insbesondere für den Einstieg in der Regel einfacher, führt aber durch die stärkere Kopplung zwischen Frontend, Logik und CMS zu gewissen Einschränkungen (beispielsweise der Performance-Optimierung).

Letztlich läuft die Entscheidung darauf hinaus, was dir wichtiger ist: Maximale Kontrolle oder ein möglichst schneller Einstieg.

...zur Antwort

Zum einen würde ich je Bild und dessen Zweck entscheiden, welche und wie viele Varianten angeboten werden. Bei Produktbildern (z.B. für Kleidung, Möbel, Fotografien) auf Verkaufsplattformen beispielsweise macht es eher Sinn, besonders auf die Bildqualität zu achten. Großflächige Bilder, die stärker im Fokus stehen (z.B. Headerbilder) würde ich ebenso besonders behandeln, da bei ihnen Artefakte schneller auffallen.

Wenn du die Möglichkeit hast, wäre es sinnvoll, auf einem großen Bildschirm gegenzutesten, wie stark der Qualitätsunterschied im Vergleich zu kleineren Displays tatsächlich ist. Nimm da ruhig die Faktorabstufungen 1.5 und 2.

Selbst bei einfachen/kleinen Inhaltsbildern würde ich einmal schauen, wie groß der Mehrwert zwischen den verschiedenen Faktoren ausfällt. Immerhin sammeln sich so schnell Datenmengen, die auf die Performance gehen. Nutze auf jeden Fall moderne Bildformate (WebP, AVIF) mit sinnvoll gewählter Kompression (für WebP ~70-85%, für AVIF deutlich niedriger).

Bedenke zudem, dass Nutzer bei einem größeren Bildschirm tendentiell weiter entfernt vom Monitor sitzen, als bei kleineren Bildschirmen, wodurch Unterschiede oft weniger stark wahrgenommen werden.

Zum anderen könntest du mit einem Trackingtool prinzipiell einmal eine Analysephase starten, in der du ermittelst, welche Bildschirmgrößen, Viewportbreiten und Pixeldichten (DPR) von deinen Nutzern so verwendet werden und inwiefern es sich lohnt, 4k-Monitore u.ä. überhaupt zu berücksichtigen.

...zur Antwort
Java weitermachen oder auf Webentwicklung wechseln?

Hi, ich lerne aktuell Java mit einem Grundkurs-Buch und bin etwa zu zwei Dritteln durch (gerade bei Konstruktoren).

Zusätzlich habe ich schon einen Python-Grundkurs gemacht, aber noch wenig praktische Erfahrung – bisher ca. 10+ eigene, eher kleine Projekte. Mein Ziel ist es, später einen Job als Entwickler zu finden.

Jetzt überlege ich:

Soll ich erst einmal bei Java bleiben und danach Frameworks wie Spring Boot lernen, um in Richtung Backend zu gehen?

Oder wäre es sinnvoller, nach Ende des Java-Kurses auf Webentwicklung umzusteigen (HTML, CSS, JavaScript), um schneller eigene visuelle Projekte bzw. Websites zu bauen und eventuell leichter in einen Job zu kommen?

Meine Motivation ist aktuell ziemlich hoch, weil ich Webentwicklung spannend finde – besonders, weil man schnell sichtbare Ergebnisse bekommt und eigene kleine Websites bauen kann.

Außerdem habe ich den Eindruck (korrigiert mich gern), dass es im Webbereich eine größere Auswahl an Einstiegsjobs gibt.

Ich merke auch, dass ich eher kreativ als rein logisch lerne.

Java ist zwar eine gute Herausforderung deswegen für mich, aber teilweise stoße ich an meine Grenzen. Einfach weil gefühlt ich oft länger brauche für Grundkonzepte wie anderen eher technisch/logischen lernern.

Deshalb frage ich mich, ob mir Webentwicklung vielleicht mehr liegen könnte. Gleichzeitig habe ich etwas Angst, mich zu verzetteln und nichts wirklich richtig zu können.

Was sind eure Erfahrungen?

Was ist sinnvoller für den Einstieg in den Job?

Wie würdet ihr an meiner Stelle weitermachen? Danke euch!

Ps: ist web Entwicklung im übrigen schnell gelernt nach guten java Grundlagen + Projekten?

Ich weiß es sind ganz andere sprachen/Tools aber Logiken bleiben ja teils gleich?

...zum Beitrag
Oder wäre es sinnvoller, nach Ende des Java-Kurses auf Webentwicklung umzusteigen (...)

Es wäre sinnvoll, nach Ende des Kurses weitere Praxiserfahrung mit Java zu sammeln, um das, was du bisher gelernt hast, zu festigen. Ein einfaches Abrattern von irgendwelchen Kursen bringt dir doch eher wenig, wenn du das Gelernte nicht auch praktisch öfter angewandt hast, sodass du wirklich sicher darin bist.

(...) und danach Frameworks wie Spring Boot lernen (...)

Spring würde ich dementsprechend erst einmal noch etwas weiter nach hinten schieben.

Oder wäre es sinnvoller, nach Ende des Java-Kurses auf Webentwicklung umzusteigen (...)?

Java hat bereits einen starken Fokus auf Webentwicklung. Spring wird für viele Webanwendungen genutzt.

Du müsstest zwar nichtsdestotrotz HTML, CSS und JavaScript-Grundlagen lernen, doch das bedeutet nicht, dass Java in deinem Repertoire an Bedeutung verlieren müsste.

Außerdem habe ich den Eindruck (korrigiert mich gern), dass es im Webbereich eine größere Auswahl an Einstiegsjobs gibt.

Das gilt für die Softwareentwicklung generell. Vor allem bei mittel-/großen Projekten (oder Unternehmen) gibt es in der Regel eine Aufgabenteilung zwischen verschiedenen Rollen. Grob wären das Frontend- und Backendentwickler, Designer sowie Tester, doch diese Bereiche könnten noch weiter zergliedert werden.

Java ist zwar eine gute Herausforderung deswegen für mich, aber teilweise stoße ich an meine Grenzen. (...) Wie würdet ihr an meiner Stelle weitermachen?

An deiner Stelle würde ich eher hinterfragen, ob dir Programmierung (mit Java) nun eigentlich Spaß macht oder nicht und in welche Richtung (Web oder was auch immer) du nun überhaupt möchtest. Einen Grund, wieso du dich mit Python befasst hast, muss es doch ebenso gegeben haben. Wieso machst du damit nicht weiter?

Das es mühsam sein kann, Programmieren zu lernen, ist nun nichts besonderes. Wenn du es auf andere Bereiche überträgst, z.B. Klavierspielen lernen, würdest du ebenso auf Hürden stoßen, die viel Geduld und Übung erfordern. Es ist halt nichts, was du in ein paar Tagen/Wochen einfach einmal so aus dem Ärmel schüttelst. Ob nun mit oder ohne Lehrer.

Das Bilden von Algorithmen ist ein Kernbestandteil von Programmierung/Softwareentwicklung generell. Mit JavaScript würdest du ebenso auf eine Programmiersprache stoßen, die diese (und eigene) Hürden mit sich bringt.

Natürlich kannst du deinen Techstack oder das Anwendungsgebiet auch wechseln und stattdessen etwas anderes ausprobieren. Nur solltest du dann auch deinen Fokus darauf setzen, dich in den tatsächlich zu vertiefen.

Ps: ist web Entwicklung im übrigen schnell gelernt nach guten java Grundlagen + Projekten?

Wenn wir uns hierbei einmal auf HTML, CSS und JavaScript fokussieren: In HTML und CSS findet man sehr leicht einen Einstieg, etwas fordernder wird es erst im Detail. JavaScript wird ebenso erst komplexer, umso tiefer man gräbt. In seiner Syntax lehnt es nah an Java an und ja, du wirst auf einige Funktionalitäten/Konzepte stoßen (z.B. Kontrollstrukturen), die dir aus Java schon bekannt sind.

Das Wort schnell solltest du aber aus deiner Erwartungshaltung streichen, wie auch bei Java braucht es viel Praxisübung.

...zur Antwort

Nach aktueller Beobachtung hat YouTube diese Darstellungsform vorerst wohl eingestellt. Selbst wenn du bei einer via iFrame eingebetteten Videoserie/Playlist auf die YouTube-Schaltfläche klickst, bekommst du derzeit auf YouTube selbst die anderen Videos der Liste nicht sofort angezeigt, sondern musst auf der rechten Seite erst den Tab wechseln.

Ein verbleibender Lösungsweg wäre ein Eigenbau einer Seitenleiste mittels der YouTube Data API. Das heißt, du holst dir über diese API die relevanten Informationen zu den Videos deiner Playlist (Titel, URL, Thumbnail) und renderst sie dann selbst. Voraussetzung wäre natürlich, dass du technischen Zugriff auf deine Ziel-UI (Webseite oder wo auch immer die Liste eingebettet werden soll) besitzt.

Das könnte, sehr einfach gehalten, ungefähr so aussehen:

<article class="playlist-embed">
  <iframe allowfullscreen class="player" height="315" id="player" src="https://www.youtube.com/embed/videoseries?si=ABC&list=DEF" title="..." width="560"></iframe>
  <aside>
    <ul class="playlist" id="playlist"></ul>
  </aside>
</article>

CSS:

.playlist-embed {
  display: flex;
  gap: 20px;
}

.player {
  border: 0;
}

.playlist {
  display: flex;
  flex-direction: column;
  list-style-type: none;
  padding: 0;
  row-gap: 5px;
}

.playlist-item-cta {
  background: none;
  border: none;
  cursor: pointer;
  display: flex;
  flex-direction: column;
}

JavaScript:

const apiKey = "YOUR API KEY";
const playlistId = "YOUR PLAYLIST ID";

fetch(`https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=${playlistId}&key=${apiKey}`)
  .then(response => response.json())
  .then(data => {
    const playlist = document.getElementById("playlist");
    data.items.forEach(item => {
      if (!item.snippet || !item.snippet.resourceId) {
        return;
      }

      const videoId = item.snippet.resourceId.videoId;
      const title = item.snippet.title;
      const thumbnail = item.snippet.thumbnails.medium.url;

      const playlistItem = document.createElement("li");
      const playlistItemCta = document.createElement("button");
      playlistItemCta.type = "button";
      playlistItemCta.classList.add("playlist-item-cta");
      playlistItemCta.innerHTML = `<img alt="" height="180" src="${thumbnail}" width="320"><span>${title}</span>`;

      playlistItemCta.addEventListener("click", () => {
        const iframe = document.getElementById("player");
        iframe.src = `https://www.youtube.com/embed/${videoId}`;
        iframe.title = title;
      });
      playlistItem.appendChild(playlistItemCta);
      playlist.appendChild(playlistItem);
    });
  });

Es gibt also neben dem Video einen Container, der alle weiteren Videos auflistet. Bei Klick auf einen dieser Einträge wird dessen URL als Quelle für den iFrame gesetzt. Sollte die Liste mehr als 50 Einträge fassen, musst du mittels des Page Token weitere Seiten nachladen.

Damit das Ganze funktioniert, musst du dir einen API-Key holen und ihn entsprechend eintragen. Die ID deiner Playlist brauchst du natürlich auch, sie muss öffentlich zugänglich sein.

Eine deutlich bessere Implementation im Vergleich zu meinem Beispiel wäre eine, die serverseitig (über PHP/NodeJS/ASP.NET oder was auch immer deine Anwendung nutzt) läuft. Die Videoliste könnte früher gerendert und für serverseitiges Caching berücksichtigt werden und der API-Key bliebe verborgen.

...zur Antwort

Ein eingebauter Preload garantiert keinen Performanceschub. Im schlechtesten Fall kann er sich sogar negativ auswirken.

Zu deiner Schriftart:

1) Schau nach, wann die Schrift gebraucht wird. Von Anfang an oder erst irgendwo ab Mitte/Ende der Seite? In letzterem Fall macht es keinen Sinn, die Schrift frühzeitig zu laden.

2) Dein CSS muss die Schrift exakt einbinden, sodass der Preload verwendet wird.

@font-face {
  font-family: 'ThisNight';
  src: url('/wp-content/uploads/fonts/this-night.ttf') format('truetype');
  font-display: swap;
}

Die Anfrage aus dem CSS muss zu der vom Preload übereinstimmen. Andernfalls wird die Datei womöglich sogar zweimal geladen (einmal für den Preload, einmal für das CSS). Ob das der Fall ist, kannst du im Netzwerktab deiner Devtools prüfen (Seite neuladen und dann nach den Requests für die Schrift filtern).

Zudem solltest du das font-display-Property auf swap setzen. Das sorgt dafür, dass der Browser nicht unbedingt auf das Laden der Schrift wartet.

3) Statt TTF zu nutzen, wäre WOFF2 für das Web viel besser optimiert.

Zu deinem Bild:

1) Es gilt das Gleiche wie bei der Schrift. Zuerst muss bewertet werden, wie wichtig es für den Rendervorgang der Seite ist.

2) Bei einem Stage-/Herobild solltest du zusätzlich die Attribute fetchpriority und loading setzen, um nochmal stärker in den Ladeprozess einzugreifen.

Test: Wenn du bei Tests merkst, dass dir ein Preload keinen nennenswerten Vorteil einbringt, brauchst du ihn nicht. Er kann gerade in diesem Fall auch andersherum eine unnötige Belastung sein.

Zumal die Performancebremsen ganz woanders liegen können (z.B. bei einem langsamen Server oder anderen großen Ressourcen, die den Rendervorgang blockieren).

Sofern du das noch nicht gemacht hast, solltest du dich erst einmal auf andere Punkte fokussieren, die mehr Einfluss auf die Ladezeit nehmen können. Caching wäre hierbei ein Stichwort. Laut deinem Screenshot nutzt du das bisher noch gar nicht, dabei sollte das auf deiner Prioritätenliste ganz oben stehen. Ein CDN kann an der Stelle einen ziemlichen Vorteil liefern.

...zur Antwort
(...) ist es dann unweigerlich unscharf und/oder verpixelt?

Durch die notwendige Interpolation verliert es an Schärfe. Je nach Grafik/Motiv fällt das mehr oder weniger auf.

Denn offenbar müssen die durch mehr Hardware-Pixel zunächst verkleinerten Bilder per Software wieder gestreckt werden (...)

Nein, das Bild wird direkt auf eine größere Fläche gezeichnet, ohne es zuvor zu skalieren. Da dabei mehr Pixel benötigt werden, als das Bild ursprünglich hat, berechnet der Browser für die fehlenden Pixel anhand der umliegenden Pixel Zwischenwerte (Interpolation). So entstehen weichere Übergänge, sprich das Bild wird als unschärfer wahrgenommen.

Sehe ich das soweit richtig?

Ja. Dafür gibt es das srcset-Attribut (für img-/source-Elemente). Über das stellst du dem Browser weitere Bildvarianten in höherer Auflösung bereit, zwischen denen er dann selbst wählen kann.

Ändert das etwas?

Nein. Mit der gesetzten Maximalbreite verhinderst du ein visuelles Hochskalieren im Layout, aber auf die Umrechnung des Bildes je DPR (Gerätpixeldichte) hat es keinen Einfluss.

...zur Antwort

Ein Schwert müsste als ein Tool-Objekt erstellt werden.

https://www.youtube.com/watch?v=qacMw2usmiU

Zum Schwingen eines Schwerts kannst du diese Tutorialserie nutzen.

...zur Antwort

Zunächst würde ich an deiner Stelle gezielt nach Plugins oder vorhandenen Export/Import-Funktionalitäten bei den Systemen recherchieren, mit denen du arbeitest. Manchmal gibt es da sogar Migrationstools, die beides für dich erledigen.

Ansonsten würde ich abwägen: Zum einen kann das manuelle Neuanlegen schneller sein, als stundenlang nach Automatisierungen zu suchen oder Herumzuprobieren und zum anderen würde ich hinterfragen, ob die alte Inhaltsstruktur wirklich so beibehalten werden sollte (du redest immerhin davon, dass eine Verbesserung durchgeführt werden soll) und durch das neue System so abgebildet werden kann. Ich gehe hierbei davon aus, dass die neue Webseite durch ein CMS gesteuert wird, es geht mir in erster Linie also um die innere Datenstruktur.

AI-Tools (z.B. Claude, Gemini) eignen sich bei einer Migration sicherlich am besten als Hilfe, um deinen bestehenden Export zu transformieren. Vielleicht in ein Import-Format, was das Zielsystem mit Hilfe einer eigenen Schnittstelle verarbeiten kann oder in direkte SQL-Statements. Da müsstest du sicherlich im Vorfeld ein wenig testen, wie gut es funktioniert. Am besten teilst du so einen Prozess in mehrere Teilschritte (Strukturanalyse, Mapping, Transformation, Validierung) auf, da sich das besser prüfen und von einem AI-Tool stabiler verarbeiten lässt. Ein perfektes, fehlerfreies Ergebnis darfst du dabei allerdings nicht erwarten.

...zur Antwort

Unity hat eine eigene Lernplattform für Anfänger. Dort findet ihr Schritt-für-Schritt-Kurse, die an Unity heranführen. Der Startpunkt wäre der Lernpfad Unity Essentials.

Auf YouTube könntet ihr ebenso schauen. Dort gibt es zum Beispiel diese Playlist von den Boundfox Studios, die es sich zur Aufgabe gemacht haben, deutschsprachige Einstiegshilfe zu geben.

Sollte es auch mit diesen Videos Verständnisprobleme geben, müsstest du zusätzliche Recherche betreiben. Sammle all deine Unklarheiten ein und füttere damit dann eine Suchmaschine, ein Forum (du kannst hier auch Detailfragen zu C#/Unity stellen), einen AI-Bot oder suche in deinem Umfeld Hilfe (Mitschüler, Lehrer).

Einfache Spielideen:

  • Asteroids
  • Pong
  • Space Invaders
  • Snake
  • Pac-Man

Fokussiert euch von Anfang an nur auf die grundlegende Spielmechanik und belasst es bei einfachen Spielobjekten (Quader, Kugel, u.ä.). Wenn das soweit funktioniert, könnt ihr eure Spielwelt durch bessere Assets Stück für Stück aufhübschen.

...zur Antwort