Kiste
EN

Sternjäger

Ein Arcade-Weltraum-Shooter — Gegnerwellen, Power-ups, Effekte und eine Bestenliste. Rund 700 Zeilen Kiste in einer einzigen Datei, ohne Spiel-Engine.

Sternjäger im Spiel

Spiel herunterladen

Herunterladen, entpacken, starten — es läuft genau das, was du im Video siehst. Der vollständige Quelltext (sternjaeger.ki) liegt jedem Paket bei.

So gebaut

Sternjäger ist ein reines Kiste-Programm. Es nutzt nur die eingebauten Module gui (Fenster, Zeichnen, Tasten), klang (Töne und Musik), liste, zufall und datei — keine fremde Spiel-Engine. Hier sind die interessantesten Stellen.

1 · Der Spiel-Takt

Ein einziger Zeitgeber treibt alles an: 60 Mal pro Sekunde (alle 16 ms) bewegt sich die Welt und wird neu gezeichnet. Ein modus-Wert entscheidet, ob gerade das Menü, das Spiel, die Pause oder der Game-Over-Bildschirm läuft.

nimm uhr = gui.bei_zeit(16, funktion(t) {
    sterne_bewegen()
    partikel_bewegen()
    wenn flash > 0 { flash = flash - 1 }
    wenn modus == 1 { spiel_logik() }   // nur im Spiel rechnen
    zeichne()                           // aber immer neu zeichnen
})

2 · Alles sind parallele Listen

Statt Objekten führt Sternjäger für jede Eigenschaft eine eigene Liste — Gegner Nummer j hat seine Position in ex[j]/ey[j], seinen Typ in et[j] und so weiter. Das ist schlicht und schnell.

// Jede Gegner-Eigenschaft ist eine eigene, parallele Liste.
// Leere Listen mit liste.gefüllt(0, …) anlegen, damit der
// Compiler den Elementtyp kennt.
nimm ex = liste.gefüllt(0, 0)    // x-Position
nimm ey = liste.gefüllt(0, 0)    // y-Position
nimm et = liste.gefüllt(0, 0)    // Typ 0..4
nimm eh = liste.gefüllt(0, 0)    // Trefferpunkte
nimm ealive = liste.gefüllt(0, 0)

3 · Gegner mit eigenem Verhalten

Fünf Gegnertypen. Je länger du überlebst (je höher die welle), desto härtere Typen tauchen auf und werden häufiger.

// Mit steigender Welle kommen härtere Gegner dazu.
nimm r = zufall.ganz(0, 99)
nimm t = 0
wenn welle >= 4 und r < 6 + welle {
    t = 4                        // Panzer (ab Welle 5)
} sonstwenn welle >= 2 und r < 30 {
    t = 3                        // Verfolger (ab Welle 3)
} sonstwenn r < 22 + schwer {
    t = 2                        // Schütze
} sonstwenn r < 60 {
    t = 1                        // Zickzack
} sonst {
    t = 0                        // Drifter
}

Jeder Typ verhält sich anders. Der Verfolger etwa schaut in jedem Takt, wo der Spieler steht, und lenkt seitlich auf ihn zu:

// Typ 3 (Verfolger) steuert seitlich auf den Spieler zu
wenn t == 3 {
    wenn px > wert.als_ganz(ex[j]) { evx[j] = 2 } sonst { evx[j] = -2 }
}

4 · Sammelbare Items und Power-ups

Abgeschossene Gegner lassen manchmal ein Item fallen. Berührt dein Schiff es, greift sammle: die Bombe fegt den Bildschirm leer, das Schild macht dich kurz unverwundbar, der Doppelschuss lässt dein Schiff doppelt feuern. Power-ups sind einfach Zähler, die jeden Takt herunterlaufen.

funktion sammle(typ) {
    spiele_ton(power_s)
    wenn typ == 0 { zünde_bombe() }         // löscht alle sichtbaren Gegner
    sonstwenn typ == 1 { schild = 300 }     // ~5 s unverwundbar
    sonst { doppel = 480 }                  // ~8 s Doppelschuss
}

funktion spieler_getroffen() {
    wenn schild > 0 { gib }                 // Schild fängt den Treffer ab
    leben = leben - 1
    flash = 8
    wenn leben <= 0 { game_over() }
}

5 · Zeichnen mit Rechtecken und Kreisen

Es gibt keine Bilddateien für Schiff, Gegner oder Effekte — alles wird pro Bild aus gui.rechteck, gui.kreis und gui.text_an zusammengesetzt. Für sauber zentrierte Texte misst gui.text_breite die echte Pixelbreite.

// Echtes Zentrieren dank gui.text_breite (misst die Pixelbreite)
funktion text_mitte(cx, y, txt, farbe, groesse) {
    gui.text_an(bild, cx - gui.text_breite(txt, groesse) div 2, y, txt, farbe, groesse)
}

// Das Schiff — nur aus Rechtecken und einem Kreis
gui.rechteck(bild, px - 3, SPIELER_Y - 24, 6, 30, "#bae6fd")
gui.rechteck(bild, px - 18, SPIELER_Y + 2, 36, 8, "#38bdf8")
gui.kreis(bild, px, SPIELER_Y - 14, 4, "#e0f2fe")

6 · Menü, Logo und Beenden

Die Bestenliste wird als kleine Textdatei gespeichert und beim Start geladen. Ein eigenes Logo ersetzt das Standard-Icon, und „Beenden" schließt einfach das Hauptfenster.

// Eigenes Logo in Titel- und Taskleiste
gui.setze_app_icon("sternjaeger-logo.png")

// „Beenden" = das Hauptfenster schließen
funktion beende_spiel() {
    gui.fenster_schließe(fenster)
}

Das ist das ganze Rezept: ein Zeitgeber, ein paar Listen, Rechtecke und Kreise. Der komplette Quelltext liegt jedem Download oben bei — ändere die Gegner, erfinde neue Power-ups, bau dein eigenes Spiel daraus.