Python Tutorial
- jetzt Python programmieren lernen

ein Koordinatensystem für unsere Computerspiele

Ein Verständnis des verwendeten Koordinatensystems ist hilfreich für die Programmierung von Computerspielen. Wir wollen in den folgenden Kapiteln ein Breakout-Spiel programmieren. Dazu verwenden wir eine andere Technik als im bisherigen programmierten Spiel Pong.

Als erstes schauen wir uns einfach das aus Schulzeiten vielleicht noch bekannte kartesische Koordinatensystem an. Wer sich nicht mehr an die Schulzeiten erinnert (oder es bisher nicht kennen gelernt hat) – jetzt bekommt Mathe endlich eine praktische Anwendung. Aber keine Panik: es ist keine wilde Rechnerei, sondern es geht um das Verständnis zwischen Koordinatensystem und die Anwendung beim Programmieren!

Das kartesische Koordinatensystem wurde von dem Franzosen René Descartes entwickelt. Dabei war es damals hipp, Latein zu verwenden und so wurde das Koordinatensystem nach dem latinisierten Nachnamen von Descartes, also „Cartesius“ benannt (wir müssen jetzt nicht Latein lernen, aber manchmal kann man im Klugscheißermodus beeindrucken).

Das typische kartesische Koordinatensystem:

das kartesische Koordinatensystem
das kartesische Koordinatensystem

Welche Eigenschaften hat das kartesische Koordinatensystem?

  • Koordinatenachsen stehen senkrecht  90 Grad Winkel die Koordinatenachsen stehen senkrecht (orthogonal) aufeinander
  • konstante Abstände Koordinatenlinien sind Geraden in konstantem Abstand voneinander
  • x-Achse, y-Achse, Nullpunkt die waagrechte Achse heißt x-Achse (Abszisse/Abszissenachse)
  • die senkrechte Achse heißt y-Achse (Ordinate/Ordinatenachse)
  • die Nennung ist immer in der Reihenfolge x und dann y
  • der Punkt 0 (beide Achsen treffen dort aufeinander) ist der Koordinatenursprung (Ursprung/Nullpunkt)
  • 4 Quadranten die 4 Bereiche werden als Quadranten bezeichnet (der erste liegt rechts oben und die Nummerierung erfolgt gegen den Uhrzeigersinn)

Was hat das mit unserer Programmierung zu tun?

Das Koordinatensystem beim Programmieren

Unseren Bildschirm können wir mathematisch auch als Koordinatensystem sehen, allerdings mit nur einem Quadranten! Wichtig dabei ist, dass der Nullpunkt (Koordinatenursprung) am linken oberen Eck sitzt. Das gilt auch für ein Fenster. Die x-Achse geht vom Nullpunkt nach rechts (wie beim kartesischen Koordinatensystem). Die y-Achse geht nach unten und wird mit positiven Zahlen bezeichnet.

Auch hier sagt ein Bild mehr als tausend Worte:

Koordinatensystem beim Programmieren


Koordinatensystem beim Programmieren

In dieses Koordinatensystem können wir nun über Pygame einfach etwas einzeichnen:

pygame.draw.rect(screen, ROT, [20, 50, 30, 30])
Rechteck im Koordinatensystem


Rechteck im Koordinatensystem

Unsere erste Angabe mit 20 bezieht sich auf die X-Achse und die zweite Angabe mit 50 bezieht sich auf die Y-Achse. Das Viereck wird als an der Position 20 (rechts vom Nullpunkt) und an der Position 50 (nach unten vom Nullpunkt aus gesehen) gezeichnet. Es ist jeweils 30 Pixel breit wie hoch.

Hier kommt das Koordinatensystem zum Einsatz.

WICHTIG für das Verständnis

Und jetzt kommt der Trick beim Programmieren von Spielen: Der Bildschirm dient nur zur Ausgabe – die Berechnung, ob ein Ereignis stattfindet im Hintergrund über Listenelemente!

Wir geben auf dem Bildschirm (in einem Fenster) unsere Spielegrafik aus, aber im Hintergrund haben wir eine ineinander verschachtelte Liste, durch die wir bequem unsere 2-dimensionale Spielekarte (map) darstellen können und Ereignisse berechnen. Schauen wir uns diese Listen an:

Unsere Liste – man könnte auch Karte dazu sagen (oder map hört sich auch gut an):

In unserer ersten Zeile (die 8 Felder hat) sollen:

  • leere Flächen über ein "-" (Minus),
  • Essen zum Einsammeln über die "E"
  • und Berge (unüberwindbare Hindernisse) über "B" dargestellt werden.

In Python wäre das eine typische Liste:

karte = ["-", "-", "E", "B", "B", "E", "-", "E"]

Wir haben also da der dritte Position Essen, dass wir einsammeln wollen und dann kommen 2 Bergelemente, die wir so nicht überwinden können um das darauffolgende Essen einsammeln zu können.

