Zum Inhalt

Kollisionen und Textausgaben

Lernziele

  • Kollisionen
  • Textausgabe
  • Pixel-Kollisionen

Kollisionen

Als Nächstes wollen wir überprüfen, wann sich zwei Sprites überschneiden, sprich sich berühren.

Dazu machen wir ein erstes kleines Spiel. Wir benutzen dazu die Vorlage aus dem vorherigen Kapitel, d.h. zwei Spieler (die farbigen Räder player1 und player2) und eine Münze (coin).

Räder

Vorlage: Download HIER.

Die Spieler sollen die Münze einfangen. Wer sie zuerst berührt, der erhält einen Punkt. Eine neue Münze soll wiederum zufällige irgendwo auf dem Bildschirm auftauchen. Das Testen einer Berührung, sprich einer Kollision, muss natürlich in der Hauptschleife geschehen. Zwecks Übersichtlichkeit lagern wir diese Funktionalität, Kollision überprüfen, in eine Funktion aus und rufen die Funktion in der Hauptschleife dann auf.

Dazu erstellen wir im Block "Globale Funktionen definieren" eine Kollisions-Funktion check_collisions(). Das machen wir jetzt; führe dazu die folgenden Schritte aus:

  1. Erstelle eine neue Funktion mit dem Namen check_collisions() und sorge dafür, dass sie in der Hauptschleife aufgerufen wird.

  2. Es ist einer der vielen Vorteile von Sprites, dass man die Kollision von zwei Sprite-Objekten mit einem einzigen Befehl abfragen kann. Hier benutzen wir die Kollisionsabfrage py.sprite.collide_rect(player1,coin) == True , um zu überprüfen ob sich player1 und coin berühren bzw. player2 und coin. Wie der Name der Funktion collide_rect() bereits sagt, wird überprüft, ob sich die entsprechenden Rechtecke der betroffenen Sprites überlagern.

    Rect Kollision

    Benutze den Befehl collide_rect() in der check_collisions() Funktion und erstelle bei einer Berührung eine entsprechende Ausgabe auf der Konsole, z.B. "Kollision". Dies einfach mal, um es zu testen.

  3. Wenn player1 die Münze coin zuerst berührt, dann soll sich die Münze an einen beliebigen neuen Ort verschieben. Der Spieler erhält dann einen Punkt.

    Definiere dazu eine neue Eigenschaft in der Player()-Klasse, d.h. füge das Attribut self.points der Klasse hinzu. In diesem Attribut self.points werden einfach die Punkte des entsprechenden Players gespeichert.

  4. Wenn player2 aber die Münze coin zuerst berührt, dann wird selbstverständlich dessen Kontostand um eins erhöht.

  5. Bei einer Berührung soll zusätzlich der aktuelle Kontostand auf der Konsole mittels print Befehel ausgegeben werden. Dies könnte dann so aussehen:

    Rect Kollision

Textausgabe

Natürlich wäre es viel praktischer, wenn wir den Punktestand direkt auf dem Spielfenster ausgeben könnten, statt nur in der Konsole. Gehe dazu die folgenden Punkte der Reihe nach durch.

  1. Definiere dazu zuoberst beim Block "Pygames initialisieren" eine Schrift und ihre Grösse, die geladen werden soll:

    my_font = py.font.SysFont('Comic Sans MS', 36)
    

  2. Das Schreiben und darstellen des Punktestandes auf dem Bildschirm lagern wieder in eine neue Funktion draw_score() aus, damit die Hauptschleife übersichtlich bleibt. Erstelle eine solche Funktion.

  3. Erstelle in der Funktion draw_score() eine neue Variable, z.B. text_string, und speichere in ihr den aktuellen Punktestand als String.

  4. Danach legen wir die Farbe fest und wandeln den String text_string in ein grafisches Textobjekt (Bild) um. Dies geht wie folgt:

    • Textobjekt erstellen:

      text = my_font.render(text_string, True, [0, 0, 0])
      
      - Textobjekt auf dem Bildschirm darstellen:

      screen.blit(text, (win_size[0] / 2 - text.get_rect().width / 2 ,20))
      
  5. Wenn du jetzt noch dafür sorgst, dass die Funktion draw_score() in der Hauptschleife aufgerufen wird, sollte der Punktestand nun auf dem Bildschirm erscheinen.

    So sollte es jetzt aussehen:

    Textausgabe

  6. Noch ein weiteres Textobjekt: Lass neben dem Punktestand auch noch die Zeit anzeigen, wie lange das Spiel bereits am Laufen ist.

    • Die Pygame Funktion py.time.get_ticks() könnte dir helfen.
    • Versuche das selbstständig im Code zu implementieren.
    • Mehr Infos zur Funktion py.time.get_ticks() findest in der Dokumentation.

    Mögliche Ausgabe:

    Textausgabe mit Zeit

Pixel-Kollision

Im obigen Beispiel wird eine Kollision festgestellt, wenn sich die den Objekten zu Grunde liegenden Rechtecke überschneiden. Eine kleine Anpassung des Bauplans, d.h. der Klassen, genügt, um erst bei einer effektiven Bildüberschneidung eine Kollision zu melden. Kurz: "Melde erste eine Kollision, wenn sich die Pixel der jeweiligen Objekte überlappen."

  1. Definiere in allen Klassen (also im Bauplan) eine neue Eigenschaft self.mask. In diesen "Mask" Attributen sollen die nicht transparenten Pixel des Bildes gespeichert werden. Dies geschieht mittels der Funktion py.mask.from_surface(). In der Klasse sollte das dann so aussehen:

    self.mask = py.mask.from_surface(self.image)
    
  2. Aufgepasst: Das "Mask" Attribut ändert sich nach jedem Kostümwechsel. D.h. nach jedem Kostümwechsel muss self.mask aktualisiert werden (dem neuen Bild entsprechend).

  3. Nun muss nur noch die Kollision mit einer neuen Kollisions-Funktion überprüft werden und fertig. Ersetze nun py.sprite.collide_rect(player1, munze) == True durch die neue Abfrage

    py.sprite.collide_mask(player1, munze) != None
    

    Pixelkollision

  4. Überprüfe dein Programm.