BlitzBasic-Community-Tutorial/ Pong

Aus Wikibooks
Zur Navigation springen Zur Suche springen

Einleitung[Bearbeiten]

Was soll es denn werden?[Bearbeiten]

Natürlich ein Spiel! Also soll es Spaß machen, es zu spielen. Doch auch das Programmieren soll Spaß bereiten. Bevor man wild drauf los programmiert, sollte man sich eine Liste machen, was man programmieren will:
Es soll ein einfaches Ping- Pong- Spiel werden. Ein Spieler wird oben (Spieler2) und einer unten (Spieler1) sein. Es gibt einen Spielball, der von den Spielern hin und her gespielt wird. An den Seiten gibt es eine Wand, an der der Ball abprallt. Um das Ganze interessanter zu gestalten, sind die Spieler wie ein Halbkreis geformt. Dadurch wird die Flugbahn der Kugel verändert. Ziel ist es, die Kugel so zu bewegen, dass der Gegenspieler sie nicht mehr erreicht.

Nun hätten wir erst mal den Grundaufbau. Doch so macht es noch nicht wirklich viel Spaß beim Spielen, deshalb kannst du einige Besonderheiten hineinprogrammieren:

  • Der Hintergrund könnte ständig seine Farbe wechseln(Farbverlauf).
  • Der Spielstand soll anhand der durchgelassenen Bälle gezählt und angezeigt werden.
  • Die Anzahl der Punkte, die man braucht, um ein Spiel zu gewinnen, soll einstellbar sein
  • Auch soll ein Endlosspiel möglich sein.
  • Als Letztes wird es eine Pausenfunktion geben.

Das hört sich jetzt zunächst recht kompliziert an, doch es liegt alles im Bereich des Machbaren. Zuerst werden wir das Grundgerüst bauen, in das der Rest später eingebaut wird. Ich werde mich bemühen, alles möglichst verständlich zu schreiben, jedoch soll dies bereits das 2. Spiel werden. Ich werde deswegen nicht jeden Befehl so genau beschreiben. Wenn du einige Befehle nicht kennst, kannst du sie sicher in diesem Buch nachschlagen. Wenn du sie nicht findest, kannst du gerne auf der Diskussionsseite danach fragen. Bei Fragen oder Verbesserungsvorschlägen, bin ich auf der Disskusionsseite zu erreichen oder ihr könnt mir eine Mail schicken (axe.site@gmail.de). Außerdem ist dieses Tutorial auch auf meiner Homepage (Adresse ist auf der Diskussionsseite) zu erreichen.

Da wir für dieses Projekt einige Bilder, Dateien usw. benötigen, lege bitte irgendwo einen Ordner mit dem Namen "Ping Pong" (oder so ähnlich) an, wo du die Programme speichern kannst und dort einen Unterordner "gfx", dort werden wir später die ganzen Dateien unterbringen.


Als Struktur sieht das dann so aus:

  • Ping Pong (für die Programme)
    • gfx (für Bilder, Dateien)

Grundgerüst[Bearbeiten]

Die ersten Zeilen[Bearbeiten]

Am Anfang benötigen wir natürlich erst mal ein Grafikfenster:

Graphics 1024,768,32,1

Damit wir später einmal die Auflösung ändern können bzw. nicht immer diese Zahlen wissen müssen, kann man auch folgendes schreiben:

global xmax=1024,ymax=768 ;damit definieren wir die Auflösungs-Variablen für das gesamte Programm
Graphics xmax,ymax,32,1  ;die Variablen werden nur eingesetzt, funktioniert wie oben

damit wir später nicht laufend den Bildaufbau sehen, werden wir den Backbuffer benutzen:

SetBuffer BackBuffer()

Nun brauchen wir noch eine Framebegrenzung, denn das Spiel soll ja immer gleich schnell ablaufen:

Global frametimer = CreateTimer(60)

Und zum Schluss des Anfangs wollen wir dem Zufall noch auf die Sprünge helfen:

SeedRnd MilliSecs() ; Damit initialisieren wir den Zufall mit der Anzahl an Millisek. seit dem Starten von Windows

Zusammengefasst ergibt sich also folgender Quelltext für die ersten Zeilen:

Global xmax=1024,ymax=768 
Graphics xmax,ymax,32,1 
SetBuffer BackBuffer() 
Global frametimer = CreateTimer(60) 
SeedRnd MilliSecs()

Die Hauptschleife[Bearbeiten]

Als unsere Hauptschleife werden wir eine für Spiele typische "Repeat - Until"-Schleife verwenden. Diese Schleifenart funktioniert so, dass am Ende der Schleife(until) eine Bedingung abgefragt wird. In unserem Fall soll festgestellt werden, ob Escape gedrückt wurde. Nachdem die Bedingung (Escape drücken) erfüllt wurde wird das Programm nach der Schleife fortgesetzt, in unserem Fall soll das Programm beendet werden:

