Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

C-Kurs/Pong: Unterschied zwischen den Versionen

Zeile 54: Zeile 54:
  
 
=== Verarbeiten der Tastendrücke ===
 
=== Verarbeiten der Tastendrücke ===
 +
Als nächstet kommt die Funktion ''void key_processing()'' dran. Darin fragen wir nun folgendermaßen eine Tastedruck ab:
 +
<pre>int ch = getch();</pre>
 +
Durch unser bei der Initialisierung gesetztes Timeout, wird die Funktion spätestens nach 100 Millisekunden verlassen. Wir können das Ergebnis in ''ch'' nun z.B. mit der Konstante ''KEY_UP'' und ''KEY_DOWN'' bzw. den Buchstaben '' 'w' '' und '' 's' '' vergleichen und entsprechend die Positionsvariable der Schläger erhöhen oder veringern. Dabei sollte abgefangen werden, dass der Schläger außerhalb des Spielfelds landet. Wurde keine oder eine ungültige Taste gedrückt, können wir das hier stillschweigend ignorieren.
 +
 +
Zum Testen kann die Funktion zusammen mit ''print_field()'' in eine Endlosschleife gepackt werden.
 +
 +
=== Ball bewegen ===
  
  

Version vom 19. September 2009, 16:11 Uhr

Hier soll das Spiel Pong Schritt für Schritt implementiert werden. Die Anzeige des Spielfelds soll durch ASCII-Zeichen realisiert werden, sodass das Spiel in einem Terminal laufen kann. Ein Beispiel-Screenshot könnte so aussehen:

         1                     2
+----------------------------------------+
|                                        |
|                                        |
|#                                       |
|#                                       |
|#                                       |
|            *                           |
|                                        |
|                                       #|
|                                       #|
|                                       #|
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
+----------------------------------------+

Leider ist es nicht ganz einfach, einzelne Tasten einzulesen, wie sie gebraucht werden, wenn der Benutzer den Schläger bewegen möchte. scanf arbeitet gepuffert und gibt die Eingabe erst nach Betätigung der Enter-Taste an das Programm. Wir verwenden deswegen die C-Programmbibliothek curses, die uns entsprechende Funktionen zum Abfragen eines Tastendrucks liefert.

Aufgabe

curses initialisieren

Erstmal müssen wir das Headerfile für curses includen:

 #include <curses.h> 

Schreibe jetzt eine Funktion void init(), die für das Initialisieren von curses zuständig wird. Sie enthält folgende Befehle:

  • initscr();
    aktiviert curses
  • noecho();
    damit Buchstaben der getippten Tasten nicht im Terminal erscheinen
  • cbreak();
    deaktiviert das Puffern der Terminalzeile
  • keypad(stdscr, TRUE);
    aktiviert spezielle Tasten, wie die Pfeiltasten
  • halfdelay(1);
    damit die Funktion, die später auf einen Tastendruck wartet, nach einer Zehntel Sekunde beendet wird

Jetzt folgt die main-Funktion. Sie enthält als ersten Aufruf unsere init-Funktion. Unser Programm sollte beim Beenden curses vernünftig deaktivieren, weswegen als letzter Aufruf in der main-Funktion folgender sein sollte:

 endwin(); 

Wenn die Quelltextatei pong.c heißt, kann sie ab jetzt mit folgendem Befehl kompiliert werden:

 gcc -lcurses pong.c 

Variablen für den Zustand des Spiels

Zuerst überlegen wir uns, wie groß unser Spielfeld und die Schläger sein sollen. Diese Werte sollten als Präprozessor-Befehle angegeben werden. Ein kleines, aber feines Feld bekommt man z.B. mit einer Breite von 40, einer Höhe von 15 und einer Schlägerhöhe von 3.

Jetzt führen wir die Variablen ein, die den Spielzustand repräsentieren sollen. Wir brauchen je eine y-Positionen für die beiden Schläger. Dazu kommt x- und y-Position des Balls. Diese Positionsvariablen sind vom Typ int. Damit wir wissen, in welche Richtung sich der Ball gerade bewegt, brauchen wir x- und -y-Richtung. Dafür eignet sich auch int; welche die Werte 1 und -1 annehmen können sollen, je nachdem, ob es nach rechts/links bzw. nach unten/oben gehen soll. Jetzt brauchen wir noch zwei Variablen für den Punktestand, die wir auch gleich mit 0 initialisieren können.

Die Funktion void place_paddles() soll die Schläger mittig platzieren. Die Funktion void place_ball() soll den Ball in der Mitte platzieren. Die x- und y-Reichtung können wir erstmal mit 1 belegen. Beide Funktionen sollten jetzt in der main aufgerufen werden.

Ausgeben des Spielfelds

Jetzt soll die Funktion void print_field() geschrieben werden, die das komplette Spielfeld und den Punktestand anzeigen soll. Schaue dir dazu den obigen Screenshot an und überlege, wie du diesen zeilenweise aus den Positionsvariablen zusammenbauen kannst.

In der Funktion sollte zuerst clear() von curses aufgerufen werden, was den bisherigen Terminalinhalt löscht. Wichtig ist, dass du printw() von curses statt printf() verwendest. Die Art und Weise der Verwendung ist aber identisch. Zum Schluss muss noch refresh() von curses aufgerufen werden, damit das eben ausgegebene erscheint.

Teste nun dein print_field(), indem du es in main aufrufst. Sollte das Bild gleich nach Starten des Programms wieder verschwinden, baue am Ende noch ein sleep(10) ein, damit das Programm noch 10 Sekunden läuft.

Verarbeiten der Tastendrücke

Als nächstet kommt die Funktion void key_processing() dran. Darin fragen wir nun folgendermaßen eine Tastedruck ab:

int ch = getch();

Durch unser bei der Initialisierung gesetztes Timeout, wird die Funktion spätestens nach 100 Millisekunden verlassen. Wir können das Ergebnis in ch nun z.B. mit der Konstante KEY_UP und KEY_DOWN bzw. den Buchstaben 'w' und 's' vergleichen und entsprechend die Positionsvariable der Schläger erhöhen oder veringern. Dabei sollte abgefangen werden, dass der Schläger außerhalb des Spielfelds landet. Wurde keine oder eine ungültige Taste gedrückt, können wir das hier stillschweigend ignorieren.

Zum Testen kann die Funktion zusammen mit print_field() in eine Endlosschleife gepackt werden.

Ball bewegen

Kollisionen des Balls erkennen

Erkennen, wenn der Ball nicht vom Schläger getroffen wurde

alles in ein rundenbasiertes Spiel stecken

Kommentare

Wenn du Anmerkungen zur Aufgabe hast oder Lob und Kritik loswerden möchtest, ist hier die richtige Stelle dafür. Klicke einfach ganz rechts auf "bearbeiten" und schreibe deinen Kommentar direkt ins Wiki. Keine Scheu, es geht nichts kaputt ;)