Main sections
13 Das PONG Spiel
PONG
Was ist PONG
Jetzt, da die Grundlagen klar sind, muss das Gelernte gefestigt und geübt werden. Das Spiel heißt: "PONG". Es ist nicht nur eines Deiner ersten Spiele mit GLBasic, sondern auch das erste Computerspiel der Welt. (1972 von Ralph H. Baer)
Wenn Du PONG nicht kennst, sieh hier nach:
www.pong-story.com
Neues Projet
Nach dem Start von GLBasic den Kopf "Neues Projekt" auswählen, und einen Namen + Pfad angeben. z.B. ..\GLBasic\Projects\Pong
Variablen
Nachdem das Projekt angelegt ist, können wir schon mit der Programmierarbeit anfangen.
Wir brauchen Variablen für die Schlägerpositionen x und y, sowie die bisher erzielten Punkte. Für all diese Variaben legen wir je ein Feld an, damit später 3,4 oder mehr Spieler einfach eingebaut werden könnten. Auch kann man so schnell den Code für Schlägerbewegung und Punktestand in einer Schleife wiederverwenden. Später mehr dazu...
Unser Code sieht jetzt so aus:
// Pong
DIM bat_y[2]
DIM bat_x[2]
DIM score[2]
Nun müssen wir die Spieler initialisieren. Dazu fügen wir eine SUB hinzu mit dem Menüpunkt: "Projekt/Neue SUB". Name: "Init"
In die SUB schreiben wir nun Quellcode, damit der Hintergrund des Spielfelds gezeichnet wird und verwenden den BackBuffer als aktuelles Hintergrundbild (man kann stattdessen natürlich auch einfach ein Bild laden).
Danach setzen wir die Position der Schläger auf die Randkoordinaten.
// ------------------------------------------------------------- //
// -=# INIT #=-
// ------------------------------------------------------------- //
SUB Init:
// Spielfeld zeichnen, als Hintergrund nutzen
BLACKSCREEN
DRAWRECT 0, 0, 639, 15, RGB(255, 255, 255)
DRAWRECT 0, 464, 640, 16, RGB(255, 255, 255)
DRAWRECT 312, 0, 16, 480, RGB(255, 255, 255)
USEASBMP
// Schläger 0 setzten
bat_y[0]=240; bat_y[1]=240
// Schläger 1 setzten
bat_x[0]=16; bat_x[1]=600
ENDSUB // INIT
Ball zurücksetzen
Zu Begin jedes Spiels muss der Ball wieder in die Mitte platziert werden, und seine Geschwindigkeit wieder auf 1 gesetzt werden. Dazu fügen wir eine neue SUB ein, wie vorher beschrieben, und nennen Sie: ResetBall
// ------------------------------------------------------------- //
// -=# RESETBALL #=-
// ------------------------------------------------------------- //
SUB ResetBall:
ball_x=320
ball_y=240
IF ball_sx<0 // Wenn Ball nach links, dann jetzt nach rechts und vice versa
ball_sx=1
ELSE
ball_sx=-1
ENDIF
ball_sy=1
ENDSUB // RESETBALL
Diese Funktion rufen wir auch in Init auf. Dazu in die SUB Init
GOSUB ResetBall
einfügen.
Anzeigen
Jetzt haben wir schon einiges programmiert, aber noch immer nichts gesehen. Es wird Zeit, dass wir das Spielfeld und den Ball anzeigen. Also, neue SUB mit Namen ShowAll:
// ------------------------------------------------------------- //
// -=# SHOWALL #=-
// ------------------------------------------------------------- //
SUB ShowAll:
// Die Schläger anzeigen
FOR num=0 TO 1
DRAWRECT bat_x[num], bat_y[num], 16, 64, RGB(255, 255, 255)
PRINT score[num], num*320 + 32, 16
NEXT
// Der Ball
DRAWRECT ball_x, ball_y, 16, 16, RGB(255, 255, 255)
SHOWSCREEN
ENDSUB // SHOWALL
Hauptschleife
Jetzt brauchen wir eine Hauptschleife, die immer wieder die SUBs aufruft. Dazu die folgenden Zeilen über die erste SUB schreiben. Vor der ersten SUB oder FUNCTION steht das Hauptprogramm. Dieses wird beim Programmstart ausgeführt.
// Voreinstellungen
GOSUB Init
// Hauptschleife
main:
GOSUB ShowAll
GOTO main
Achtung! Der Code würde das Programm dazu bringen, dass es nicht mehr reagiert, wenn wir nicht in ShowAll den Befehl
SHOWSCREEN
aufrufen würden.
Der erste Start
Drücke jetzt den Knopf zum Kompilieren drücken und starte dann das Programm.
(F8, dann F5)
Bewegung!
Jetzt muss nur noch Bewegung in das Spiel. Dazu legen wir eine SUB mit dem Namen MoveAll an und fügen den Aufruf vor
GOSUB ShowAll
mit
GOSUB MoveAll
// ------------------------------------------------------------- //
// -=# MOVEALL #=-
// ------------------------------------------------------------- //
SUB MoveAll:
// Schläger
FOR num=0 TO 1
// Spieler 1: Tasten: A, Y
IF KEY(30) THEN bat_y[0]=bat_y[0]-2
IF KEY(44) THEN bat_y[0]=bat_y[0]+2
// Tasten: auf, ab
IF KEY(200) THEN bat_y[1]=bat_y[1]-2
IF KEY(208) THEN bat_y[1]=bat_y[1]+2
// Schläger am oberen/unteren Rand? IF bat_y[num]<0 THEN bat_y[num]=0
IF bat_y[num]>416 THEN bat_y[num]=416
NEXT
Die Codes für den KEY()-Befehl findest Du unter dem Menüpunkt "Werkzeuge/KeyCodes".
Jetzt kannst Du das Programm wieder kompilieren und starten. Mit den Tasten "A, Y" und "Auf, Ab" kann man jetzt beide Schläger steuern.
Nun bewegen wir den Ball um die aktuelle x/y Geschwindigkeit des Balls:
// Ball
ball_x=ball_x+ball_sx
ball_y=ball_y+ball_sy
Kollision mit Rand
Wenn der Ball oben oder unten anstößt, drehen wir einfach seine y-Geschwindigkeit um:
// Ball unten am Rand
IF ball_y>464
ball_y=464
ball_sy=-ball_sy
ENDIF
// Ball oben am Rand
IF ball_y<0
ball_y=0
ball_sy=-ball_sy
ENDIF
Wenn der Ball links/rechts an den Rand stößt, bekommt ein Spieler einen Punkt und der Ball wird wieder in die Mitte gesetzt.
// Ball linker Rand -> Punkt für Spieler 1
IF ball_x<0
score[1]=score[1]+1
GOSUB ResetBall
ENDIF
// Ball rechter Rand -> Punkt für Spieler 0
IF ball_x>624
score[0]=score[0]+1
GOSUB ResetBall
ENDIF
Kollision mit Schläger
Wir durchlaufen eine Schleife für alle Spieler:
FOR num=0 TO 1
Zunächst fragen wir ab, ob sich der Ball in Richtung des Schlägers bewegt. Wenn der Ball nämlich schon umgedreht wurde, kann er evtl. trotzdem noch mit dem Schläger kollidieren. Dadurch würde er sonst wieder auf die eigene Seite bewegt werden.
IF (ball_sx<0 AND num = 0) OR (ball_sx>0 AND num=1)
Ist dies der Fall, prüfen wir, ob sich die beiden Rechtecke Ball + Schläger überlappen:
Wenn der Ball an einen Schläger kommt, wird seine X-Geschwindigkeit umgedreht. Die Geschwindigkeiten in X und Y werden beide erhöht. Jedoch nicht im gleichen Maße, weil sich sonst der Flugwinkel des Balls nicht ändern würde.
col = BOXCOLL(bat_x[num], bat_y[num], 16, 64, ball_x, ball_y, 16, 16)
IF col=TRUE
// Ballgeschwindigkeit in X umdrehen
ball_sx= -ball_sx
// Schneller machen / Speed up
ball_sx = ball_sx * 1.2
ball_sy = ball_sy * 1.05
Jetzt noch unsere IF Bedingungen und die Schleife abschließen:
ENDIF
ENDIF
NEXT
Voila. Fertig ist das Spiel.
Überprüfe alle Programmteile sorgfältig und verstehe jede einzelne Zeile des Codes, bevor Du versuchst ein eigenes Spiel zu schreiben. Sieh' die Referenz der Befehle in dieser Hilfe nach und versuche das Spiel auf 4 Spieler zu erweitern (oben und unten noch ein Schläger).
Erstelle einen Computer-Spieler, so dass Du auch allein spielen kannst. Dabei musst Du nur prüfen, ob die Y-Koordinate des Balls höher oder tiefer als der Mittelpunkt des Schlägers liegt, und dann den Schläger evtl. auf oder ab bewegen.
Oder versuche, dass je nach Aufschlagsposition des Balls der Flugwinkel geändert wird.
Das Programm lässt viel Platz für eigene Ideen.
Viel Spass beim Basteln.
Gesamter Quellcode:
// Pong
DIM bat_y[2]
DIM bat_x[2]
DIM score[2]
// Voreinstellungen / Setup values
GOSUB Init
// Hauptschleife / Main Loop
main:
GOSUB MoveAll
GOSUB ShowAll
GOTO main
// ------------------------------------------------------------- //
// -=# INIT #=-
// ------------------------------------------------------------- //
SUB Init:
GOSUB ResetBall
// Spielfeld zeichnen, als Hintergrund nutzen
// Draw playfield, use as background bitmap
BLACKSCREEN
DRAWRECT 0, 0, 640, 15, RGB(255, 255, 255)
DRAWLRECT 0, 464, 640, 16, RGB(255, 255, 255)
DRAWRECT 312, 0, 16, 479, RGB(255, 255, 255)
USEASBMP
// Schläger 0 setzten / Reset Bat 0
bat_y[0]=240; bat_y[1]=240
// Schläger 1 setzten / Reset Bat 1
bat_x[0]=16; bat_x[1]=600
// Klassischer Zeichensatz / Classic Font
LOADFONT "FontBW.bmp", 0
ENDSUB // INIT
// ------------------------------------------------------------- //
// -=# RESETBALL #=-
// ------------------------------------------------------------- //
SUB ResetBall:
// Diese Variablen sind als LOCAL definiert:
// These variables are defined LOCAL:
// void
ball_x=320
ball_y=240
IF ball_sx<0
ball_sx=1
ELSE
ball_sx=-1
ENDIF
ball_sy=1
ENDSUB // RESETBALL
// ------------------------------------------------------------- //
// -=# SHOWALL #=-
// ------------------------------------------------------------- //
SUB ShowAll:
// Die Schläger anzeigen / Show the bats
FOR num=0 TO 1
DRAWRECT bat_x[num], bat_y[num], 16, 64, RGB(255, 255, 255)
PRINT score[num], num*320 + 32, 16
NEXT
// Der Ball / The ball
DRAWRECT ball_x, ball_y, 16, 16, RGB(255, 255, 255)
SHOWSCREEN
ENDSUB // SHOWALL
// ------------------------------------------------------------- //
// -=# MOVEALL #=-
// ------------------------------------------------------------- //
SUB MoveAll:
// Paddles
FOR num=0 TO 1
// Tasten / Keys: A, Y
IF KEY(30) THEN bat_y[0]=bat_y[0]-2
IF KEY(44) THEN bat_y[0]=bat_y[0]+2
// Tasten / Keys: /\, \/
IF KEY(200) THEN bat_y[1]=bat_y[1]-2
IF KEY(208) THEN bat_y[1]=bat_y[1]+2
// Schläger am Rand? / Bat at border?
IF bat_y[num]<0 THEN bat_y[num]=0
IF bat_y[num]>416 THEN bat_y[num]=416
NEXT
// Ball
ball_x=ball_x+ball_sx
ball_y=ball_y+ball_sy
// Ball unten am Rand / Ball at lower border
IF ball_y>464
ball_y=464
ball_sy=-ball_sy
ENDIF
// Ball oben am Rand / Ball at upper border
IF ball_y<0
ball_y=0
ball_sy=-ball_sy
ENDIF
// Ball Linker Rand / Ball at left border
IF ball_x<0
score[1]=score[1]+1
GOSUB ResetBall
ENDIF
// Ball rechter Rand / Ball at right border
IF ball_x>624
score[0]=score[0]+1
GOSUB ResetBall
ENDIF
// Pong
FOR num=0 TO 1 // Für jeden Spieler / For each player
// Bewegt sich der Ball auf den Schläger 'num' zu?
// Does ball move toward bat 'num'
IF (ball_sx<0 AND num = 0) OR (ball_sx>0 AND num=1)
col=BOXCOLL(bat_x[num], bat_y[num], 16, 64, ball_x, ball_y, 16, 16)
IF col=TRUE
// Ballgeschwindigkeit in X umdrehen / Flip ball's X-direction
ball_sx= -ball_sx
// Schneller machen / Speed up
ball_sx = ball_sx * 1.2
ball_sy = ball_sy * 1.05
ENDIF
ENDIF
NEXT
ENDSUB // MOVEALL