Repeat;wiederhole
;hier wird gleich der Inhalt eingesetzt
Until Keyhit(1);bis Escape gedrückt wurde
End

Eigentlich doch nicht so schwer, oder?

Das erste kleine Testprogramm[Bearbeiten]

Nun wird es etwas komplizierter. Doch keine Angst wir werden das schon schaffen!
Wie die Überschrift schon sagt wollen wir nun schon mal ein kleines (lauffähiges) Programm erstellen. Dazu setzten wir die ersten Zeilen und die Hauptschleife zusammen:

global xmax=1024,ymax=768 
Graphics xmax,ymax,32,1 
SetBuffer BackBuffer() 
Global frametimer = CreateTimer(60) 
SeedRnd MilliSecs()

Repeat
 Waittimer (frametimer);damit nutzen wir den oben erstellten Frametimer

 ;hier kommt später noch mehr rein

 Text xmax/2,ymax/2,"Das erste kleine Testprogramm zu Ping Pong!";das gibt einen Text ausgehend vom Mittelpunkt aus.
 Flip ;da wir den Hintergrundpuffer aktiviert haben, wechseln wir jetzt die Seiten, damit wir was sehen
 Cls ;der nichtsichtbare Bereich wird gelöscht
Until Keyhit(1)
End ;damit wird unser Programm beendet

Um dieses Wunderwerk auszuprobieren einfach kopieren und in ein leeres BB Fenster einfügen!

Das ist doch schon sehr gut, nicht wahr? Um alles richtig zu verstehen, könnt ihr gerne ein bisschen damit herum experimentieren (z.b. könnte man das Programm doch auch über eine andere Taste beenden).

Die Grafik kommt ins Spiel[Bearbeiten]

Nun wollen wir uns mal um die Grafiken kümmern, denn was ist ein Spiel schon ohne Grafik?
Zuerst wollen wir uns mal überlegen, was wir so an Grafiken brauchen:

  • die Kugel
  • die Spieler (unten und oben)
  • die Seitenwände (Stahlträger)

Die einzelnen Bilddateien erstellen[Bearbeiten]

Die benötigten Bilder habe ich bereits gemalt. Um sie hier zur Verfügung zu Stellen, musste ich sie jedoch in das PNG-Format umwandeln. Um die Bilder aber auch in der Demoversion von Bltiz Basic verwenden zu können, musst du sie in BMP Grafiken umwandeln. Das sollte eigentlich nicht schwer sein, denn das kann jedes Bildbearbeitungsprogramm. Die Bilder speicherst du bitte in den Unterordner "gfx", den wir ja schon erstellt haben. Der Dateiname steht gleich bei den Dateien. Wenn dir meine Bilder nicht gefallen kannst du gerne eigene verwenden, die entsprechenden Abmessungen stehen ebenfalls unten.

Du kannst die Bilder auch auf meiner Homepage (Adresse ist auf der Diskussionsseite) downloaden. Dann entfällt das Konvertieren.

Die Kugel[Bearbeiten]

Die Kugel ist bei mir einfach nur ein weißer Kreis auf schwarzem Hintergrund. Natürlich könnte man in Blitz Basic auch einen Kreis malen, jedoch wollen wir eine Kollisionsabfrage benutzen, da ist es so praktischer.(Dateiname:"kugel.bmp" Abmessung 20*20 Pixel)
Weiße Kugel

Die Spieler[Bearbeiten]

Für die Spieler habe ich einfach einen Halbkreis gemalt, später kann man durch die Krümmung die Flugbahn der Kugel beeinflussen. (Dateiname:"pongspieler1.bmp" Abmessung 80*20 Pixel). Um die Grafik für den 2. Spieler zu erstellen, musst du dieses Bild einfach um 180 Grad drehen und erneut abspeichern (Dateiname: "pongspieler2.bmp").
Pong Spieler1

Die Seitenwände[Bearbeiten]

Die Seitenwände sehen bei mir wie Stahlträger aus, sie werden aus einer einzelnen Bilddatei zusammengesetzt. Wie man diese im Programm zusammensetzt, kommt später.(Dateiname:"seitenwand.bmp" Abmessung 50*50 Pixel).
Stahträgerfragment

Die Einbindung der Bilddateien ins Programm[Bearbeiten]

Nun kommen wir wieder zu unserem eigentlichen Programm zurück.

Da wir dabei sind ein Spiel zu programmieren, werden wir die verschiedenen Grafikbefehle in BB ausnutzen. Wir werden also für jedes Bild den Transparentmodus verwenden. Wie du vieleicht schon bemerkt hast, haben die Grafiken verschiedene Hintergrundfarben. Diese müssen wir beachten, damit der Transparentmodus wirklich funktioniert.