In Python kann man den Inhalt eines bestimmten Listenfeldes über den Index abfragen. Wollen wir nun die dritte Position abfragen und wir denken, da müsste doch ein „E“ für Essen herauskommen, wird sich wundern. Es kommt ein B!

karte = ["-", "-", "E", "B", "B", "E", "-", "E"]
print(karte[3])

Kleine Gemeinheit am Rande. Wir können den Inhalt von Listen sehr einfach abfragen. Aber der Index fängt bei 0 an – sprich unser erstes Element ist karte[0]. Unser drittes Element aus unserem obigen Beispiel sprechen wir an über:

karte = ["-", "-", "E", "B", "B", "E", "-", "E"]
print(karte[2])

Für die Vorstellungskraft: immer Minus 1 und dann passt das mit Index ab 0 :)

karte = ["-", "-", "E", "B", "B", "E", "-", "E"]
print(karte[3-1])

Zahlen auf Karten sind praktischer

In der Praxis wird man lieber Zahlen auf unserer virtuellen Karte einsetzen, da diese einfacher zu handhaben sind und mehr Möglichkeiten bieten. Die leere Fläche wäre 0, Essen ist die Zahl 1 und Berge sind die Zahl 7. Unsere Karte würde also so aussehen:

karte = [0, 0, 1, 7, 7, 1, 0, 1]

Also wollen auch eine weitere Zeile – unsere Karte wird somit 2-Dimensonal. In Python werden verschachtelte Listen einfach über ein Komma getrennt und das komplette Element wird durch eine weitere eckige Klammer umschlossen. die Unübersichtliche Schreibweise wäre, alles in eine Zeile zu schreiben (hier einmal, dass man es sich nicht angewöhnt):

karte = [[0, 0, 1, 7, 7, 1, 0, 1], [5, 0, 0, 1, 0, 0, 0, 7] ]

In der zweiten Zeile kommt eine 5 als erste Angabe (das könnte eine Höhle darstellen). Diese Angabe ist wichtig für das Verständnis im Folgenden:

Und die schönere Darstellung ist (weil man sich dann fast schon die Landschaft vorstellen kann) einfach untereinander:

karte = [
    [0, 0, 1, 7, 7, 1, 0, 1], 
    [5, 0, 0, 1, 0, 0, 0, 7]
]

Für die Abfrage einer Position müssen wir nun sowohl die X- wie die Y-Achse angeben:

karte = [
    [0, 0, 1, 7, 7, 1, 0, 1], 
    [5, 0, 0, 1, 0, 0, 0, 7]
]
print(karte[1][0])

Aber hoppla – was kommt da nun raus? Als Rückgabewert erhalten wir „5“ und nicht „0“. Warum? Bei verschachtelten Listen haben wir den Unterschied zum kartesischen Koordinatensystem, dass die erste Angabe die Zeile ausmacht, sprich Y und die zweite Angabe dann X!

Das folgende Bild soll es klarer machen, wenn wir die Position karte[1][3] auslesen wollen:

Auslesen von der Position karte[1][3]
Auslesen von der Position karte[1][3]

Wir werden von unserer Spielfigur den „Aufenthaltsort“ in 2 weiteren Variablen speichern. Vorteil: wir können auf unserer Karte schauen, was je nach Zug passieren soll (und den Zug dann unter Umständen nicht zulassen).

spielfigur_x = 0
spielfigur_y = 0

Jetzt können wir die Anweisung geben, dass die Figur sich nach rechts bewegt. Bevor wir die Figur bewegen, überprüfen wir, ob in unserer Karte rechts neben unsere Spielfigur ein Berg befindet, wo die Figur sich nicht hinbewegen kann. Also ein kleiner Check über unsere Karte:

# kann Spielfigur nach rechts sich bewegen?
if karte[ spielfigur_y ][ spielfigur_x + 1] == 7:
    echo ("Da ist ein Berg, das geht nicht")
else:
    echo ("und ein Feld nach rechts laufen")

Und sieht man auch den Vorteil von Zahl. Wir könnten in unserem Spiel weitere unüberwindbare Bereiche haben. Neben Berge (7) gibt es noch Flüsse (8) und Schluchten (9). Und somit wäre unsere Abfrage einfach anstelle von „==“ einfach „>=“

if karte[ spielfigur_y ][ spielfigur_x + 1] >= 7:
    echo ("Da ist ein Berg oder Fluss oder Schlucht, das geht nicht")
else:
    echo ("und ein Feld nach rechts laufen")

Kurz und gut:

Auf dem Bildschirm wird nur ausgegeben! Im Hintergrund wird eine virtuelle Karte in Form von verschachtelten Listen bereitgehalten, auf der überprüft wird, welches Möglichkeiten welches Feld bietet.

Soweit so gut. Das als Hintergrundwissen für Spieleentwicklung