Der nun folgende Code muss direkt oberhalb (vor) der Hauptschleife eingebaut werden:
Hinweis: Die Pfadangaben sind relativ, d.h. man muss nicht den gesamten Pfad (C:\...) angeben, sondern nur den Pfad ausgehend von dem Speicherort des Programmes.

In der Praxis bedeutet das:

  • Ordner, wo die Programmdatei liegt(bei uns "Ping Pong")
    • Unterordner, der relative Pfad würde nur "Unterordner" heißen(bei uns also nur "gfx")
;...

Global kugel=LoadImage("gfx\kugel.bmp");damit wird die Kugel in eine Variable geladen
MidHandle kugel ;der Urspung wird auf den Mittelpunkt gelegt, das macht sich bei Berechnungen besser
;auf das Einstellen der Tranzparenzfarbe kann verzichtet werden, weil sie Standard mäßig schwarz ist.

Global spieler1=LoadImage("gfx\pongspieler1.bmp");damit ist der Untere gemeint
MidHandle spieler1;auch dieser bekommt seine Ursprung in die Mitte (s.Kugel)
MaskImage spieler1,255,255,255;hier müssen wir die Tranzparenzfarbe angeben, weil sie vom Standard abweicht

Global spieler2=LoadImage("gfx\pongspieler2.bmp");damit ist der Obere gemeint
MidHandle spieler2;auch dieser bekommt seine Ursprung in die Mitte (s.Kugel)
MaskImage spieler2,255,255,255;hier müssen wir die Tranzparenzfarbe angeben, weil sie vom Standard abweicht

Global begrenzung=LoadImage("gfx\seitenwand.bmp");damit wird die Seitenwand geladen
MaskImage begrenzung,255,255,255;hier müssen wir die Tranzparenzfarbe angeben, weil sie vom Standard abweicht

Repeat
;...

Die Seitenwände[Bearbeiten]

Nun haben wir die Seitenwände ja bereits geladen, doch da dieses Bild ja nur 50*50 Pixel groß ist, müssen wir es mehrmals untereinander setzten, damit erhalten wir dann auch einen richtigen Stahlträger.

Doch nun zum Code:
Ich habe es mir ursprünglich so gedacht, dass die Positionen vor der Hauptschleife in einem Dim Feld berechnet und gespeichert werden.
Jedoch ist es einfacher, wenn man die Positionen erst in der Hauptschleife berechnet, denn dabei benötigt man kein Dim-Feld. Deshalb musst du den folgenden Code in die Hauptschleife einbauen:

Repeat
Waittimer (frametimer);damit nutzen wir den oben erstellten Frametimer

For z2=0 To 1;also wird das ganze 2x durchlaufen (links und rechts)
 If z2=1 Then x=xmax-50 Else x=0 ;wenn die Schleife zum 2. Mal durchlaufen wird, werden die Steine rechts gemalt
 For z= 0 To ymax/50;diese Schleife sorgt für die Verschiebung auf der Y-Achse
  DrawImage begrenzung,x,z*50;x ist der Wert aus der 1. Schleife, y wird durch die Schleife immer um 50 erhöht
 Next
Next

Zugegeben ist diese Schleifenkonstruktion etwas kompliziert, deshalb pflücken wir sie noch mal auseinander:

Die erste Schleife (for z2=0 to 1) wird sichergestellt, dass die Reihe 2x gemalt wird: Das erste Mal links (x=0), das zweite Mal rechts (x=xmax-50 (1024-50=974)). Diese X Werte werden mit der If Konstruktion berechnet.
Nun die 2. Schleife: Diese hat eigentlich die Funktion, die Y-Werte zu berechnen. Jedoch nur solange sie wirklich auf dem Bildschirm sichtbar sind. 1024/50=20 Die Schleife wird also 20 mal durchlaufen.
Jetzt sind wir im inneren der beiden Schleifen, dort werden schließlich die Begrenzungsstein gemalt. Hierzu wird DrawImage verwendet, damit der Transparenzmodus genutzt wird(s.oben). Die Parameter bedeuten folgendes:

  • begrenzung: das ist die Variable in der wir die Grafik der Seitenbegrenzung geladen haben
  • x: gibt die X-Position an, wird durch die If Anweisung gesteuert, ist entweder 0 (links) oder xmax-50 (1024-50=974) (rechts)
  • z*50: gibt die Y-Position an, wird durch die 2. Schleife gesteuert, wird durch die Multiplikation mit 50 jewals um 50 erhöht (Werte:0,50,100,...,700,750)

Ich hoffe das ich das jetzt so erklärt habe, das du es verstanden hast, wenn nicht schreibe es bitte auf der Disskusionsseite.

Zusammenfassung Grafik[Bearbeiten]

Dieses Kaptitel war nun schon etwas anspruchsvoller. Wir haben hier die Grundlagen für das Aussehen des Spiels gelegt. Damit man davon mal etwas sieht, folgt nun das 2.Testprogramm:

Das 2.Testprogramm[Bearbeiten]

Um dieses Programm zum Laufen zu bringen, müssen die Grafiken im Ordner "gfx" sein und die jeweils richtigen Namen haben.

global xmax=1024,ymax=768 
Graphics xmax,ymax,32,1 
SetBuffer BackBuffer() 
Global frametimer = CreateTimer(60) 
SeedRnd MilliSecs()

Global kugel=LoadImage("gfx\kugel.bmp");damit wird die Kugel in eine Variable geladen
MidHandle kugel ;der Urspung wird auf den Mittelpunkt gelegt, das macht sich bei Berechnungen besser
;auf das Einstellen der Tranzparenzfarbe kann verzichtet werden, weil sie Standard mäßig schwarz ist.

Global spieler1=LoadImage("gfx\pongspieler1.bmp");damit ist der Untere gemeint
MidHandle spieler1;auch dieser bekommt seine Ursprung in die Mitte (s.Kugel)
MaskImage spieler1,255,255,255;hier müssen wir die Tranzparenzfarbe angeben, weil sie vom Standard abweicht

Global spieler2=LoadImage("gfx\pongspieler2.bmp");damit ist der Obere gemeint
MidHandle spieler2;auch dieser bekommt seine Ursprung in die Mitte (s.Kugel)
MaskImage spieler2,255,255,255;hier müssen wir die Tranzparenzfarbe angeben, weil sie vom Standard abweicht

Global begrenzung=LoadImage("gfx\seitenwand.bmp");damit wird die Seitenwand geladen
MaskImage begrenzung,255,255,255;hier müssen wir die Tranzparenzfarbe angeben, weil sie vom Standard abweicht

ClsColor 255,0,0;damit wird der Hintergrund rot, du kanst sonst die Spieler und Seitenwände nicht sehen

Repeat
Waittimer (frametimer)

For z2=0 To 1
 If  z2=1 Then x=xmax-50 Else x=0
 For z=0 To ymax/50
  DrawImage begrenzung,x,z*50
 Next
Next


Text xmax/2,ymax/2,"Das zweite Testprogramm zu Ping Pong!";das gibt einen Text ausgehend vom Mittelpunkt aus.

DrawImage kugel,400,400;nur damit man sieht, das sie existiert
DrawImage spieler1,400,600
DrawImage spieler2,400,100

Flip ;da wir den Hintergrundpuffer aktiviert haben, wechseln wir jetzt die Seiten, damit wir was sehen
Cls ;der nichtsichtbare Bereich wird gelöscht
Until Keyhit(1)
End ;damit wird unser Programm beendet

Jetzt kommt Bewegung ins Spiel[Bearbeiten]

Wie die Überschrift schon sagt, werden wir uns jetzt mal darum kümmern, das sich die Sachen bewegen und du die Spieler steuern kanst.

Die Spieler[Bearbeiten]

Als erstes kümmern wir uns mal um die Steuerung der Spieler:

Um die Y-Position brauchen wir uns eigentlich nicht kümmern, denn da Spieler immer oben bzw. unten sind, ist die Y-Position immer gleich: Wir müssen nur beachten, dass die Y-Pos. des Oberen nicht 0 ist, denn wir haben seinen Ursprung ja auf den Mittelpunkt gesetzt (s. oben). Um die Y-Position zu bekommen, müssen wir also die Höhe der Spieler grafik durch 2 teilen: 20/2=10 Also ist die Y-Pos. des Oberen immer 10. Da der 1.Spieler ja unten ist, bedeutet das, dass er dort 10 Pixel vom Rand entfernt ist also ymax-10 (768-10=758).

Nun brauchen wir noch die Bewegung der Spieler:

Damit du später das Spiel richtig steuern kanst, bzw. auch alleine spielen kannst, wird es also mehrere Arten der Steuerung geben:

  • Computer
  • Tastatursteuerung
  • Maussteuerung

Damit wir diese im Programm leicht verändern können, werden wir also Variablen vergeben:

Global sp1st ;bedeutet: Spieler 1 Steuerung
Global sp2st
Global xsp1 ;für die X-Position des 1. Spielers
Global xsp2 ;für die X-Position des 2. Spielers

Dieser Code muss vor der Hauptschleife eingebaut werden.

Damit auch etwas passiert, müssen wir in der Hauptschleife also einige Tasten abfragen:
Dafür brauchen wir die Scancodes, die man eigentlich überall findet, ich werde trotzdem immer mit angeben, welche Taste damit gemeint ist.

If KeyDown(203) And sp1st=1 Then xsp1=xsp1-beweglichkeit;linke Pfeiltaste
If KeyDown(205) And sp1st=1 Then xsp1=xsp1+beweglichkeit;rechte Pfeiltaste

Im Klartext bedeutet das:
Wenn die linke Pfeiltaste gedrückt ist und die Steuerungsvariable 1 ist(was für Tastatursteuerung stehen soll) dann verringer die X-Pos des 1. Spielers um die Beweglichkeit. Die Beweglichkeit wird später behandelt.
Um den 2. Spieler bewegen zu können, brauchen wir natürlich 2 andere Tasten, ich habe mir Y und X gedacht:

If KeyDown(44) And sp2st=1 Then xsp2=xsp2-beweglichkeit;Y Taste
If KeyDown(45) And sp2st=1 Then xsp2=xsp2+beweglichkeit;X Taste

Nun könne wir schon unsere beiden Spieler bewegen, doch sie können auch außerhalb des Bildschrims sein, das darf es eigentlich nicht geben. Deswegen machen wir eine einfache If Abfrage ob die Position unzulässig ist:

If xsp1<70 Then xsp1=70
If xsp1>xmax-70 Then xsp1=xmax-70
If xsp2<70 Then xsp2=70
If xsp2>xmax-70 Then xsp2=xmax-70

Wie komme ich jetzt wieder auf die 70? Da wir später die Flugbahn der Kugel durch die Krümmung verändern wollen, soll es auch möglich sein, die Kugel knapp am Rand gerade zurückzubewegen. Wenn das jetzt noch nicht einleuchtet, wirst du das spätestens beim ersten richtigen spielen merken.

Wie oben geschrieben, wollen wir ja nicht nur die Tastatursteuerung sondern auch eine Maussteuerung ermöglichen:

If sp1st=2 Then xsp1=xsp1+MouseXSpeed()
If sp2st=2 then xsp2=xsp2+MouseXSpeed()

Diese Abfrage ist eigentlich recht einfach: Wenn die Steuerungvariable 2 ist (was für Maus stehen soll), dann wird zu der X-Pos. einfach der Unterschied der X- Mauskoordinaten addiert. Dies ist ein sehr nützlicher Befehl der uns von Blitz Basic zur Verfügung gestellt wird.

Als letztes fehlt uns noch die automatische Steuerung der Spieler:

If xsp1>xkugel And sp1st=0 Then xsp1=xsp1-beweglichkeit
If xsp1<xkugel And sp1st=0 Then xsp1=xsp1+beweglichkeit

If xsp2>xkugel And sp2st=0 Then xsp2=xsp2-beweglichkeit
If xsp2<xkugel And sp2st=0 Then xsp2=xsp2+beweglichkeit

Dises Abfrage sollte eigentlich nicht so schwer sein: xkugel steht für die X-Position der Kugel, die wir später noch brauchen. Diese Steuerung ist noch etwas unvollständig, wir werden sie später noch ergänzen.
Als Letztes brauchen wir natürlich noch Umschaltmöglichkeit für die Steuerungsarten: Dafür fragen wir die Tasten 1 und 2 ab:

If KeyHit(2) Then sp1st=sp1st+1;die Zahlentaste 1
If KeyHit(3) Then sp2st=sp2st+1;die Zahlentaste 2

If sp1st>2 then sp1st=0
If sp2st>2 then sp2st=0

Natürlich dürfen die Steuerungsvariablen nur im Bereich 0-2 liegen, deswegen werden sie noch überprüft.

Das war die Steuerung der Spieler. Hier noch mal eine Zusammenfassung: Der Code gehört direkt unter das Malen der Seitenbegrenzung.

;...
;Seitenbegrenzung malen

;als erstes die Abfrage zur Steuerungsart
If KeyHit(2) Then sp1st=sp1st+1;die Zahlentaste 1
If KeyHit(3) Then sp2st=sp2st+1;die Zahlentaste 2

If sp1st>2 then sp1st=0
If sp2st>2 then sp2st=0

;die automatische Steuerung, wenn die Steuerungsvariable 0 ist:
If xsp1>xkugel And sp1st=0 Then xsp1=xsp1-beweglichkeit
If xsp1<xkugel And sp1st=0 Then xsp1=xsp1+beweglichkeit

If xsp2>xkugel And sp2st=0 Then xsp2=xsp2-beweglichkeit
If xsp2<xkugel And sp2st=0 Then xsp2=xsp2+beweglichkeit

;die Tastatursteuerung, wenn die Steuerungsvariable 1 ist:
If KeyDown(203) And sp1st=1 Then xsp1=xsp1-beweglichkeit;linke Pfeiltaste
If KeyDown(205) And sp1st=1 Then xsp1=xsp1+beweglichkeit;rechte Pfeiltaste

If KeyDown(44) And sp2st=1 Then xsp2=xsp2-beweglichkeit;Y Taste
If KeyDown(45) And sp2st=1 Then xsp2=xsp2+beweglichkeit;X Taste

;die Maussteuerung, wenn die Steuerungsvariable 2 ist:
If sp1st=2 Then xsp1=xsp1+MouseXSpeed()
If sp2st=2 then xsp2=xsp2+MouseXSpeed()

;die Überprüfung:
If xsp1<70 Then xsp1=70
If xsp1>xmax-70 Then xsp1=xmax-70
If xsp2<70 Then xsp2=70
If xsp2>xmax-70 Then xsp2=xmax-70

;...

Die Kugel[Bearbeiten]

Zu der Kugel brauch ich eigentlich nicht wirklich viel sagen.

Als erstes brauchen wir wieder ein paar Variablen: Diese können an die Variablen der Spieler angehangen werden.

Global xkugel# ;X-Pos. der Kugel als Kommazahl
Global ykugel# ;Y-Pos. der Kugel als Kommazahl
Global winkel  ;gibt den Flugwinkel der Kugel an 
Global geschwindigkeit ;die Fluggeschwindgikeit der Kugel

Wir haben die Koorodinaten der Kugel als Kommazahlen definiert, weil sich dadurch später eine weichere Bewegung ergibt.

Die eigentliche Bewegung:

Mithilfe der in Blitzbasic intigrierten Mathematik-Befehle lässt sich die Winkelbewegung mit Sinus und Cosinus recht einfach zusammenbauen.

Zu dem X und Y Koordinaten wird der Cosinus bzw. Sinus des Winkels addiert bzw. subtrahiert. Die Summe wird mit der Geschwindigkeit multipliziert.

xkugel=xkugel+Cos(winkel)*geschwindigkeit
ykugel=ykugel-Sin(winkel)*geschwindigkeit

Beispiel: Wenn xkugel 100, ykugel 90, der Winkel 120 und die Geschwindigkeit 3 wären, dann würde die Rechnung etwa so aussehen:

xkugel = 100 + (-0,5) * 3
ykugel = 90 - etwa (0,86) * 3

Die eigentliche Steuerung der Kugel wird ja nicht durch Tasten gemacht, sondern anhand von Kollisionen:

Die Kollisionsabfragen[Bearbeiten]

In diesem Kaptiel geht es eigentlich nur um das Steuern der Kugel. Zuerst müssen wir uns Überlegen, wo die Kugel überall kollidieren kann:

  • mit den Spielern
  • mit der Seitenbegrenzung

Damit es nicht zu kompliziert wird habe ich nicht überall echte Kollisionsabfragen eingebaut, deshalb fangen wir mit den Seitenwänden an:

Die Seitenwände[Bearbeiten]

Da die Seitenwänd ja immer an der gleichen Position sind, habe ich das ganze hier stark vereinfacht. Denn ich überprüfe nicht ob die Kugel mit der Wand kollidiert, sondern ob die Kugel einfach nur im Bereich ist, wo sie kollidieren müsste:

If xkugel<60 Then
 winkel=180-winkel ;damit prallt die Kugel ab
EndIf

If xkugel>xmax-60 Then
 winkel=180-winkel
EndIf

Wo kommt jetzt wieder die 60 her? Ganz einfach: Die Steine haben ja eine Breite von 50, die Kugel einen Radius von 10 Pixeln, das addiert ergibt 60.

Die Spieler[Bearbeiten]

Bei den Spielern können wir unseren Trick, wie bei den Seitenwänden, nicht anwenden. Trotzdem ist es hoffentlich nicht zu schwer:

If ImagesCollide(spieler1,xsp1,ymax-10,0,kugel,xkugel,ykugel,0) Then;wenn eine Kollision ist
 winkel=360-winkel ;prallt die Kugel ab
 abweichung=2*(xsp1-xkugel) ;damit kannst du die Richtung der Kugel steuern
 winkel=winkel+abweichung
EndIf

If ImagesCollide(spieler2,xsp2,10,0,kugel,xkugel,ykugel,0) Then
 winkel=360-winkel
 abweichung=2*(xsp2-xkugel)
 winkel=winkel-abweichung
EndIf

;damit der Winkel nicht über den Bereich von 0-360 geht:
If winkel>360 Then winkel=winkel-360
If winkel<0 Then winkel=winkel+360

Diese Steuerung must du nicht auf Anhieb verstehen, wie sie funktioniert, kannst du die am besten in der Praxis angucken und ausprobieren.

Wenn ein Spieler die Kugel durchgelassen hat[Bearbeiten]

...dann freut sich der andere!

Doch woher wissen wir ob er die Kugel durchgelassen hat? Mal wieder brauchen wir eine If Abfrage:

If ykugel<-10 Then ;oben
  fehlersp2=fehlersp2+1 ;der Obere bekommt einen Fehlerpunkt dazu
  resetkugel ;ein Funktionsaufruf
EndIf

If ykugel>ymax+10 Then ;unten
  fehlersp1=fehlersp1+1 ;der Untere bekommt einen Fehlerpunkt dazu
  resetkugel ;ein Funktionsaufruf
EndIf

Das ist schon alles! fehlersp1 und fehlersp2 sollen einfach nur der Fehler- oder Punktezähler sein. Es fehlt natürlich noch die Funktion "resetkugel":

Function resetkugel()
xkugel=xmax/2:ykugel=ymax/2
If Rand(0,1)=1 Then winkel=Rand(105,45) Else winkel=Rand(315,225);der Winkel wird durch Zufall ermittelt
End Function

Was zum Teufel soll das mit dem Winkel? Da hast du recht, das sieht irgendwie komisch aus. Ich könnte natürlich auch schreiben winkel=Rand(0,360), aber da existiert ein Unterschied: Bei der einfachen Version kann es vorkommen, dass die Kugel genau so nach links oder rechts fliegt, das sie nur zwischen den Seiten hin- und herprallt. Wenn das eben unverständlich war, dann probier das doch einfach mal aus, dann wirst du schnell wissen was ich meine.

So, jetzt haben wir eigentlich allen Code um alles zu bewegen und zu steuern. Es fehlen zwar noch ein paar Sachen, doch die sind nicht so lebenswichtig.

Deshalb kommt hier die erste Version des funktionstüchtigen Spiels:

Die erste spielbare Version[Bearbeiten]

Damit du eventuelle Fehler abfangen kannst, habe ich noch eine Rücksetzten Taste eingebaut, der Kommentar sollte als Erklärung reichen.

Graphics 1024,768,32,2 
SetBuffer BackBuffer() 
Global frametimer = CreateTimer(60) 
SeedRnd MilliSecs()

Global kugel=LoadImage("gfx\kugel.bmp");damit wird die Kugel in eine Variable geladen
MidHandle kugel ;der Urspung wird auf den Mittelpunkt gelegt, das macht sich bei Berechnungen besser
;auf das Einstellen der Tranzparenzfarbe kann verzichtet werden, weil sie Standard mäßig schwarz ist.

Global spieler1=LoadImage("gfx\pongspieler1.bmp");damit ist der Untere gemeint
MidHandle spieler1;auch dieser bekommt seine Ursprung in die Mitte (s.Kugel)
MaskImage spieler1,255,255,255;hier müssen wir die Tranzparenzfarbe angeben, weil sie vom Standard abweicht

Global spieler2=LoadImage("gfx\pongspieler2.bmp");damit ist der Obere gemeint
MidHandle spieler2;auch dieser bekommt seine Ursprung in die Mitte (s.Kugel)
MaskImage spieler2,255,255,255;hier müssen wir die Tranzparenzfarbe angeben, weil sie vom Standard abweicht

Global begrenzung=LoadImage("gfx\seitenwand.bmp");damit wird die Seitenwand geladen
MaskImage begrenzung,255,255,255;hier müssen wir die Tranzparenzfarbe angeben, weil sie vom Standard abweicht

Global xsp1=xmax/2;also in der Mitte
Global xsp2=xmax/2
Global sp1st
Global sp2st
Global xkugel#
Global ykugel#
Global winkel
Global geschwindigkeit=5 ;wird mit Wert zugewiesen, weil man sie (noch) nicht ändern kann
Global fehlersp1
Global fehlersp2
Global beweglichkeit


ClsColor 255,0,0;damit wird der Hintergrund rot, du kanst sonst die Spieler und Seitenwände nicht sehen

resetkugel;damit sie an der richtigen Position ist

Repeat
Waittimer (frametimer)

beweglichkeit=geschwindigkeit

For z2=0 To 1
 If  z2=1 Then x=xmax-50 Else x=0
 For z=0 To ymax/50
  DrawImage begrenzung,x,z*50
 Next
Next

If KeyHit(14) Then resetkugel;wenn die Löschen Taste gedrückt wurde wird die Kugel zurück gesetzt

;die Spielersteuerung
If KeyHit(2) Then sp1st=sp1st+1;die Zahlentaste 1
If KeyHit(3) Then sp2st=sp2st+1;die Zahlentaste 2

If sp1st>2 then sp1st=0
If sp2st>2 then sp2st=0

;die automatische Steuerung, wenn die Steuerungsvariable 0 ist:
If xsp1>xkugel And sp1st=0 Then xsp1=xsp1-beweglichkeit
If xsp1<xkugel And sp1st=0 Then xsp1=xsp1+beweglichkeit

If xsp2>xkugel And sp2st=0 Then xsp2=xsp2-beweglichkeit
If xsp2<xkugel And sp2st=0 Then xsp2=xsp2+beweglichkeit

;die Tastatursteuerung, wenn die Steuerungsvariable 1 ist:
If KeyDown(203) And sp1st=1 Then xsp1=xsp1-beweglichkeit;linke Pfeiltaste
If KeyDown(205) And sp1st=1 Then xsp1=xsp1+beweglichkeit;rechte Pfeiltaste

If KeyDown(44) And sp2st=1 Then xsp2=xsp2-beweglichkeit;Y Taste
If KeyDown(45) And sp2st=1 Then xsp2=xsp2+beweglichkeit;X Taste

;die Maussteuerung, wenn die Steuerungsvariable 2 ist:
If sp1st=2 Then xsp1=xsp1+MouseXSpeed()
If sp2st=2 then xsp2=xsp2+MouseXSpeed()

;die Überprüfung:
If xsp1<70 Then xsp1=70
If xsp1>xmax-70 Then xsp1=xmax-70
If xsp2<70 Then xsp2=70
If xsp2>xmax-70 Then xsp2=xmax-70

;die Kollisionsabfrage der Spieler
If ImagesCollide(spieler1,xsp1,ymax-10,0,kugel,xkugel,ykugel,0) Then;wenn eine Kollision ist
 winkel=360-winkel ;prallt die Kugel ab
 abweichung=2*(xsp1-xkugel) ;damit kannst du die Richtung der Kugel steuern
 winkel=winkel+abweichung
EndIf

If ImagesCollide(spieler2,xsp2,10,0,kugel,xkugel,ykugel,0) Then
 winkel=360-winkel
 abweichung=2*(xsp2-xkugel)
 winkel=winkel-abweichung
EndIf

;damit der Winkel nicht über den Bereich von 0-360 geht:
If winkel>360 Then winkel=winkel-360
If winkel<0 Then winkel=winkel+360


;Kollisionsabfrage Seitenwände
If xkugel<60 Then
 winkel=180-winkel ;damit prallt die Kugel ab
EndIf

If xkugel>xmax-60 Then
 winkel=180-winkel
EndIf

;wenn die Kugel durchgelassen wurde
If ykugel<-10 Then ;oben
 fehlersp2=fehlersp2+1 ;der Obere bekommt einen Fehlerpunkt dazu
 resetkugel ;ein Funktionsaufruf
EndIf

If ykugel>ymax+10 Then ;unten
  fehlersp1=fehlersp1+1 ;der Untere bekommt einen Fehlerpunkt dazu
  resetkugel ;ein Funktionsaufruf
EndIf



;das Berechnen der Kugelkoordinaten
xkugel=xkugel+Cos(winkel)*geschwindigkeit
ykugel=ykugel-Sin(winkel)*geschwindigkeit

;einige Informationen werden auf den Bildschirm gemalt
Text 200,300,"Geschwindigkeit:" + geschwindigkeit
Text 500,300,"Spielstand:  "+fehlersp2 + "       :       " + fehlersp1
;damit du die Steuerungsart sehen kannst
Text 55,ymax-25,"Spieler1" 
If sp1st>0 Then
	If sp1st=2 Then Text 120,ymax-25,"Maussteuerung" Else Text 120,ymax-25,"Tastatursteuerung"
	Else Text 120,ymax-25,"Computer"
EndIf
;If spieler1man>0 Then Text 250,ymax-25,scorep1

Text 55,5,"Spieler2" 
If sp2st>0 Then 
 If sp2st=2 Then
  Text 120,5,"Maussteuerung"
 Else
  Text 120,5,"Tastatursteuerung"
 Endif
Else
  Text 120,5,"Computer"
EndIf


DrawImage kugel,xkugel,ykugel;nur damit man sieht, das sie existiert
DrawImage spieler1,xsp1,ymax-10
DrawImage spieler2,xsp2,10

Flip ;da wir den Hintergrundpuffer aktiviert haben, wechseln wir jetzt die Seiten, damit wir was sehen
Cls ;der nichtsichtbare Bereich wird gelöscht
Until Keyhit(1)
End 

 
Function resetkugel()
xkugel=xmax/2:ykugel=ymax/2
If Rand(0,1)=1 Then winkel=Rand(105,45) Else winkel=Rand(315,225);der Winkel wird durch Zufall ermittelt
End Function

Damit kann man doch schon halbwegs spielen, oder? Natürlich gibt es noch einige Fehler und um ein komfortables Spielen zu ermöglichen fehlen noch ein paar Funktionen. Zuerst hatte ich eigentlich vor, den Quellcode weiter zu veröffentlichen, aber ich habe mich umentschlossen. Ich werde das Tutorial hier nicht mehr fortführen. Die Ideen für die Weiterentwicklung kannst du dann selbst umsetzen. Momentan programmiere ich eine 3d Version von Ping Pong. Diese werde ich dann als closed Code veröffentlichen.