Entwicklung und Betrieb von Websites, allgemeine Programmierung

[Guide] Pong = Browser-Spielep...

#890096 von DerSpieler
07.04.2012, 14:39
http://oi43.tinypic.com/amsadk.jpg

Einfache Browser-Spieleprogrammierung mit Javascript
(Keine Vorkenntnisse benötigt)

Link zum Ergebnis: PONG

0. Inhaltsverzeichnis

1. Einleitung
2. HTML-Einführung
3. Javascript-Einführung
4. Positionierung mit Javascript & jQuery
5. "Physik Simulation"
6. Bewegung von DIVs durch Tastatur
7. Vereinfachung zu Pong
8. Schmetterball
9. Nachwort


1. Einleitung

Wie ihr vom Banner ableiten könnt, geht es in diesem Guide nicht darum, wie man einen schönen Banner erstellt. Stattdessen wollte ich jedem Freund des virtuellen Tennis die Möglichkeit anbieten sich seinen eigenen kleinen Pong-Klon für den Webbrowser zu erstellen.
Mir wird sicherlich jeder zustimmen, dass Pong nicht unbedingt das Spiel ist, welches man den ganzen Tag lang spielen möchte, seht es darum einfach als ein simples Beispiel an, anhand dessen hier grundlegende Konzepte der Spieleprogrammierung erläutert werden sollen (dafür habe ich es nämlich ausgewählt).
Der Guide ist für absolute Anfänger geschrieben. Wer also bereits Kenntnisse in HTML oder sogar Javascript besitzt, kann sicherlich die ersten Kapitel überspringen. Sollte etwas unklar sein oder ihr sonst eine Frage haben zögert bitte nicht zu fragen (Beitrag hier oder PN). Dieser Guide ist nämlich sicherlich (noch) nicht perfekt und nur wenn mich jemand auf Hürden (oder sogar Fehler) aufmerksam macht, kann ich versuchen diese zu beseitigen. Ich hoffe ihr habt Spaß und lernt vielleicht noch was XD

2. HTML-Einführung

Ich sollte anmerken, dass wer diesen Guide gelesen hat sicherlich kein Experte für HTML sein wird. Es werden lediglich die für das Spiel unbedingt notwendigen Kenntnisse besprochen. Für das umfassende Erlernen von HTML gibt es zahlreiche Guides im Internet, die sich besser eignen als dieser (Google ist dein Freund).
Es sei noch erwähnt, dass für HTML, Javascript usw. keine extra Software installiert werden muss.

2.1 Die HTML-Datei
Egal welchen Browser ihr verwendet, was er vom Webserver erhält, wenn ihr beispielsweise "www.pokefans.net" eingegeben habt, ist ein einfaches Textdokument. Erst der Browser (z.B. Internetexplorer oder Firefox) macht aus den Textzeilen "bunte Kästen", Bilder usw.
Damit der Browser weiß, was er machen soll, werden in den Textdateien sog. HTML-Tags (oder kurz nur "Tags") verwendet. Diese speziellen Textblöcke werden vom Browser nicht als "Text", sondern als "Anweisung" interpretiert.
Um das zu verdeutlichen erstellen wir nun unsere erste HTML-Datei. Legt am besten einen neuen Ordner mit dem Namen "pong" o.ä. an (neue Ordner erstellen könnt ihr oder?).Als nächstes öffnet ihr den "Texteditor" (nicht "Word" o.ä.). Diesen Editor findet man in der Regel (bei Windows) unter "Start/Programme/Zubehör" (siehe Bild rechts)
Nach einem Klick sollte dieser sich öffnen und ein leeres "Textfeld" sollte sich vor euch auftun.
Hier tippt ihr nun folgenden Text ein:
Code: Alles auswählen<html>
   <body>
      Hallo, Ich bin ein HTML-File!
   </body>
</html>

Anschließend speichert ihr die Datei unter dem Namen "pong.html" in dem vorher angelegten Ordner ab. Achtung! Bei Windows Vista und 7 wird der Dateityp auf diese Weise leider nicht angepasst. Ihr müsst darum die Ansichteinstellungen ändern. Dazu öffnet ihr den Pong-Ordner und klickt in der linken oberen Ecke auf "Organisieren" und im erscheinenden Menü auf "Ordern- und Suchoptionen".


Im Untermenü wählt ihr dann das "Ansicht" Tab aus und entfernt das Häckchen bei "Erweiterungen bei bekannten Dateitypen ausblenden". (Keine Angst, dieses Vorgehen ist zum Glück nur einmalig notwendig)


Von nun an könnt ihr wie oben beschrieben HTML-Dateien erstellen. Solltet ihr die Datei bereits erstellt haben und diese nun den Namen "pong.txt", "pong.html.txt" o.ä. tragen, so müsst ihr diese jetzt in "pong.html" umbennennen.
Es erscheint in der Regel eine Warnung, dass sich dadurch der Dateityp ändert usw. - Das ist ja genau das was wir bezwecken, nämlich eine ".txt" Datei zu einer ".html" Datei zu machen. Wie ihr bemerkt haben solltet handelt es sich nur um eine Umbennennung. Der Inhalt der Datei ändert sich also nicht. Der Grund ist einfach, dass dein Browser die erwähnten HTML-Tags nur dann als solche erkennt, wenn die Datei die Endung ".html" hat.

Unser Werk kann nun also im Browser betrachtet werden. Dazu sollte nun ein einfacher Doppelklick auf die erstellte Datei genügen.
Es sollte sich der Standard-Internetbrowser öffnen. Die aufgerufene "Web-Seite" sollte den Schriftzug "Hallo, Ich bin ein HTML-File!" zeigen.

2.2 HTML-Tags
Euch ist sicherlich aufgefallen, dass der Browser beim Anzeigen der Datei alles ignoriert hat, dass zwischen "<" und ">" steht. Dies sind nämlich die oben angesprochenen (HTML-)Tags. Wie bereits gesagt werden diese nicht als einfacher Text inperpretiert - haben also andere Funktionen.
Die hier verwendeten Tags sind "html" und "body". Das "html"-Tag (nicht zu verwechseln mit dem HTML-Tag :-)) teilt dem Browser erneut mit, dass er den folgenden Text als HTML-Code interpretieren soll. Das "body"-Tag steht für den sichtbaren Inhalt der Seite (tieferes Verständnis dafür ist für diesen Guide nicht erforderlich).
Da in diesem Guide alles in die Kategorie des "sichtbaren" Inhalts fällt, wird alles "in" dieses Tag geschrieben. Was dieses "in" bedeutet wird gleich klar.
Allgemein bestehen Tags nämlich aus 3 Teilen. Da wäre das "Anfangs-Tag" wie beispielsweise <html> oder <body>, dann der "Inhalt" (bestehend aus Text und/oder weiteren Tags) und das "End-Tag" z.B. </html> oder </body>.
Wie ihr in unserem Beispiel sehen könnt wird dies wie folgt angewandt: <Anfangstag> Inhalt <Endtag>, wobei das "Endtag" sich vom Anfangstag stets durch ein Slash also ein "/" vor dem Wort unterscheidet.
Konkret ist der Inhalt des "Body"-Tags also der Text
Code: Alles auswählenHallo, Ich bin ein HTML-File!
.
Der Inhalt des "html"-Tags ist hingegen folgendes:
Code: Alles auswählen<body>
      Hallo, Ich bin ein HTML-File!
   </body>

Ihr seht also, dass zum Inhalt eines Tags auch weitere Tags gehören können.

2.3 Das "DIV"-Element
Das für diesen Guide elementarste Tag ist das "div"-Tag. Der Begriff "DIV" steht für "Division" also zu deutsch "Teilung". Es wird benutzt um die Seite in verschiedene Bereiche zu unterteilen. Ich persönlich stelle mir ein DIV immer als eine Box vor, die ich nach bestimmten Regeln auf der Seite verteilen kann.
Der Inhalt eines DIVs kann wieder aus verschiedenen anderen Tags und/oder Text bestehen. Insbesondere kann der Inhalt von DIVs auch weitere DIVs beinhalten. Die Abfolge sollte klar sein:
Code: Alles auswählen<div>
   Inhalt des DIV
</div>
...oder bei verschachtelten DIVs (also mehreren DIVs ineinander)
Code: Alles auswählen<div>
   Inhalt DIV 1
   <div>
      Inhalt DIV 2
   </div>
</div>
Für unser Spiel erstellen wir nun unser erstes DIV (wie gesagt wird bei uns alles in das Body-Tag geschrieben). Mit dem neuen DIV sollte unser Code nun so aussehen:
Code: Alles auswählen<html>
   <body>
      <div>
   
      </div>
   </body>
</html>

Damit wir das DIV später noch identifizieren können, geben wir diesem eine Bezeichnung, eine sog. "ID" (Der Grund dafür wird sich später erschließen). Diese ID wird innerhalb der "<" und ">", nach dem Wort "div" getrennt wurde ein Leerzeichen geschrieben.
Dort schreiben wir das Wort "id" dann ein Gleichheitszeichen "=" und letztlich die gewünschte Bezeichnung in Anführungszeichen. Die Bezeichnung meiner Wahl ist aus offensichtlichen Gründen "spielfeld". Der Code sollte nun wie folgt aussehen:
Code: Alles auswählen<html>
   <body>
      <div id="spielfeld">
   
      </div>
   </body>
</html>
(im Folgenden werde ich auf die <body> und <html> Tags wegen der Übersichtlichkeit verzichten - es sollte klar sein, dass der folgende Code immer im body-Tag steht).

2.4 Die "Style"-Option
Öffnet man nun die Datei im Browser so fällt auf, dass wir nichts sehen können. Der Grund dafür ist, dass DIVs ohne jegliche Angabe eine Höhe und Breite von 0 haben und zu allem Überfluss auch noch transparent sind. Im folgenden Abschnitt werden wir also lernen, wie man derartige Parameter eines DIVs festlegen kann.
Hierzu wird die sogenannte Style-Option verwendet (an die Profis: Ich werde hier wegen der Einfachheit nur auf Inline-Style eingehen). Diese "Style"-Option wird analog zur "id" innerhalb der "<", ">" und durch Leerzeichen zu den anderen Optionen getrennt geschrieben. In unserem Fall sieht das so aus:
Code: Alles auswählen<div id="spielfeld" style="">
   
</div>
Innerhalb der Anführungszeichen nach dem "style=" werden nun die Angaben zum Style (frei übersetzt "Aussehen") des DIVs geschrieben. Da wir erneut keine Angaben gemacht habe, sollte im Browser immernoch nichts zu sehen sein.
(Für die Interessierten: Die Style-Angeben werden im sog. CSS-Syntax geschrieben. Auch auf CSS werde ich nicht erschöpfend eingehen und verweise erneut auf vielfältige Internettutorials). Das Spielfeld soll eine Breite von 800 Pixeln und eine Höhe von 600 Pixeln haben. Für den Hintergrund wollen wir die Farbe "grün" verwenden.
Für den Code bedeutet das:
Code: Alles auswählen<div id="spielfeld" style="width:800px; height:600px; background-color:green;">
   
</div>
Mit etwas gesundem Menschenverstand und rudimentären Englischkenntnissen sollte ungefähr klar sein, wie das Style funktioniert. Zuerst kommt der Name des Parameters, den man setzen möchte (z.B. "width" = Englisch für "Breite"). Anschließend folgt ein Doppelpunkt (":") dann der Wert auf den der Parameter gesetzt werden soll (z.B. 800px - px = Abkürzung für Pixel). Zum Schluss wird der Ausdruck durch einen Strichpunkt ";" beendet.
Nach diesem Schema können innerhalb der Style-Option beliebig viele Parameter gesetzt werden (die Reihenfolge ist in der Regel egal). Wird die Datei nun im Browser geöffnet, sollte ein großes grünes Feld zu sehen sein. Es gibt neben "width", "height" und "background-color" noch zahlreiche weitere Parameter, die auf diese Weise gesetzt werden können. Im Laufe dieses Guides werden später nach und nach noch einige davon erläutert werden.

2.5 Bilder
Ein weiteres HTML-Tag, das in diesem Guide verwendet wird sind Bilder. Das zugehörige Tag heißt "<img>" (kurz für "Image"). Die Funktionsweise ist zum größten Teil mit der von DIVs identisch. Die einzige Ausnahme ist, dass ein Bild eine weitere Option besitzt, in welcher der Name (oder genauer der Dateipfad) des angezeigten Bildes gespeichert wird.
Dies Option hat den Namen "src" (kurz für "Source" also Englisch für "Quelle"). Ein Beispiel schafft hier sicherlich Klarheit:
Code: Alles auswählen<img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px;" ></img>

<div id="spielfeld" style="width:800px; height:600px; background-color:green;">
   
</div>
Dem Bild wurde die Bezeichnung (bzw. ID) "banner" zugewiesen. Als Dateipfad wurde ein im Internet gespeichertes Bild angegeben (mein Banner, den ich bei einem Free-Image-Hoster hochgeladen habe). Hier könnte alternativ auch der Pfad zu einem auf eurem Computer gespeicherten Bild stehen.
Außerdem wurde dem Bild (vollkommen analog zum DIV) über die Style-Option eine bestimmte Breite gegeben. Die Seite sollte nun etwa so aussehen:


2.6 Positionierung
Die letzte wichtige Eigenschaft, die besprochen werden muss ist die Positionierung von Bildern und DIVs über die Style-Option. Hierbei wird zunächst der Typ der Positionierung ausgewählt. Die beiden hier verwendeten Varianten sind "Absolute" und "Relative" Positionierung.
Wie man beim derzeitigen Stand der Seite deutlich erkennen kann, wurde das Spielfeld automatisch unter das Banner-Bild platziert. Aus offensichtlichen Gründen möchte man diese Position bei einem Computerspiel jedoch gern eigenhändig und präzise auswählen. Die erste Möglichkeit ist das "relative" Positionieren.
Dabei wird ein Bild oder DIV relativ zu seiner automatischen Position positioniert. Bewegen wir also zur Übung den Banner ein paar Pixel nach rechts. Wie bereits angedeutet wird hierfür die Style-Option verwendet. Erst der Code, dann die Erklärung:
Code: Alles auswählen<img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>

<div id="spielfeld" style="width:800px; height:600px; background-color:green;">
   
</div>
Wird die Datei nun im Browser geöffnet, sollte sich der Banner 100 Pixel nach rechts bewegt haben (auch wenn "left" vielleicht etwas irritierend sein mag). Also was haben wir gerade getan? Zuerst wurde innerhalb der Style-Option der Parameter "position" auf den Wert "relative" gesetzt.
Nun weiß der Browser, dass er dieses Bild nach der Regel "relative" platzieren soll. Danach wurde der Parameter "left" auf 100 Pixel gesetzt. Der Parameter heißt hierbei "left", da es um den Abstand zum linken Rand der ursprünglichen Position geht. Das Prinzip soll durch die Abbildung unten verdeutlicht werden.

Die zweite Regel zur Positionierung, die hier angesprochen wird ist das absolute Positionieren. Hierbei werden absolute Werte (sozusagen Koordinaten) für das Bild oder DIV angegeben und dieses dann entsprechend auf dem Bildschirm platziert.
Die Abbildung unten soll das etwas ungewöhnliche Koordinatensystem verdeutlichen, dass hierbei verwendet wird.

Es ist hierbei allerdings gelegentlich von Vorteil, wenn der Nullpunkt des Koordinatensystems nicht die obere Ecke der Seite ist, sondern beispielsweise die linke oberen Ecke des übergeordneten DIVs. Es wird daher (automatisch) stets die oberen linke Ecke des nächsten übergeordneten DIVs genommen, dessen eigene Positionierung als "relative" oder "absolute" definiert ist.
Da unser Spiel Komplett innerhalb des Spielfeld-DIVs ablaufen soll und es darum von Vorteil ist dessen Ecke als Nullpunkt zu definieren, müssen wir dieses also nach der Regel "relative" oder "absolute" Positionieren. Da wir mit der automatischen Position allerdings sehr zufrieden sind, wird ein kleiner Trick verwendet. Wir setzen die Positionierungsregel auf "relative" verschieben es allerdings um 0 Pixel d.h. effektiv bleibt das DIV an seinem Platz.
Der Neue Code:
Code: Alles auswählen<img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>

<div id="spielfeld" style="width:800px; height:600px; background-color:green; position:relative;">
   <div style="width: 25px; height:25px; background-color:red; position:absolute; left:100px; top:100px;"></div>
   
</div>
Die Positionierungs-Regel der Spielfeld-DIV wurde auf "relative" gesetzt und keine Angaben zur Verschiebung gemacht (Standardwert ist 0). Außerdem wurde zum testen der absoluten Positionierung ein kleines rotes DIV innerhalb des Spielfelds erstellt.
Die Parameter "left" und "top" sind so gewählt worden, dass sich das DIV 100px vom oberen und 100px vom linken Rand des Spielfelds entfernt liegt. Die Seite sollte nun folgendermaßen aussehen:

Da besonders das absolute Positionieren für den weiteren Verlauf des Guides von großer Wichtigkeit sind, wird empfohlen mit den Parameterb "left" und "top" etwas zu spielen, um ein gutes Verständnis dafür zu bekommen.

3. Javascript-Einführung

Mit reinem HTML kann man sicherlich hübsche Seiten erstellen. Das Problem an der Sache ist, dass sich mit reinem HTML keine dynamischen Abläufe z.B. Bewegungen realisiert werden können. Gerade für ein Spiel ist eine Bewegung aber offensichtlich von elementarer Wichtigkeit.
Eine Möglichkeit Dynamik in die Seite zu bringen ist das sog. "Javascript" (eine Alternative wäre z.B. "Flash"). Bevor man sich jedoch daran wagen kann DIVs und Bilder über den Bildschirm flitzen zu lassen, muss zunächst das Grundkonzept des Javascrpt klar sein.
Jeder mit etwas Programmiererfahrung sollte kein Problem damit haben in wenigen Minuten die Grundzüge von Javascript zu erlernen. Für die Programmier-Neulinge wird es vermutlich etwas länger dauern. Es wird aber versucht auch dem absoluten Anfänger die Grundzüge des Programmierens hier zu erläutern.
Es sei dennoch wiederrum gesagt, dass es sicherlich umfangreichere Guides zum Thema "Javascript" im Internet gibt. Hier wird hier lediglich versucht jeden Leser auf einen Stand zu bringen, dass er dem Guide eigenmächtig folgen kann.

3.1 Das Script-Tag
Zunächst mal muss dem Browser klar gemacht werden, dass der den folgenden Text als Javascript interpretieren soll (also nicht als Text oder HTML). Das zugehörige HTML Tag ist "<script>". Da es theoretisch verschiedene Skripte geben kann, wird stets ein Parameter gesetzt, der sich "type" nennt.
Ein Beispiel sollte Klarheit schaffen. Unsere HTML-Datei sollte so aussehen:
Code: Alles auswählen<html>
   <body>
   <script type="text/javascript">
      
      // Hier kommt der Javascript-Code rein!
      
   </script>
   
   <img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>
   
   <div id="spielfeld" style="width:800px; height:600px; background-color:green; position:relative;">
      <div style="width: 25px; height:25px; background-color:red; position:absolute; left:100px; top:100px;"></div>
   </div>

   </body>
</html>
Alles was im folgenden Kapitel 2 beschrieben wird, sollte an die oben markierte Stelle geschrieben werden.

3.2 Die "Alert" Funktion
Um die später erstellten Programme auf ihre Funktionalität zu testen, benötigen wir eine logischerweise eine Art "Output". Der Computer muss also irgendwie Informationen an uns übermitteln können.
Die einfachste Methode stellt die "Alert" Funktion da. Folgender Code soll in das Skript-Tag geschrieben werden.
Code: Alles auswählen   alert("Hallo Benutzer!");

Wenn anschließend die Seite im Browser geöffnet wird, sollte ein Fenster mit der Aufschrift "Hallo Benutzer!" erscheinen. Dies ist die Funktionsweise dieser Funktion. Alle was zwischen den Klammern steht wird in diesem Fenster ausgegeben.
Was genau eine "Funktion" überhaupt ist und warum der Text stets in Anführungszeichen stehen muss wird später noch erklärt, wichtig ist zunächst lediglich, dass der Computer Kontakt zu uns aufnehmen kann. Ein elementares Prinzip des Programmierens lernen wir kennen, wenn wir folgenden Code eingeben:
Code: Alles auswählen   alert("Hallo Benutzer!");
   alert("Pokefans ist klasse!");

Wird die Seite nun im Browser geöffnet, erscheint zuerst das bekannte "Hallo Benutzer!" und anschließend das "Pokefans ist klasse!". Der Browser liest also in der Regel eine Zeile nach der anderen.

3.3 Taschenrechner
Was können Computer (auch "Rechner" genannt) besonders gut? Richtig! Die Antwort lautet "rechnen". Wie in allen mir bekannten Programmiersprachen, so sind auch beim Javascript die Grundrechenarten denkbar einfach zu gebrauchen.
Um zwei Zahlen zu addieren verwendet man ein Plus "+", für Subtraktion ein Minus "-", für die Multiplikation ein Stern "*", für die Division ein Slash "/". Außerdem gelten die (hoffentlich) aus dem Matheunterricht bekannten Punkt vor Strich- und Klammerregeln.
Versucht folgenden Code:
Code: Alles auswählen   alert(1+1-5);
   alert(3+5*2);
   alert(2*(3+6)/3);
Die Ausgabe sollte -3, 13 und 6 sein. Im Prinzip haben wir jetzt einen primitiven Taschenrechner programmiert (Auch wenn zumindest bei meinem Rechner dir Tasche sehr groß sein müsste).

3.4 Variablen
Innerhalb des Codes ergibt sich oft die Notwendigkeit Informationen (z.B. eine Zahl) zur späteren Verwendung zu speichern. Hierzu gibt man diesen Daten einen beliebigen Namen und verwendet das Gleichheitszeichen "=".
Angenommen wir wollen z.B. die 13er Reihe ausgeben. Nun könnten wir folgenden Code verwenden.
Code: Alles auswählen   alert(1*13);
   alert(2*13);
   alert(3*13);
   ...
Speichern wir die Zahl 13 unter dem Namen "a", ersparen wir uns schon eine Menge Arbeit (das Wort "var" vor dem Namen steht für "variable" und zeigt dem Browser, dass es sich im folgenden um eine Solche handelt):
Code: Alles auswählen   var a = 13;
   alert(1*a);
   alert(2*a);
   alert(3*a);
   ...
Um die gespeicherten Daten wieder abzurufen, verwendet man an der gewünschten Stelle einfach deren Namen. Der Browser wird also bei seiner Interpretation stets das "a" durch die Zahl 13 ersetzen.
Man kann Variablen nicht nur innerhalb von Rechnungen verwenden, sondern auch das Ergebnis einer Rechnung (was ja wieder eine Zahl ist) in einer Variable speichern.
Code: Alles auswählen   var a = 2+5;
   alert(a);
Die Ausgabe sollte hier "7" lauten. Verwendet man den Namen ein weiters mal, so wird der Inhalt überschrieben (der vorherige Inhalt geht also verlorern). Der folgende Code:
Code: Alles auswählen   var a = 3;
   a = 500;
   alert(a);
liefert also das Ergebnis 500. Es sei auch angemerkt, dass bei einer bereits vorher erstellten Variable, das Wort "var" nicht erneut verwendet werden muss (es würde aber auch nicht schaden). Verwendet man die beide soeben genannten Eigenschaften, kann unser 13er-Reihen Programm verbessert werden:
Code: Alles auswählen   var a = 0;
   a = a+13;
   alert(a);
   a = a+13;
   alert(a);
   a = a+13;
   alert(a);
   ...
Hierbei wird die Variable "a" immer um 13 erhöht. Während der Rechnung "a+13" wird also der "alte" Wert von "a" verwendet. Unter Verwendung der "Kopieren & Einfügen"-Funktion ersparen wir uns so schon eine Menge Arbeit.

3.5 Text in Variablen
Neben Zahlen möchte man relativ oft Informationen in Form von Text speichern. Damit der Browser den im Code verwendeten Text als Text und nicht z.B. als Variablenname oder Zahl interpretiert, muss der Text in Anführungszeichen " oder ' geschrieben werden.
Speichern wir z.B. das Wort "Pokefans" in einer Variable:
Code: Alles auswählen   var b = "Pokefans";
   alert(b);
innerhalb der Anführungszeichen werden natürlich auch Symbole wie "+" oder "=" als Text interpretiert.
Auch Texte kann man in Javascript addieren. In diesem Fall werden die beiden Texte zu einem großen Text zusammengefasst:
Code: Alles auswählen   var b = "Pokefans";
   var c = " ist klasse!";
   alert(b+c);


3.6 Listen
Es ist häufig sinnvoll ähnliche Daten in einem einzigen übergeordneten Namen zu speichern wobei man den einzelnen Daten zur Identifikation eine eindeutige Zahl oder einen Text zuordnet. Vielleicht erscheint das im Moment unnötig kompliziert oder verwirrend. Ein Beispiel verdeutlicht hoffentlich die Idee:
Es werden z.B. die Namen von Pokemon unter ihrer Nummer in einer Liste gespeichert:
Code: Alles auswählen   var pokemon = [];
   pokemon[1] = "Bisasam";
   pokemon[2] = "Bisaknosp";
   pokemon[3] = "Bisaflor";
   pokemon[25] = "Pikachu";
   alert(pokemon[3]);
   alert(pokemon[25]);
In der ersten Zeile wird hier eine neue Liste unter dem Namen "pokemon" erstellt. Hierzu werden zwei eckige Klammern "[" und "]" verwendet. Danach wird unter der Nummer 1, 2 und 3 die Entwicklungen von Bisasam gespeichert (und unter 25 Pikachu). Anschließend wird der Eintrag an der Stelle 3 und der Stelle 25 ausgegeben.
Beim Ausführen sollte also "Bisaflor" und "Pikachu" erscheinen (An Stelle der Zahlen hätte natürlich auch Text verwendet werden können).

3.7 Verzweigung
Bisher wurde jedes Programm vom Browser stets Zeile für Zeile komplett durchgearbeitet. Es ist aber oft sinnvoll, einige Abschnitte des Codes nur unter bestimmten Bedingungenen auszuführen. Hierzu werden die sog. Verzweigungen verwendet.
Betrachten wir folgenden Code:
Code: Alles auswählen   var x = 15;
   if( x < 10){
      alert( "x ist kleiner als 10" );
   }else{
      alert( "x ist nicht kleiner als 10" );
   }
In der ersten Zeile wird eine Variable mit dem Namen x auf 15 gesetzt. Dann folgt ein Ausdruck "if( x < 10 )". "if" ist das englische Wort für "wenn". Der Ausdruck in den Klammern dahinter stellt die Bedingungen da "x < 10" gelesen: "x kleiner als 10".
Danach folgt innerhalb von geschweiften Klammern "{" und "}" ein bekannter Code. Es folgt das Wort "else" was englisch für "sonst" bedeutet. Dann Wieder bekannter Code innerhalb von geschweiften Klammern. Übersetzt haben wir also:
"wenn x kleiner als 10 { ..code1...} sonst { ...code2... }". Der Browser wird hier den "code1" ausführen, falls x kleiner als 10 ist sonst den "code2". Da wir in x die Zahl 15 gespeichert haben wird die Ausgabe als nur "x ist nicht kleiner als 10" lauten.
Der Abschnitt mit dem "else" ist hierbei nur optional. Folgendes wäre auch funktionsfähiger Javascript Code:
Code: Alles auswählen   var x = 15;
   if( x < 10){
      alert( "x ist kleiner als 10" );
   }
Hier würde natürlich keine Ausgabe erfolgen. Innerhalb der Klammern nach dem "if" können auch verschiedene Bedingungen verknüpft werden. Hierbei werden zwei elementare Typen unterschieden. Due "und"-Verknüpfung und die "oder"-Verknüpfung.
Folgender Code soll das "und" verdeutlichen:
Code: Alles auswählen   var x = 7;
   if( x < 10 && x > 5){
      alert( "x ist zwischen 5 und 10." );
   }
Die beiden "&" stehen für die "und"-Verknüpfung. Übersetzt man den Code erhält man: "wenn x kleiner 10 und x größer als 5". Der Code wird also nur dann ausgeführt, wenn beide Bedingungen erfüllt sind.
Folgender Code soll das "oder" verdeutlichen:
Code: Alles auswählen   var x = 7;
   if( x < 10 || x > 100){
      alert( "Hallo!" );
   }
Die beiden "|" stehen für "oder". Übersetzt bedeutet der Code: "wenn x kleiner 10 oder x größer als 100". Der Code wird dann ausgeführt, wenn mindestens eine der beiden Bedingungen erfüllt ist.
Neben der "<" und ">", die wir bisher verwendet haben gibt es noch ander Operatoren, die in einer Bedingung verwender werden können. Hier eine Liste:
SymbolOperator
>größer
<kleiner
<=Kleiner oder Gleiche
>=Größer oder Gleich
==Gleich
!=Ungleich

Der "==" und "!=" können auch für Text verwendet werden:
Code: Alles auswählen   var name = "Glumanda";
   if( name == "Glumanda" ){
      alert( "Der Name ist Glumanda!" );
   }
Der Code oben überprüft, ob in der Variable der Text "Glumanda" gespeichert wurde.

3.8 Schleifen
Erinnern wir uns zurück zu unserem Programm zur Auflistung der 13er-Reihe. Wir mussten häufig sehr ähnliche Zeilen schreiben. Da ähnliche Aufgaben beim Programmieren auftreten, gibt es für solche Wiederholungen sog. Schleifen.
Folgender Code listet die 13er-Reihe auf:
Code: Alles auswählen   var i = 0;
   while(i <= 10){
      alert(i*13);
      i = i + 1;
   }
Die erste Zeile ist relativ klar. Es wird eine Variable mit dem Namen i erstellt und mit dem Wert 0 gefüllt. Dann folgt ein Abschnitt, der dem oben besprochenen "if" ähnelt. Nur das in diesem Fall ein "while" Englisch für "solange" vor der Bedingungen steht.
Übersetzt lautet der Code also: "solange i kleiner oder gleich 10 { code }". Der Code innerhalb der geschweiften Klammern wird hier also solange ausgeführt, wie die Bedingungen "i <= 10" erfüllt ist. Es ist offensichtlich, dass i innerhalb dieses Bereichs verändert werden muss, damit die Bedingungen irgendwann nichtmehr erfüllt ist und das Programm beendet werden kann.
Dies passiert in der Zeile "i = i+1;". Hier wird der Inhalt der Variable i um 1 erhöht. Der Code wird in diesem Beispiel also 11-mal durchlaufen, bis i die Bedingungen "i <= 10" nichtmehr erfüllt. Da i bei jedem dieser Durchläufe um 1 erhöht wird, erscheint beim Aufruf des Programms die 13er-Reihe auf dem Bildschirm. Es ist wohl unbestreitbar, dass dieses Programm Unmengen an Arbeit spart. Insbesondere, wenn man bedenkt, dass man nur die Zahl "10" in der Bedingungen erhöhen muss um die Reihe beliebig weit auszugeben.
Die Bedingungen in einer solchen Schleife kann beliebig (wie beim "if") gewählt werden. Auch Kombinationen mit "und" und/oder "oder" sind möglich. Das Zählen (wie wir es benutzt haben) innerhalb einer solchen Schleife kommt beim Programmieren allerdings derart häufig vor, dass eine verkürzte Schreibweise existiert:
Code: Alles auswählen   for(var i=0 ; i <= 10 ; i=i+1){
      alert(i*13);
   }
Dieser Code hat die gleiche Bedeutung wie der Code oben. Auch unser Pokemon-Beispiel sollten wir uns ins Gedächtnis rufen. Folgender Code gibt die Namen der Pokemon aus:
Code: Alles auswählen   pokemon = [];
   pokemon[0] = "Missingno";
   pokemon[1] = "Bisasam";
   pokemon[2] = "Bisaknosp";
   pokemon[3] = "Bisaflor";
   pokemon[4] = "Glumanda";
   for(var i=0 ; i <= 4 ; i=i+1){
      alert( pokemon[i] );
   }
Nun wird auch der Vorteil der Liste gegenüber einzelner Variablen klar. Da sich alle Einträge über Nummern abrufen lassen, kann in einer solchen Schleife einfach eine Operation für jedes Element der Liste durchgeführt werden.

3.9 Funktionen
Das letzte Kapitel sind Funktionen (gelegentlich auch Methoden genannt). Es handelt sich dabei um vorgefertigte Codeabschnitte, die häufig benötigt werden und darum unter einem bestimmten Namen gespeichert werden.
Erstellen wir z.B. eine Formel, die den Maximalschaden einer Pokemon Attacke ausrechnet. Es ist offensichtlich, dass diese Berechnung z.B. im Laufe eines Pokemonkampfes häufig verwendet werden wird und darum eine sinnvolle Funktion in einem hypothetischen Kampfsimulator darstellt.
Folgender Code stellt eine solche Funktion da:
Code: Alles auswählen   function schaden(ang,ver,level,atk_base){
      var dmg = (2*level/5+2)*atk_base*ang/50/ver+2;
      return dmg;
   }
Das Wort "function" sagt dem Browser, dass es sich im folgenden um die Definition einer neuen Funktion handelt. Alles zwischen den geschweiften Klammern gehört dann zum Inhalt der Funktion.
In der Klammer hinter dem Namen der Funktion für den "schaden" gewählt wurde, stehen die (optionalen) Parameter der Funktion. Damit sind Variablen gemeint, die beim ausführen der Funktion jedesmal neu gewählt werden können. Diese sind in unserem Beispiel deswegen sinnvoll, da der Schaden einer Attacke natürlich vom Angriff des Angreifers und der Verteidigung des Verteidigers abhängen.
Da die Funktion den Schaden allgemein (für beliebige Pokemon) ausrechnen soll, muss der Funktion also beim Aufruf mitgeteilt werden, wie hoch diese Werte sind.
Zum Inhalt der Funktion:
In der ersten Zeile innerhalb der Funktion wird aus Angriff, Verteidigung, Level und der Basisstärke der verwendeten Attacke der Schaden berechnet und in der Variable "dmg" gespeichert. In der folgenden Zeile ist das Wort "return" zu erkennen, was frei übersetzt "zurückgeben" bedeutet.
Wird die Funktion innerhalb des Programms aufgerufen wird diese durch den Wert hinter dem "return" ersetzt. In diesem Fall also durch das Endergebnis der Schadensberechnung. Möglicherweise sind die Eigenschaften von Funktionen im Moment noch nicht ganz klar darum ein Beispiel:
Code: Alles auswählen   function schaden(ang,ver,level,atk_base){
      var dmg = (2*level/5+2)*atk_base*ang/50/ver+2;
      return dmg;
   }
   
   alert( schaden(350,500,100,100) );
   alert( schaden(150,500,100,30) );
Es wird zweimal die Funktion "schaden" aufgerufen. Allerdings mit verschiedenen Werten in den Parametern. Im ersten Fall wird eine Angriff von 350 und eine Verteidigung von 500 angenommen. Als Basis-Schaden der Attacke wird 100 angenommen. Es könnte sich z.B. um ein Machomei handeln. dass Erdbeben gegen ein Pottrott einsetzt.
Im zweiten Fall wird eine Angriff von 150 und eine Basis-Schaden von 30 angenommen. Es könnte sich um ein Bisasam handeln, welches Tackle gegen das gleiche Potrott verwendet. In beiden Fällen wird die Funktion vom Browser durch das Ergebnis der jeweiligen Rechnung ersetzt.
Das "return" am Ende der Funktionsdefinition ist optional. Wenn die Funktion in ihrem Inhalt beispielsweise das Ergebnis der Rechnung über Alert aufruft, erhält man das gleiche Ergebnis:
Code: Alles auswählen   function schaden(ang,ver,level,atk_base){
      var dmg = (2*level/5+2)*atk_base*ang/50/ver+2;
      alert(dmg);
   }
   
   schaden(350,500,100,100);
   schaden(150,500,100,30);
Welche der Varianten besser ist, hängt vom jeweiligen Programm ab. Soll beispielsweise mit dem Ergebnis aus der Funktion noch weiter gerechnet werden, ist es beispielsweise sinnvoll eine Funktion mit "return" zu verwenden, da die alternative ihr Ergebnis nicht zur Verfügung stellt.

4. Positionierung mit Javascript & jQuery

An dieser Stelle solltet ihr euch bereits etwas mit Javascript und HTML beschäftigt haben. Wenn euch dar Mini-Guide hier nicht ausreichen (was wegen dessen Kürze sicherlich keine Schande wäre), empfehle ich einen Guide im Internet zu suchen und durchzuarbeiten.
Das Vorwissen aus diesem Guide sollte in einem solchen Fall zumindest ausreichen, damit ein solcher Guide in wenigen Stunden zu absolvieren ist. Wer es nur mit den Kenntnissen aus dem Mini-Guide versuchen möchte, dem steht dies natürlich frei. Ich würde mich interessieren, ob es tatsächlich jemand schafft auf diese Weise dem gesamten Guide zu folgen.

4.1 Bibliothek einbinden
Für die meisten Probleme die man so hat, gibt es im Internet bereits eine intelligente Lösung. Es ist also besonders bei komplexen Wünschen an den Code oft von Vorteil im Internet nach einer Codesammlung (Bibliothek genannt) zu suchen, die möglicherweise diesen Anforderungen gerecht wird.
Ihr solltet aber natürlich auch immer überlegen, ob euer Programm dadurch nicht unnötig aufgeblasen wird. Wegen einer einzelnen Funktion sollte man also nicht nach einer großen Bibliothek suchen.
Eine Bibliothek einzubinden gestaltet sich relativ leicht. Zunächst mal benötigt man die eigentliche Bibliothek (eine Datei). Für diesen Guide wird eine populäre Bibliothek mit dem Namen "jQuery" verwendet. Die entsprechende Datei findet man auf der offiziellen Seite. (jQuery Homepage).
Mein Browser öffnet die entsprechende Datei (jquery-1.7.2.min.js) wie eine Textdatei. Speichert diese Datei mit Hilfe der "Seite speichern unter" Funktion eures Browser im "pong"-Ordner.
Um die Funktionen der Bibliothek in eurem Programm zu benutzen ist folgende Zeile notwendig:
Code: Alles auswählen   <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
   
   <script type="text/javascript">   
      // Hier kommt der Javascript-Code rein!
   </script>
Die Zeile ähnelt sehr dem normalen Sktipt-Tag für Javascript, mit der Ausnahme, dass der Inhalt leer bleibt und eine Option mit dem Namen "src" (also Quelle) hinzugekommen ist. In diese Option wird der relative Pfad zur Bibliothek eingegeben. Da sich die Bibliothek im gleichen Ordner wie die HTML-Datei befindet genügt also der Name der Bibliothek.

4.2 HTML Content ändern mit jQuery
Es bleibt natürlich die Frage, was diese Bibliothek überhaupt so toll macht. Die Antwort ist, dass jQuery besonders das Ansteuern und Ändern von HTML Elementen (z.B. DIVs) erleichtert.
Um das zu verdeutlichen wurden zunächst ein paar weitere DIVs mit Text als Inhalt erstellt:
Code: Alles auswählen<html>
   <body>
      <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
      <script type="text/javascript">
      
      </script>
      
      <img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>
      <div style="width:800px;"><div style="width:50%;float:left;">Punktzahl Spieler 1 : <div id="punktzahl_1">0</div></div><div style="width:50%;float:left;">Punktzahl Spieler 2 : <div id="punktzahl_2">0</div></div></div><br /><br />
      <div id="spielfeld" style="width:800px; height:600px; background-color:green; position:relative;">
         <div style="width: 25px; height:25px; background-color:red; position:absolute; left:100px; top:100px;"></div>
      </div>
   </body>
</html>
Über dem Spielfeld sollten nun links die Punktzahl von Spieler 1 und rechts die von Spieler 2 stehen. Den Punktzahl DIVs wurde eine sinnvolle Bezeichnung gegeben ("punktzahl_1" und "punktzahl_2"). Mit Hilfe von jQuery kann deren Inhalt leicht ausgegeben werden. Wir müssen allerdings zunächst sichergehen, dass die Seite vom Browser geladen wurde, bevor das Javascript ausgeführt wird. Dies dauert zwar bei der relativ kleinen Seite, die bisher verwendet wurde nur den Bruchteil einer Sekunde, das Javascript ist dennoch schneller.
Dazu gibt es in unsrer Bibliothek eine Funktion, die etwas Erklärung benötigt. Der Code lautet:
Code: Alles auswählen$(document).ready(function(){
   // Dieser Code wird nach dem laden der Seite ausgeführt
});
Das "$" wird gleich noch besprochen, der Teil "$(document)" könnt ihr erstmal so verstehen, dass die folgende Funktion das gesamte HTML-Dokument (bzw. Datei) betrifft. Dann folgt der Aufruf einer Funktion mit dem Namen "ready()" (also übersetzt "fertig").
Diese Funktion hat einen Parameter, der in diesem Fall (was vielleicht etwas ungewöhnlich wirkt) wieder eine Funktion ist.
Die Funktion "ready" bewirkt, dass wenn das "Dokument fertig" geladen ist, die als Parameter übergebene Funktion ausgeführt wird. Der Code "function(){ ... }" stellt dann einfach eine neue Funktion ohne Namen da. Im Innern dieser Funktion (zwischen den geschweiften Klammern) kann dann beliebiger Code geschrieben werden.
Wir wollen nun den Inhalt eines bestimmten DIVs auslesen (in einer Variablen speichern) und ausgeben.
Der zugehörige Code lautet:
Code: Alles auswählen<script type="text/javascript">
   $(document).ready(function(){
      var inhalt = $("#punktzahl_1").html();
      alert(inhalt);
   });
</script>
Der Code oben gibt die Zahl 0 aus. Maßgeblich ist der Abschnitt "$("#punktzahl_1").html()". Das Dollarzeichen "$" gibt an, dass es sich im Folgenden um einen jQuery Objekt handelt. Es handelt sich eigentlich um eine Funktion mit dem Namen "$", die ein jQuery Objekt zurückgibt. welches die Informationen über ein HTML-Element beinhaltet.
Der Parameter "#punktzahl_1" teilt der Funktion mit, welches HTML-Element ausgewählt werden soll. Die Raute "#" steht dafür, dass das Element anhand seiner ID ausgewählt werden soll. Anschließend folgt die gewünschte ID. Das jQuery Objekt beinhaltet eigene Funktionen, von denen wir eine Funktion mit dem Namen "html()" aufrufen. Diese liefert den Inhalt des HTML-Elemnts, den wir in einer Variable speichern und über "alert" ausgeben.
Wenn anstelle der Punktzahl von Spieler 1 die von Spieler 2 ausgegeben werden soll, ist hoffentlich klar, dass einfach die entsprechende ID eingesetzt werden muss.
Die Funktion um den Inhalt eines Elements zu ändern sieht sehr ähnlich aus:
Code: Alles auswählen<script type="text/javascript">
   $(document).ready(function(){
      $("#punktzahl_1").html(5);
      $("#punktzahl_2").html(3);
   });
</script>
Der Inhalt (bzw. der Text) der beiden DIVs wird nun auf die angegebenen Werte (also 5 bzw. 3) gesetzt. Es ist offensichtlich, dass diese Funktion später benötigt wird, um die Punktzahlen der Spieler anzuzeigen. Ich hoffe ihr habt nun ein Minimum-Verständnis, wie jQuery angewendet wird.
Falls nicht empfehle ich wiedermal einen Guide im Internet zu suchen.

4.3 Positionierung mit jQuery
Mit dem derzeitigen Wissen können wir nun beinahe ein Text-Adventure erstellen. Bei "Pong" müssen wir allerdings nicht nur den Inhalt von DIVs verändern, sondern vor allem deren Position. Bevor besprochen wird, wie dazu die Tastatur verwendet werden kann, wird nun die direkte Positionierung mit Code besprochen.
Die selben Funktionen werden dann weiter unten mit Tasteneingaben verknüpft werden.
Zunächst mal wurde ein Ball-Bild erstellt und ein entsprechendes Bild in den Code eingefügt (das Rote Quadrat wird ersetzt). Speichert dieses Bild in eurem "pong"-Ordner:
http://oi42.tinypic.com/abpfzp.jpg
Der Neue Code lautet:
Code: Alles auswählen<html>
   <body>
      <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
      <script type="text/javascript">
      
      </script>
      
      <img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>
      <div style="width:800px;"><div style="width:50%;float:left;">Punktzahl Spieler 1 : <div id="punktzahl_1">0</div></div><div style="width:50%;float:left;">Punktzahl Spieler 2 : <div id="punktzahl_2">0</div></div></div><br /><br />
      <div id="spielfeld" style="width:800px; height:600px; background-color:green; position:relative;">
         <img id="ball" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></img>
      </div>
   </body>
</html>
Aus offensichtlichen Gründen wurde dem Bild die ID "ball" zugewiesen. Wie oben mit dem Inhalt wollen wir nun zunächst die Position eines DIVs auslesen und ausgeben. Die zugehörige Funktion ist:
Code: Alles auswählen<script type="text/javascript">
   $(document).ready(function(){
      var x = $("#ball").position().left;
      var y = $("#ball").position().top;
      alert(x+" "+y);
   });
</script>
Da wir sowohl den "left" und den "top" Parameter in der Style Option auf 100 gesetzt haben, sollte dies Ausgabe also "100 100" lauten. Als nächstes wollen wir diese Werte mit Javascript verändern. Der zugehörige Code lautet:
Code: Alles auswählen<script type="text/javascript">
   $(document).ready(function(){
      $("#ball").css("left",200);
      $("#ball").css("top",200);
   });
</script>
Die oben verwendete Funktion "css()", könnte auch verwendet werden um andere Parameter innerhalb der "Style"-Option zu verändern. Dies würde immer nach dem Schema "$("#ID").css(bezeichnung,neuer_wert)" ablaufen. In diesem Fall wird der "left" und der "top" Parameter auf jeweils 200 Pixel gesetzt.

5. "Physik Simulation"

Wir sind nun theoretisch in der Lage den Ball beliebig über das Spielfeld zu schieben. Wenn wir dies in kleinen Schritten innerhalb einer Schleife durchführen, hätten wir bereits etwas das wie eine Bewegung wirkt. Da wir jedoch Kollisionen mit der Wand und den Spielern durchführen wollen, müssen wir uns etwas schlauer anstellen.
Es wird also versucht, dass sich der Ball (so gut wie möglich) physikalisch korrekt bewegt.

5.1 Vermeidung einer Endlosschleife
Das erste kleine Problem ist die Endlosschleife. Eine stetige Wiederholung der selben Abfragen (Kollision, Bewegung, etc.) ist für jedes Spiel notwendig. Da der Browser eine Endlosschleife jedoch als ein "Hängen-Bleiben" des Skripts auffasst, müssen wir eine Alternative zu einer Endlosschleife finden.
Die erste Alternative, die einem in den Sinn kommen sollte ist eine Funktion nennen wir sie z.B. "update()", die am Ende ihres Inhalts erneut sich selbst aufruft. Also etwas wie:
Code: Alles auswählen<script type="text/javascript">
   function update(){
      // irgendwelches Zeug
      update();
   }
</script>
Würde diese Funktion einmal aufgerufen, würde sie in einer endlosen Wiederholung ausgeführt werden. Die wäre also tatsächlich ein Ersatz für eine Endlosschleife, wird vom Browser aber leider auch ähnlich interpretiert. Die Lösung des Problems ist ein Code, der nach einer festgelegten Wartezeit die "update()" Funktion aufruft und am Ende der selbigen aufgerufen wird.
Das Ganze muss folgendermaßen aussehen:
Code: Alles auswählen<script type="text/javascript">
   update();
   function update(){
      alert("Hallo");
      var timeout = setTimeout("update()",6000);
   }
</script>
Die "setTimeout()"-Funktion besitzt 2 Parameter. Der erste stellt den Code da, der nach Ablauf einer bestimmten Zeit ausgeführt werden soll. Der zweite Parameter eben diese Zeit in Millisekunden ( 1 ms = 0,001 s bzw. 1s = 1000ms). Die Variable timeout dient dazu, dass der Endloszyklus gegebenenfalls beendet werden kann, indem man auf diese Variable zugreift. Das Beispiel oben sollte also alle 10 Sekunden die Ausgabe "Hallo" machen.

5.2 Geschwindigkeit - Raum & Zeit
Wenn ihr in der Schule aufgepasst habt, sollte euch folgende Formel nicht Vollkommen unbekannt sein:
Falls euch die Formel dennoch unbekannt sein sollte (z.B. ihr noch keine Physik in der Schule hattet oder das Thema nicht/schlecht durchgenommen wurde) erkläre ich das Ganze nochmal "richtig" (immerhin habe ich mehr Physik-Vorlesungen hinter mir als die meisten Gym. Lehrer).
Zunächst mal zu den vorkommenden Variablen. Das "v" steht für die Geschwindigkeit eines Objekts. Das "ds" steht für die Änderung der Position und das "dt" für die Änderung der Zeit (auch die verstrichene Zeit gemeint). Eigentlich handelt es sich dabei um sog. differentielle Größen aber die Mathematik bleibt euch an dieser Stelle erspart.
Wir alle kennen eine Anwendung dieser Formel, wenn wir die Geschwindigkeit eines Autos angeben. Ein (sehr) Schnelles Auto kommt beispielsweise auf 300 km/Stunde. Was eigentlich bedeutet, dass für eine Positionsänderung von 300 km genau 1 Stunde verstreichen muss.
Will man nun beispielsweise wissen, wie weit das Auto (bei dieser Geschwindigkeit) in 3 Stunden kommt, stellen wir die Formel einfach nach der Positionsänderung um:
Das Ergebnis lautet also 3h*300km/h = 900 km (man beachte auch das Kürzen von Einheiten). Eben diese Formel wollen wir im folgenden anwenden.

5.3 Geradlinige Bewegung
Wir wollen den Ball nun (physikalisch korrekt) durch das Spielfeld bewegen. Dabei muss zunächst angemerkt werden, dass wir uns im 2-Dimensionalen Raum befinden (die Position hat 2 Komponenten). Demzufolge muss es auch 2 Geschwindigkeiten geben (eine für jede Richtung).
Wir erstellen also 2 Listen mit je 2 Komponenten:
Code: Alles auswählen<script type="text/javascript">
   var s = []; // Position
   var v = []; // Geschwindigkeit
   $(document).ready(function(){
      // Startwerte:
      s[0] = 0;
      s[1] = 0;
      v[0] = 0;
      v[1] = 0;
      update();
   });
   function update(){
      
      var timeout = setTimeout("update()",33);
   }
</script>
Als Startwert für die Position wurde hier der Punkt (0;0) gewählt. Ebenso wurden beide Komponenten der Geschwindigkeit auf 0 gesetzt. Als nächste wird eine Funktion erstellt, die mit Hilfe der bekannten jQuery Befehle nach den Positionskoordinaten den Ball setzt:
Code: Alles auswählen   function update_image(id,posi){
      $("#"+id).css("left",posi[0]);
      $("#"+id).css("top",posi[1]);
   }
Die Parameter der Funktion sind die ID des Balls und die Liste mit den Positionsdaten. Die zweite Funktion, die wir benötigen ist, die Anwendung der Formel oben. Die Funktion hat folgende Form:
Code: Alles auswählen   function update_position(posi,geschw){
      posi[0] = posi[0]+geschw[0];
      posi[1] = posi[1]+geschw[1];
      return posi;
   }
Die Funktion benötigt die momentane Position und Geschwindigkeit als Parameter und berechnet (und returnt) daraus die neue Position. Vielleicht ist euch aufgefallen, dass die Zeit "dt" in dieser Funktion gar nicht vorkommt. Der Grund dafür, dass wir diesen Faktor nicht benötigen ist, dass dieser durch
die Anwendung der Timeout-Funktion gesteuert wird. Diese wird so eingestellt, dass sie 30-Mal pro Sekunde (entspricht also 30 fps) ausgeführt wird. Der Faktor "dt" wäre also immer 33 Millisekunden. Wir sparen uns die Multiplikation unserer Geschwindigkeit mit diesem Faktor (um unser Programm zu beschleunigen) indem wir uns vorstellen, dass dieser Faktor bereits in der Geschwindigkeit berücksichtigt wurde.
d.h. eigentlich ist unsere Geschwindigkeit nicht direkt die Geschwindigkeit sondern etwas wie Geschw.*0,03. Praktisch müssen wir das allerdings nicht berücksichtigen (Es handelt sich um eine Änderung der ohnehin willkürlichen Einheit unserer Geschwindigkeit).
Beide eben erstellten Funktionen müssen nun innerhalb der ständig ausgeführten "update()"-Funktion aufgerufen werden. Der gesamte Code sieht nun so aus:
Code: Alles auswählen<html>
   <body>
   <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
   <script type="text/javascript">
      var s = []; // Position
      var v = []; // Geschwindigkeit
      $(document).ready(function(){   
         // Startwerte:
         s[0] = 0;
         s[1] = 0;
         v[0] = 5;
         v[1] = 5;
         update();
      });
      
      function update(){
         update_position(s,v);
         update_image("ball",s);
         var timeout = setTimeout("update()",33);
      }
      
      function update_image(id,posi){
         $("#"+id).css("left",posi[0]);
         $("#"+id).css("top",posi[1]);
      }
      
      function update_position(posi,geschw){
         posi[0] = posi[0]+geschw[0];
         posi[1] = posi[1]+geschw[1];
         return posi;
      }
   </script>
   
   <img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>
   <div style="width:800px;"><div style="width:50%;float:left;">Punktzahl Spieler 1 : <div id="punktzahl_1">0</div></div><div style="width:50%;float:left;">Punktzahl Spieler 2 : <div id="punktzahl_2">0</div></div></div><br /><br />
   <div id="spielfeld" style="width:800px; height:600px; background-color:green; position:relative;">
      <img id="ball" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></div>
   </div>
   </body>
</html>
Im wesentlichen wurde die "update"-Funktion verändert. Diese wird nun alle 33 ms ausgeführt und beinhaltet Aufrufe der eben erstellten Funktionen. Außerdem wurde der Startwert der Geschwindigkeit auf (5;5) geändert. Wird die Datei nun im Browser geöffnet, sollte sich der Ball über das Spielfeld bewegen. Um die Funktionsweise des Programms zu verstehen ist es zu empfehlen, dass ihr für Startposition und Startgeschwindigkeit ein paar Werte ausprobiert. Es sollte angemerkt werden, dass auch negative Werte für die Geschwindigkeit zulässig sind.
Ich darf euch nun gratulieren. Ihr habt soeben eine funktionsfähige Physik-Simulation durchgeführt, die so ähnlich (natürlich für komplexere Formeln) tatsächlich in der Wissenschaft ihre Anwendung findet.

5.4 Kollision mit der Wand
Es ist euch sicherlich aufgefallen, dass sich der Ball nicht für die Begrenzungen des Spielfelds interessiert. Dies war zu erwarten, da wir diese in unserem Programm an keiner Stelle angesprochen haben. Wir erstellen nun zunächst eine Funktion, die überprüft, ob der Ball mit einer der Wände kollidiert:
Diese Funktion kann etwa so aussehen:
Code: Alles auswählen   function rand_kolli(posi,geschw){
      var breite = $("#spielfeld").width();
      var hoehe = $("#spielfeld").height();
      if(posi[0] < 0){
         alert("links!");
      }
      if(posi[0] > breite){
         alert("rechts!");
      }
      if(posi[1] < 0){
         alert("oben!");
      }
      if(posi[1] > hoehe){
         alert("unten!");
      }
   }
Diese Funktion besorgt sich zunächst die Höhe und Breite des Spielfeldes über entsprechende jQuery-Funktionen und überprüft anschließend, wird überprüft ob die Begrenzung des Spielfelds in irgendeiner Richtung überschritten wurde und gibt gegebenenfalls die Richtung des Übertritts an. Durch Einsetzen in unsere "update()"-Funktion kann man sich leicht von der Funktionsfähigkeit überzeugen.
Leider hat diese Funktion noch einen kleinen Makel. Das Problem ist, dass die Variable "s" die Position der linken oberen Ecke des Ball-Bildes angibt. Durch einfache Addition der Breite und Höhe des Balls an der richtigen Stelle kann diesem Problem leicht Abhilfe geschafft werden. Das Bild unten soll das Vorgehen dabei verdeutlichen:
Das Bild zeigt deutlich, dass "unten" und "rechts" die Höhe bzw. Breite zur Position addiert werden muss, damit ein korrektes Ergebnis erzielt wird.
Jetzt müssen wir uns noch überlegen, was beim Aufprall eigentlich geschehen soll. Es ist klar, dass der Ball von den Wänden abprallen soll. Die Frage ist nur, wie man hier korrekt vorgeht. Hierfür wird das, im Physikunterricht in der Regel bei im Thema der Optik besprochenen Reflexionsgesetz angewendet.
Es besagt, dass Einfalls- und Ausfallswinkel identisch sind. Ich werde euch nicht mit dem Lösen der Entsprechenden Gleichungen langweilen und euch direkt das Ergebnis nennen. Es besagt, dass sich die Geschwindigkeit in Richtung der Wand umkehrt. Bei den Wänden "links" und "rechts" bedeutet dies, dass die erste Komponente von "v" ihr Vorzeichen ändert "oben" und "unten" entsprechend die zweite Komponente.
Damit die Physik-Experten nicht weinen müssen sei noch angemerkt, dass das Problem auch mit Energie- und Impulserhaltung konsistent ist, wenn man für die Wände eine unendliche (viel Größer als die des Balls) Masse annimmt. Die verbesserte Kollisionsfunktion sieht also so aus:
Code: Alles auswählen   function rand_kolli(posi,geschw){
      var breite = $("#spielfeld").width();
      var hoehe = $("#spielfeld").height();
      if(posi[0] < 0){
         geschw[0] = -geschw[0];
      }
      if(posi[0]+25 > breite){
         geschw[0] = -geschw[0];
      }
      if(posi[1] < 0){
         geschw[1] = -geschw[1];
      }
      if(posi[1]+25 > hoehe){
         geschw[1] = -geschw[1];
      }
   }
Leider ist die Funktion weiterhin nicht perfekt. Es existiert immer noch ein Problem, dass ich als falscher "Tunneleffekt" bezeichnen würde (Bitte nicht verwechseln mit dem gleichnamigen Effekt in der Quantenmechanik). Das Problem ist, dass unser Kollisionsdetektor immer dann reagiert, wenn die Wände überschritten wurden.
In unserer Simulation springt der Ball alle 0,03 Sekunden an eine neue Position. Dies wirkt für unser Auge wie eine flüssige Bewegung, tatsächlich ist es aber natürlich keine. Es kann also leicht passieren, dass der Ball in eine Wand springt. Diesen Effekt kann man leider nicht vollkommen verhindern. Wir könnten die Zeit weiter verringern, was mehr Rechenleistung erfordert aber ein besseres Resultat, was das Springen angeht liefert.
Dies ist das grundlegende Problem der Simulationsrechnung. Das Ergebnis kann nur auf Kosten längerer Rechenzeit verbessert werden. In unserem Fall können wir das Problem lösen, indem wir den Ball einfach aus der Wand teleportieren. Es mag unphysikalisch sein, sollte jedoch für den Anwender nicht erkennbar sein (und unser Ziel ist ja ein Spiel und keine Simulation). Die optimale Kollisionsfunktion ist also:
Code: Alles auswählen   function rand_kolli(posi,geschw){
      var breite = $("#spielfeld").width();
      var hoehe = $("#spielfeld").height();
      if(posi[0] < 0){
         posi[0] = 0;
         geschw[0] = -geschw[0];
      }
      if(posi[0]+25 > breite){
         posi[0] = breite-25;
         geschw[0] = -geschw[0];
      }
      if(posi[1] < 0){
         posi[1] = 0;
         geschw[1] = -geschw[1];
      }
      if(posi[1]+25 > hoehe){
         posi[1] = hoehe-25;
         geschw[1] = -geschw[1];
      }
   }
Diese Funktion an der richtigen Stelle in der update-Funktion aufgerufen:
Code: Alles auswählen   function update(){
      update_position(s,v);
      rand_kolli(s,v);
      update_image("ball",s);
      var timeout = setTimeout("update()",33);
   }
Die "rand_kolli" kommt vor die "update_image" Funktion, damit der Ball nicht innerhalb der Wand angezeigt wird und der Benutzer so nichts von dem Problem sieht. Im Browser ausgeführt sollte der Ball nun von den Wänden abprallen. Ich bin jedes mal überrascht, dass es wirklich funktioniert^^

5.5 Viele Kugeln
Es ist relativ leicht das Programm für mehrere Bälle zu erweitern. Der Code lautet dann:
Code: Alles auswählen<html>
   <body>
   <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
   <script type="text/javascript">
      var s = []; // Positionen
      var v = []; // Geschwindigkeiten
      $(document).ready(function(){   
         // Startwerte:
         s[0] = [800*Math.random(),600*Math.random()];
         s[1] = [800*Math.random(),600*Math.random()];
         s[2] = [800*Math.random(),600*Math.random()];
         s[3] = [800*Math.random(),600*Math.random()];
         s[4] = [800*Math.random(),600*Math.random()];
         v[0] = [4*Math.random(),4*Math.random()];
         v[1] = [4*Math.random(),4*Math.random()];
         v[2] = [4*Math.random(),4*Math.random()];
         v[3] = [4*Math.random(),4*Math.random()];
         v[4] = [4*Math.random(),4*Math.random()];
         update();
      });
      
      function update(){
         for(var i=0, len=s.length; i < len; i++){
            update_position(s[i],v[i]);
            rand_kolli(s[i],v[i]);
            update_image("ball_"+i,s[i]);
         }
         var timeout = setTimeout("update()",33);
      }
      
      function update_image(id,posi){
         $("#"+id).css("left",posi[0]);
         $("#"+id).css("top",posi[1]);
      }
      
      function update_position(posi,geschw){
         posi[0] = posi[0]+geschw[0];
         posi[1] = posi[1]+geschw[1];
         return posi;
      }
      
      function rand_kolli(posi,geschw){
         var breite = $("#spielfeld").width();
         var hoehe = $("#spielfeld").height();
         if(posi[0] < 0){
            posi[0] = 0;
            geschw[0] = -geschw[0];
         }
         if(posi[0]+25 > breite){
            posi[0] = breite-25;
            geschw[0] = -geschw[0];
         }
         if(posi[1] < 0){
            posi[1] = 0;
            geschw[1] = -geschw[1];
         }
         if(posi[1]+25 > hoehe){
            posi[1] = hoehe-25;
            geschw[1] = -geschw[1];
         }
      }
   </script>
   
   <img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>
   <div style="width:800px;"><div style="width:50%;float:left;">Punktzahl Spieler 1 : <div id="punktzahl_1">0</div></div><div style="width:50%;float:left;">Punktzahl Spieler 2 : <div id="punktzahl_2">0</div></div></div><br /><br />
   <div id="spielfeld" style="width:800px; height:600px; background-color:green; position:relative;">
      <img id="ball_0" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></img>
      <img id="ball_1" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></img>
      <img id="ball_2" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></img>
      <img id="ball_3" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></img>
      <img id="ball_4" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></img>
   </div>
   </body>
</html>
Da dies im endgültigen Spiel nicht umgesetzt ist, handelt es sich nur um eine kleine Spiellerei (darum nicht viel Erklärung).

5.6 Gegenseitige Kollision
~wird erstmal übersprungen~
Zuletzt geändert von DerSpieler am 09.04.2012, 02:34, insgesamt 2-mal geändert.
-0
+1

Werbung

Registriere dich kostenlos und beteilige dich aktiv in diesem Forum, um diese Werbung auszublenden.

Re: [Guide] Pong = Browser-Spi...

#890097 von DerSpieler
07.04.2012, 14:40
6. Bewegung von DIVs durch Tastatur

Bewegungen und Kollisionen können wir nun (fast) perfekt darstellen. Was zu einem richtigen Spiel noch fehlt ist die Einflussnahme durch die Spieler. Dies soll in diesem Fall über die Tastatur geschehen.

6.1 Tastaturabfragen
Die Entsprechende jQuery Funktion ist folgende:
Code: Alles auswählen   $(document).keydown(function(event){
      // Code
   });
Es handelt sich genau wie bei der "$(document).ready()" Funktion um eine Funktion die auf das gesamte Dokument zielt und eine Funktion als Parameter besitzt, die in diesem Fall nicht nach dem Laden des Dokuments, sondern beim Drücken einer Taste auf der Tastatur ausgeführt wird.
Folgender Code in das Skript-Tag eingefügt sollte für jede gedrückte Taste eine andere Zahl ausgeben:
Code: Alles auswählen   $(document).keydown(function(event){
      alert(event.which);
   });
Die Pfeiltasten sind beispielsweise die Zahlen von 37 bis 40. Diese Funktion wird nun immer ausgeführt, wenn der jeweilige Knopf "nach unten" gedrückt wird. Da wir die Bewegung stoppen wollen, wenn wir den Knopf mit dem Finger verlassen, benötigen wir noch eine Funktion, die darauf reagiert, ob ein Knopf losgelassen wird.
Der Code ist denkbar einfach:
Code: Alles auswählen   $(document).keyup(function(event){
      // Code
   });


6.2 Bewegung eines DIVs
Nun besitzen wir eigentlich alles, was zur Bewegung eines DIVs mit den Pfeiltasten notwendig ist.
Wir benötigen nun nurnoch ein Funktionen, die aus den eingegebenen Zahlen (die für Tasten stehen) die richtigen Aktionen ausführen.
Diese sollten so aussehen:
Code: Alles auswählen   function player_1_movement(geschw,tastenr){
      if(tastenr == 37){
         geschw[0] = -10;
      }
      if(tastenr == 38){
         geschw[1] = -10;
      }
      if(tastenr == 39){
         geschw[0] = 10;
      }
      if(tastenr == 40){
         geschw[1] = 10;
      }
   }
   
   function player_1_stop(geschw,tastenr){
      if(tastenr == 37 || tastenr == 39){
         geschw[0] = 0;
      }
      if(tastenr == 38 || tastenr == 40){
         geschw[1] = 0;
      }
   }
Es muss natürlich außerdem ein neues DIV erstellt werden, das vom Spieler gesteuert werden kann. Dieses sollte innerhalb des Spielfelds erstellt werden und etwa so aussehen:
Code: Alles auswählen<div id="spieler_1" style="width:50px;height:50px;background-color:red;position:absolute;"></div>

Außerdem müssen innerhalb der update-Funktion auch für den Spieler die "update_image" und "update_position" aufgerufen werden. Der Gesamtcode sollre nun so aussehen:
Code: Alles auswählen<html>
   <body>
   <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
   <script type="text/javascript">
      var s = []; // Positionen
      var v = []; // Geschwindigkeiten
      var s_player1 = [];
      var v_player1 = [];
      $(document).ready(function(){   
         // Startwerte:
         s[0] = 100;
         s[1] = 100;
         v[0] = 5;
         v[1] = 5;
         s_player1[0] = 200;
         s_player1[1] = 200;
         v_player1[0] = 0;
         v_player1[1] = 0;
         update();
      });
      $(document).keydown(function(event){
         player_1_movement(v_player1,event.which);
      });
      $(document).keyup(function(event){
         player_1_stop(v_player1,event.which);
      });
      
      function update(){
         update_position(s,v);
         update_position(s_player1,v_player1);
         rand_kolli(s,v);
         update_image("ball",s);
         update_image("spieler_1",s_player1);
         var timeout = setTimeout("update()",33);
      }
      
      function update_image(id,posi){
         $("#"+id).css("left",posi[0]);
         $("#"+id).css("top",posi[1]);
      }
      
      function update_position(posi,geschw){
         posi[0] = posi[0]+geschw[0];
         posi[1] = posi[1]+geschw[1];
         return posi;
      }
      
      function rand_kolli(posi,geschw){
         var breite = $("#spielfeld").width();
         var hoehe = $("#spielfeld").height();
         if(posi[0] < 0){
            posi[0] = 0;
            geschw[0] = -geschw[0];
         }
         if(posi[0]+25 > breite){
            posi[0] = breite-25;
            geschw[0] = -geschw[0];
         }
         if(posi[1] < 0){
            posi[1] = 0;
            geschw[1] = -geschw[1];
         }
         if(posi[1]+25 > hoehe){
            posi[1] = hoehe-25;
            geschw[1] = -geschw[1];
         }
      }
      
      function player_1_movement(geschw,tastenr){
         if(tastenr == 37){
            geschw[0] = -10;
         }
         if(tastenr == 38){
            geschw[1] = -10;
         }
         if(tastenr == 39){
            geschw[0] = 10;
         }
         if(tastenr == 40){
            geschw[1] = 10;
         }
      }
   
      function player_1_stop(geschw,tastenr){
         if(tastenr == 37 && geschw[0] < 0){
            geschw[0] = 0;
         }
         if(tastenr == 39 && geschw[0] > 0){
            geschw[0] = 0;
         }
         if(tastenr == 38 && geschw[1] < 0){
            geschw[1] = 0;
         }
         if(tastenr == 40 && geschw[1] > 0){
            geschw[1] = 0;
         }
      }
   </script>
   
   <img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>
   <div style="width:800px;"><div style="width:50%;float:left;">Punktzahl Spieler 1 : <div id="punktzahl_1">0</div></div><div style="width:50%;float:left;">Punktzahl Spieler 2 : <div id="punktzahl_2">0</div></div></div><br /><br />
   <div id="spielfeld" style="width:800px; height:600px; background-color:green; position:relative;">
      <img id="ball" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></img>
      <div id="spieler_1" style="width:50px;height:50px;background-color:red;position:absolute;"></div>
   </div>
   </body>
</html>
Wird diese Datei im Browser gestartet, sollte das rote Quadrat mit Hilfe der Pfeiltasten in alle Richtungen beweglich sein.
Das Ganze sollte etwa so aussehen:

6.3 Kollisionen mit dem bewegten DIV
Was für unser Spiel noch fehlt sind Kollisionen zwischen Spieler und Ball. Dafür benötigen wir eine weitere Funktion, die der Kollisionsfunktion für die Wände sehr ähnlich sieht.
Code: Alles auswählen   function player_kolli(player_id,player_posi,player_geschw,ball_posi,ball_geschw){
      var breite = $("#"+player_id).width();
      var hoehe = $("#"+player_id).height();
      if(ball_posi[0] < player_posi[0]+breite && ball_posi[0] > player_posi[0]+20 && player_geschw[0]-ball_geschw[0] > 0 && ball_posi[1]+25 > player_posi[1] && ball_posi[1] < player_posi[1]+hoehe){
         ball_posi[0] = player_posi[0]+breite;
         ball_geschw[0] = -ball_geschw[0]+player_geschw[0];
         ball_geschw[1] = ball_geschw[1]+player_geschw[1];
      }else if(ball_posi[0]+25 > player_posi[0] && ball_posi[0] < player_posi[0]+breite-20  && player_geschw[0]-ball_geschw[0] < 0 && ball_posi[1]+25 > player_posi[1] && ball_posi[1] < player_posi[1]+hoehe){
         ball_posi[0] = player_posi[0]-25;
         ball_geschw[0] = -ball_geschw[0]+player_geschw[0];
         ball_geschw[1] = ball_geschw[1]+player_geschw[1];
      }else if(ball_posi[1] < player_posi[1]+hoehe && ball_posi[1] > player_posi[1]+20 && player_geschw[1]-ball_geschw[1] > 0 && ball_posi[0]+25 > player_posi[0] && ball_posi[0] < player_posi[0]+breite){
         ball_posi[1] = player_posi[1]+hoehe;
         ball_geschw[0] = ball_geschw[0]+player_geschw[0];
         ball_geschw[1] = -ball_geschw[1]+player_geschw[1];
      }else if(ball_posi[1]+25 > player_posi[1] && ball_posi[1] < player_posi[1]+hoehe-20 && player_geschw[1]-ball_geschw[1] < 0 && ball_posi[0]+25 > player_posi[0] && ball_posi[0] < player_posi[0]+breite){
         ball_posi[1] = player_posi[1]-25;
         ball_geschw[0] = ball_geschw[0]+player_geschw[0];
         ball_geschw[1] = -ball_geschw[1]+player_geschw[1];
      }
   }
Die Funktion hat viele Parameter, da auch einige Informationen über den Spieler notwendig sind. Sie funktioniert eigentlich analog zur Kollision mit den Wänden. Der Unterschied besteht darin, dass beim Spieler nicht die inneren, sondern die äußeren Wände einen Effekt haben sollen.
Das Problem wird dadurch im Vergleich zu den Wänden etwas komplizierter. Die Überschreitung der Wand kann wie zuvor abgefragt werden. Das Problem ist, dass nun noch abgefragt werden muss, aus welcher Richtung der Ball in das DIV eingedrungen ist (da die Position diese Information nicht beinhaltet wird diese Information aus der Richtung der Geschwindigkeit abgelesen).
Die Funktion obene behebt noch ein paar weitere kleinere Probleme auf die ich jetzt nicht weiter eingehen kann. Ein Problem welches immer noch auftreten kann ist ein Tunneln durch den Spieler, wenn der Ball Geschwindigkeiten weisentlich über 20 hat. Dieses Problem kann leider nicht so leicht behoben werden. Die einzige einfache Lösung stellt eine (später benutzte) Beschränkung der Geschwindigkeit da.
Probiert die Funktion einfach mal aus. Fügt sie dazu in die update-Funktion ein:
Code: Alles auswählen   function update(){
      update_position(s,v);
      update_position(s_player1,v_player1);
      rand_kolli(s,v);
      player_kolli("spieler_1",s_player1,v_player1,s,v);
      update_image("ball",s);
      update_image("spieler_1",s_player1);
      var timeout = setTimeout("update()",33);
   }
Zum Schluss fehlt noch eine Funktion die verhindert, dass der Spieler das Spielfeld verlässt. Diese ist fast vollkommen analog zur Wand-Kollision beim Ball, mit dem Unterschied, dass der Spieler nicht abprallen soll. Die Funktion sollte so aussehen:
Code: Alles auswählen   function rand_kolli_player(player_id,posi,geschw){
      var breite = $("#spielfeld").width();
      var hoehe = $("#spielfeld").height();
      var breite_player = $("#"+player_id).width();
      var hoehe_player = $("#"+player_id).height();
      if(posi[0] < 0){
         posi[0] = 0;
      }
      if(posi[0]+breite_player > breite){
         posi[0] = breite-breite_player;
      }
      if(posi[1] < 0){
         posi[1] = 0;
      }
      if(posi[1]+hoehe_player > hoehe){
         posi[1] = hoehe-hoehe_player;
      }
   }
Diese Funktion sollte nun noch an die richtige Stelle in der update Funktion aufgerufen werden:
Code: Alles auswählen   function update(){
      update_position(s,v);
      update_position(s_player1,v_player1);
      rand_kolli(s,v);
      rand_kolli_player("spieler_1",s_player1,v_player1);
      player_kolli("spieler_1",s_player1,v_player1,s,v);
      update_image("ball",s);
      update_image("spieler_1",s_player1);
      var timeout = setTimeout("update()",33);
   }


7. Vereinfachung zu Pong

Was ihr bisher geleistet habt, geht über das einfache Pong eigentlich schon ein Stück hinaus. Alles was noch fehlt ist eigentlich nur eine Einschränkung der bisherigen Möglichkeiten und der 2. Spieler.

7.1 Die Tennisschläger
Zunächst mal muss der erste Spieler (bzw. sein DIV) nach rechts verschoben werden und seine Bewegung etwas eingeschränkt (nurnoch in vertikaler Richtung). Dazu wird nun also die Position des DIVs verändert und der horizontalen Bewegung entsprechenden Zeilen gelöscht.
Das neue Player DIV sieht dann so aus:
Code: Alles auswählen<div id="spieler_1" style="width:30px;height:100px;background-color:red;position:absolute;"></div>
Die neuen Startwerte sind
Code: Alles auswählens_player1[0] = 700;
s_player1[1] = 300;

Die neue move_player_1_movement funktion so:
Code: Alles auswählenfunction player_1_movement(geschw,tastenr){
   if(tastenr == 38){
      geschw[1] = -10;
   }
   if(tastenr == 40){
      geschw[1] = 10;
   }
}
Nun noch eine sinnvolle Anfangsposition und Geschwindigkeit für den Ball z.B.:
Code: Alles auswählen   s[0] = 388;
   s[1] = 312;
   v[0] = 5;
   v[1] = 0;
Nun können wir bereits Pong gegen die Wand spielen.

7.2 Der zweite Spieler
Nun müssen wir (eigentlich) noch alles was wir für den ersten Spieler gemacht haben nochmal für den zweiten Spieler wiederholen. Zum Glück haben wir aber vieles bereits so dynamisch erstellt, dass wir nur ein paar Funktionen mit veränderten Parametern aufrufen müssen.
(Außerdem habt ihr ja das Glück einfach meinen Code kopieren zu können). Zuerst muss ein zweites DIV erstellt werden:
Code: Alles auswählen<div id="spieler_2" style="width:30px;height:100px;background-color:blue;position:absolute;"></div>

Dann werden ein paar neue Variablen erstellt und auf sinnvolle Werte gesetzt (alle die ein "spieler1" im Namen hatten werden ein zweites mal mit "spieler2" erstellt). Nun wird die update-Funktion entsprechend angepasst:
Code: Alles auswählen   function update(){
      update_position(s,v);
      update_position(s_player1,v_player1);
      update_position(s_player2,v_player2);
      rand_kolli(s,v);
      rand_kolli_player("spieler_1",s_player1,v_player1);
      player_kolli("spieler_1",s_player1,v_player1,s,v);
      rand_kolli_player("spieler_2",s_player2,v_player2);
      player_kolli("spieler_2",s_player2,v_player2,s,v);
      update_image("ball",s);
      update_image("spieler_1",s_player1);
      update_image("spieler_2",s_player2);
      var timeout = setTimeout("update()",33);
   }
Nun sieht alles schon ganz hübsch aus. Der zweite Spieler sollte sich aber auch bewegen können. Es muss also eine neue Funktion geschrieben werden, die auf andere Knöpfe anspricht. (Wir wählen "w" und "s" also oben und unten für den zweiten Spieler). Die Funktionen sollte so aussehen:
Code: Alles auswählen   function player_2_movement(geschw,tastenr){
      if(tastenr == 87){
         geschw[1] = -10;
      }
      if(tastenr == 83){
         geschw[1] = 10;
      }
   }
   
   function player_2_stop(geschw,tastenr){
      if(tastenr == 87 && geschw[1] < 0){
         geschw[1] = 0;
      }
      if(tastenr == 83 && geschw[1] > 0){
         geschw[1] = 0;
      }
   }
Der Gesamtcode dann etwa so:
Code: Alles auswählen   <html>
   <body>
   <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
   <script type="text/javascript">
      var s = []; // Positionen
      var v = []; // Geschwindigkeiten
      var s_player1 = [];
      var v_player1 = [];
      var s_player2 = [];
      var v_player2 = [];
      $(document).ready(function(){   
         // Startwerte:
         s[0] = 388;
         s[1] = 312;
         v[0] = 5;
         v[1] = 0;
         s_player1[0] = 700;
         s_player1[1] = 300;
         v_player1[0] = 0;
         v_player1[1] = 0;
         s_player2[0] = 100;
         s_player2[1] = 300;
         v_player2[0] = 0;
         v_player2[1] = 0;
         update();
      });
      $(document).keydown(function(event){
         player_1_movement(v_player1,event.which);
         player_2_movement(v_player2,event.which);
      });
      $(document).keyup(function(event){
         player_1_stop(v_player1,event.which);
         player_2_stop(v_player2,event.which);
      });
      
      function update(){
         update_position(s,v);
         update_position(s_player1,v_player1);
         update_position(s_player2,v_player2);
         rand_kolli(s,v);
         rand_kolli_player("spieler_1",s_player1,v_player1);
         player_kolli("spieler_1",s_player1,v_player1,s,v);
         rand_kolli_player("spieler_2",s_player2,v_player2);
         player_kolli("spieler_2",s_player2,v_player2,s,v);
         update_image("ball",s);
         update_image("spieler_1",s_player1);
         update_image("spieler_2",s_player2);
         var timeout = setTimeout("update()",33);
      }
      
      function update_image(id,posi){
         $("#"+id).css("left",posi[0]);
         $("#"+id).css("top",posi[1]);
      }
      
      function update_position(posi,geschw){
         posi[0] = posi[0]+geschw[0];
         posi[1] = posi[1]+geschw[1];
         return posi;
      }
      
      function rand_kolli(posi,geschw){
         var breite = $("#spielfeld").width();
         var hoehe = $("#spielfeld").height();
         if(posi[0] < 0){
            posi[0] = 0;
            geschw[0] = -geschw[0];
         }
         if(posi[0]+25 > breite){
            posi[0] = breite-25;
            geschw[0] = -geschw[0];
         }
         if(posi[1] < 0){
            posi[1] = 0;
            geschw[1] = -geschw[1];
         }
         if(posi[1]+25 > hoehe){
            posi[1] = hoehe-25;
            geschw[1] = -geschw[1];
         }
      }
      
      function rand_kolli_player(player_id,posi,geschw){
         var breite = $("#spielfeld").width();
         var hoehe = $("#spielfeld").height();
         var breite_player = $("#"+player_id).width();
         var hoehe_player = $("#"+player_id).height();
         if(posi[0] < 0){
            posi[0] = 0;
         }
         if(posi[0]+breite_player > breite){
            posi[0] = breite-breite_player;
         }
         if(posi[1] < 0){
            posi[1] = 0;
         }
         if(posi[1]+hoehe_player > hoehe){
            posi[1] = hoehe-hoehe_player;
         }
      }
      
      function player_1_movement(geschw,tastenr){
         if(tastenr == 38){
            geschw[1] = -10;
         }
         if(tastenr == 40){
            geschw[1] = 10;
         }
      }
      
      function player_2_movement(geschw,tastenr){
         if(tastenr == 87){
            geschw[1] = -10;
         }
         if(tastenr == 83){
            geschw[1] = 10;
         }
      }
   
      function player_1_stop(geschw,tastenr){
         if(tastenr == 37 && geschw[0] < 0){
            geschw[0] = 0;
         }
         if(tastenr == 39 && geschw[0] > 0){
            geschw[0] = 0;
         }
         if(tastenr == 38 && geschw[1] < 0){
            geschw[1] = 0;
         }
         if(tastenr == 40 && geschw[1] > 0){
            geschw[1] = 0;
         }
      }
      
      function player_2_stop(geschw,tastenr){
         if(tastenr == 87 && geschw[1] < 0){
            geschw[1] = 0;
         }
         if(tastenr == 83 && geschw[1] > 0){
            geschw[1] = 0;
         }
      }
      
      function player_kolli(player_id,player_posi,player_geschw,ball_posi,ball_geschw){
         var breite = $("#"+player_id).width();
         var hoehe = $("#"+player_id).height();
         if(ball_posi[0] < player_posi[0]+breite && ball_posi[0] > player_posi[0]+20 && player_geschw[0]-ball_geschw[0] > 0 && ball_posi[1]+25 > player_posi[1] && ball_posi[1] < player_posi[1]+hoehe){
            ball_posi[0] = player_posi[0]+breite;
            ball_geschw[0] = -ball_geschw[0]+player_geschw[0];
            ball_geschw[1] = ball_geschw[1]+player_geschw[1];
         }else if(ball_posi[0]+25 > player_posi[0] && ball_posi[0] < player_posi[0]+breite-20  && player_geschw[0]-ball_geschw[0] < 0 && ball_posi[1]+25 > player_posi[1] && ball_posi[1] < player_posi[1]+hoehe){
            ball_posi[0] = player_posi[0]-25;
            ball_geschw[0] = -ball_geschw[0]+player_geschw[0];
            ball_geschw[1] = ball_geschw[1]+player_geschw[1];
         }else if(ball_posi[1] < player_posi[1]+hoehe && ball_posi[1] > player_posi[1]+20 && player_geschw[1]-ball_geschw[1] > 0 && ball_posi[0]+25 > player_posi[0] && ball_posi[0] < player_posi[0]+breite){
            ball_posi[1] = player_posi[1]+hoehe;
            ball_geschw[0] = ball_geschw[0]+player_geschw[0];
            ball_geschw[1] = -ball_geschw[1]+player_geschw[1];
         }else if(ball_posi[1]+25 > player_posi[1] && ball_posi[1] < player_posi[1]+hoehe-20 && player_geschw[1]-ball_geschw[1] < 0 && ball_posi[0]+25 > player_posi[0] && ball_posi[0] < player_posi[0]+breite){
            ball_posi[1] = player_posi[1]-25;
            ball_geschw[0] = ball_geschw[0]+player_geschw[0];
            ball_geschw[1] = -ball_geschw[1]+player_geschw[1];
         }
      }
   </script>
   
   <img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>
   <div style="width:800px;"><div style="width:50%;float:left;">Punktzahl Spieler 1 : <div id="punktzahl_1">0</div></div><div style="width:50%;float:left;">Punktzahl Spieler 2 : <div id="punktzahl_2">0</div></div></div><br /><br />
   <div id="spielfeld" style="width:800px; height:600px; background-color:green; position:relative;">
      <img id="ball" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></img>
      <div id="spieler_1" style="width:30px;height:100px;background-color:red;position:absolute;"></div>
      <div id="spieler_2" style="width:30px;height:100px;background-color:blue;position:absolute;"></div>
   </div>
   </body>
</html>
Es sollten sich nun beide Spieler bewegen können.

7.3 Punkte zählen & Aufschlag
Alles was jetzt noch fehlt ist das Zählen der Punkte und der Aufschlag, wenn ein Punkt gemacht wurde. Dazu müssen wir lediglich die Wand-Kollisionsfunktion für den Ball etwas umschreiben. Die veränderte Version sollte so aussehen:
Code: Alles auswählenfunction rand_kolli(posi,geschw){
         var breite = $("#spielfeld").width();
         var hoehe = $("#spielfeld").height();
         if(posi[0] < 0){
            $("#punktzahl_1").html(parseInt($("#punktzahl_1").html())+1);
            posi[0] = 388;
            posi[1] = 312;
            geschw[0] = 5;
            geschw[1] = 0;
         }
         if(posi[0]+25 > breite){
            $("#punktzahl_2").html(parseInt($("#punktzahl_2").html())+1);
            posi[0] = 388;
            posi[1] = 312;
            geschw[0] = -5;
            geschw[1] = 0;
         }
         if(posi[1] < 0){
            posi[1] = 0;
            geschw[1] = -geschw[1];
         }
         if(posi[1]+25 > hoehe){
            posi[1] = hoehe-25;
            geschw[1] = -geschw[1];
         }
      }
Wie ihr sicherlich sehen könnt, wurden lediglich die Kollisionen mit der linken und rechten Wand angepasst. Die jeweilige Anzeige wird über jQuery um 1 erhöht und die Position des Balls auf den Startwert gesetzt.

7.4 Der fertige Code
Der nun fertige Code lautet:
Code: Alles auswählen<html>
   <body>
   <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
   <script type="text/javascript">
      var s = []; // Positionen
      var v = []; // Geschwindigkeiten
      var s_player1 = [];
      var v_player1 = [];
      var s_player2 = [];
      var v_player2 = [];
      $(document).ready(function(){   
         // Startwerte:
         s[0] = 388;
         s[1] = 312;
         v[0] = 5;
         v[1] = 0;
         s_player1[0] = 700;
         s_player1[1] = 300;
         v_player1[0] = 0;
         v_player1[1] = 0;
         s_player2[0] = 100;
         s_player2[1] = 300;
         v_player2[0] = 0;
         v_player2[1] = 0;
         update();
      });
      $(document).keydown(function(event){
         player_1_movement(v_player1,event.which);
         player_2_movement(v_player2,event.which);
      });
      $(document).keyup(function(event){
         player_1_stop(v_player1,event.which);
         player_2_stop(v_player2,event.which);
      });
      
      function update(){
         update_position(s,v);
         update_position(s_player1,v_player1);
         update_position(s_player2,v_player2);
         rand_kolli(s,v);
         rand_kolli_player("spieler_1",s_player1,v_player1);
         player_kolli("spieler_1",s_player1,v_player1,s,v);
         rand_kolli_player("spieler_2",s_player2,v_player2);
         player_kolli("spieler_2",s_player2,v_player2,s,v);
         update_image("ball",s);
         update_image("spieler_1",s_player1);
         update_image("spieler_2",s_player2);
         var timeout = setTimeout("update()",33);
      }
      
      function update_image(id,posi){
         $("#"+id).css("left",posi[0]);
         $("#"+id).css("top",posi[1]);
      }
      
      function update_position(posi,geschw){
         posi[0] = posi[0]+geschw[0];
         posi[1] = posi[1]+geschw[1];
         return posi;
      }
      
      function rand_kolli(posi,geschw){
         var breite = $("#spielfeld").width();
         var hoehe = $("#spielfeld").height();
         if(posi[0] < 0){
            //posi[0] = 0;
            //geschw[0] = -geschw[0];
            $("#punktzahl_1").html(parseInt($("#punktzahl_1").html())+1);
            posi[0] = 388;
            posi[1] = 312;
            geschw[0] = 5;
            geschw[1] = 0;
         }
         if(posi[0]+25 > breite){
            //posi[0] = breite-25;
            //geschw[0] = -geschw[0];
            $("#punktzahl_2").html(parseInt($("#punktzahl_2").html())+1);
            posi[0] = 388;
            posi[1] = 312;
            geschw[0] = -5;
            geschw[1] = 0;
         }
         if(posi[1] < 0){
            posi[1] = 0;
            geschw[1] = -geschw[1];
         }
         if(posi[1]+25 > hoehe){
            posi[1] = hoehe-25;
            geschw[1] = -geschw[1];
         }
      }
      
      function rand_kolli_player(player_id,posi,geschw){
         var breite = $("#spielfeld").width();
         var hoehe = $("#spielfeld").height();
         var breite_player = $("#"+player_id).width();
         var hoehe_player = $("#"+player_id).height();
         if(posi[0] < 0){
            posi[0] = 0;
         }
         if(posi[0]+breite_player > breite){
            posi[0] = breite-breite_player;
         }
         if(posi[1] < 0){
            posi[1] = 0;
         }
         if(posi[1]+hoehe_player > hoehe){
            posi[1] = hoehe-hoehe_player;
         }
      }
      
      function player_1_movement(geschw,tastenr){
         //if(tastenr == 37){
         //   geschw[0] = -10;
         //}
         if(tastenr == 38){
            geschw[1] = -10;
         }
         //if(tastenr == 39){
         //   geschw[0] = 10;
         //}
         if(tastenr == 40){
            geschw[1] = 10;
         }
      }
      
      function player_2_movement(geschw,tastenr){
         if(tastenr == 87){
            geschw[1] = -10;
         }
         if(tastenr == 83){
            geschw[1] = 10;
         }
      }
   
      function player_1_stop(geschw,tastenr){
         if(tastenr == 37 && geschw[0] < 0){
            geschw[0] = 0;
         }
         if(tastenr == 39 && geschw[0] > 0){
            geschw[0] = 0;
         }
         if(tastenr == 38 && geschw[1] < 0){
            geschw[1] = 0;
         }
         if(tastenr == 40 && geschw[1] > 0){
            geschw[1] = 0;
         }
      }
      
      function player_2_stop(geschw,tastenr){
         if(tastenr == 87 && geschw[1] < 0){
            geschw[1] = 0;
         }
         if(tastenr == 83 && geschw[1] > 0){
            geschw[1] = 0;
         }
      }
      
      function player_kolli(player_id,player_posi,player_geschw,ball_posi,ball_geschw){
         var breite = $("#"+player_id).width();
         var hoehe = $("#"+player_id).height();
         if(ball_posi[0] < player_posi[0]+breite && ball_posi[0] > player_posi[0]+20 && player_geschw[0]-ball_geschw[0] > 0 && ball_posi[1]+25 > player_posi[1] && ball_posi[1] < player_posi[1]+hoehe){
            ball_posi[0] = player_posi[0]+breite;
            ball_geschw[0] = -ball_geschw[0]+player_geschw[0];
            ball_geschw[1] = ball_geschw[1]+player_geschw[1];
         }else if(ball_posi[0]+25 > player_posi[0] && ball_posi[0] < player_posi[0]+breite-20  && player_geschw[0]-ball_geschw[0] < 0 && ball_posi[1]+25 > player_posi[1] && ball_posi[1] < player_posi[1]+hoehe){
            ball_posi[0] = player_posi[0]-25;
            ball_geschw[0] = -ball_geschw[0]+player_geschw[0];
            ball_geschw[1] = ball_geschw[1]+player_geschw[1];
         }else if(ball_posi[1] < player_posi[1]+hoehe && ball_posi[1] > player_posi[1]+20 && player_geschw[1]-ball_geschw[1] > 0 && ball_posi[0]+25 > player_posi[0] && ball_posi[0] < player_posi[0]+breite){
            ball_posi[1] = player_posi[1]+hoehe;
            ball_geschw[0] = ball_geschw[0]+player_geschw[0];
            ball_geschw[1] = -ball_geschw[1]+player_geschw[1];
         }else if(ball_posi[1]+25 > player_posi[1] && ball_posi[1] < player_posi[1]+hoehe-20 && player_geschw[1]-ball_geschw[1] < 0 && ball_posi[0]+25 > player_posi[0] && ball_posi[0] < player_posi[0]+breite){
            ball_posi[1] = player_posi[1]-25;
            ball_geschw[0] = ball_geschw[0]+player_geschw[0];
            ball_geschw[1] = -ball_geschw[1]+player_geschw[1];
         }
      }
   </script>
   
   <img id="banner" src="http://oi43.tinypic.com/amsadk.jpg" style="width:200px; position:relative; left: 100px;" ></img>
   <div style="width:800px;"><div style="width:50%;float:left;">Punktzahl Spieler 1 : <div id="punktzahl_1">0</div></div><div style="width:50%;float:left;">Punktzahl Spieler 2 : <div id="punktzahl_2">0</div></div></div><br /><br />
   <div id="spielfeld" style="width:800px; height:600px; background-color:green; position:relative;">
      <img id="ball" src="ball.png" style="width: 25px; height:25px; position:absolute; left:100px; top:100px;"></img>
      <div id="spieler_1" style="width:30px;height:100px;background-color:red;position:absolute;"></div>
      <div id="spieler_2" style="width:30px;height:100px;background-color:blue;position:absolute;"></div>
   </div>
   </body>
</html>
Das Ganze sollte etwa so aussehen:

8. Der Schmetterball

~wird erstmal übersprungen~

9. Nachwort

Unglaublich aber wahr. Wir sind am Ende angekommen. Ich weiß, dass ich mich an einigen Stellen sehr kurz gefasst habe und deshalb einiges vielleicht nicht leicht zu verstehen ist. Ich stehe diesbezüglich natürlich immer zur Verfügung und zum Glück ist so ein Guide ja nicht statisch.
Über viel Feedback wäre ich (und zukünftige Leser) also überaus dankbar. Natürlich ist sonstiges (konstruktives) Feedback auch immer erwünscht. Es würde mich vor allem sehr interessieren, ob dieser Guide jemandem geholfen hat und/oder ob ihn überhaupt jemand durcharbeiten konnte.
Bei genügend positiver Resonanz könnte ich mir gut vorstellen noch weitere (auch komplexere) Guides zur Spieleprogrammierung mit Javascrit zu schreiben. Vielleicht auch mal etwas das mit Pokemon zu tun hat.
Ich hoffe ihr hattet Spaß am Lesen (das Schreiben war nämlich mühsam XD).
Vielen Dank sagt DerSpieler

PS.: Ich habe auch eine fertige Version online. Link zum Ergebnis: PONG

"Erlaubnis":
Delirium hat geschrieben:Für Guides brauchst du keine Erlaubnis, du darfst selbstverständlich Posten, sofern es noch nichts gleiches gibt. Und das gibts nicht.
-0
+1

Re: [Guide] Pong = Browser-Spi...

#890113 von looper
07.04.2012, 15:17
Ich finde es schön, dass du dich an ein solch ausführlichen Guide rangesetzt hast. Ich habe auch leider(jetzt) nicht die Zeit, mir das ganze durchzulesen, aber beim Anspielen deiner Demo sind mir 3 Dinge aufgefallen:
  • Der Ball wird unlogisch schnell. Mit einer Maximalgeschwindigkeit könnte das ganze ein wenig logischer aussehen ;)
  • Die Punktezählung scheint falsch zu sein, wenn der Ball ins linke Aus geht, kriegt der Linke ein Punkt :huh:
  • Für Bildschirme mit geringerer Auflösung ist das ganze ein wenig unpraktisch, da beim scrollen sich die ganze Seite mitbewegt.Das kann durch eine dynamische Berechnung der Spielfläche aufgrund der Anzeigegröße, sowie durch ein CSS-Eintrag gelöst werden.

Code: Alles auswählenbody { overflow: hidden; }


Ansonsten werde ich mir das anschauen, wenn ich Zeit habe :)
-0
+0

Re: [Guide] Pong = Browser-Spi...

#890137 von DerSpieler
07.04.2012, 17:00
Die Punktzahl wird schon richtig angezeigt, es ist nur vielleicht etwas verwirrend, da der 1. Spieler (da er mit den Pfeiltasten spielt auf der rechten Seite ist). Da die Nummerierung aber ohnehin schnuppe ist, werd ich es bei Gelegenheit umschreiben. Die Sache mit der kleinen Auflösung ist mir bewusst. Ich wollte einem Anfänger nur erstmal nicht aufbürden die Koordinaten (z.B. des Balls) in Prozent angeben zu müssen (bzw. umzurechnen).
Eine Maximalgeschwindigkeit ist sicherlich eine Überlegung wert. Ich befürchte nur, dass dann keine Punkte mehr gemacht werden XD

Ich hoffe du findest die Zeit ihn zu lesen (ist wegen des Umfangs durchaus verständlich wenn nicht). Würde mich über Feedback zur Verständlichkeit etc. sehr freuen.
-0
+0

Re: [Guide] Pong = Browser-Spi...

#890228 von looper
07.04.2012, 21:12
Sooo... jetzt habe ich mir es durchgelesen ;) War aber auch ein harter Brocken, die lange JS-Codes habe ich aus Frechheit einfach mal übersprungen :P

Viel zu mäkeln gibt es eigentlich nicht, aber ich habe mal etwas aufgeschrieben:

Du solltest erwähnen, dass das aufhübschen per styles kein HTML mehr ist, sondern CSS. Und dass das ganze natürlich auch in eine externe Datei ausgelagert werden kann, was natürlich lesbarer ist :lol:

Die Codeanweisung alert(1+1-5); gibt keinesfalls -4 aus, sondern -3.

Du hättest noch auf den wichtigen Unterschied von = und == aufmerksam machen können, ich hab mir sagen lassen, dass viele Anfänger damit Probleme haben ;)

Das Dollarzeichen "$" gibt an, dass es sich im Folgenden um einen jQuery Objekt handelt. Es handelt sich eigentlich um eine Funktion mit dem Namen "$", die ein jQuery Objekt zurückgibt. welches die Informationen über ein HTML-Element beinhaltet.


Es handelt sich im nachfolgenden keineswegs um ein jQuery-Objekt, sondern wie du gesagt hast, gibt das nur eine Funktion an. (btw. anstatt des Punktes zum 2. Satz ein Komma :)) Das Objekt enthält nicht zwingend die Daten zu einem Element, sondern die Informationen zu allen Elementen, die auf den CSS-Selektor, den man angibt, passen. D.h., dass es null, ein oder mehrere Elemente geben kann.


Zu einem späteren Absatz: Ein Browser wertet eine Endlosschleife afaik nicht als Hängenbleiben auf. Das Hängenbleiben ist dann gegeben, wenn der Thread, der für die JS-Berechnung zuständig ist, nicht mehr antwortet.(Moderne Browser, alte sterben einfach ab :lol:)


Alles in allem nichts schwerwiegendes, nebenbei noch ein paar extrem kleine Gramatikfehler, aber nichts, was dem Lesefluss Abbruch tut.

Übrigens wäre das ganze auch einfach ohne jquery möglich gewesen, da du mit den Funktionen document.getElementById() und document.getElementsByClassName() auch einfach auf DOM-Elemente zugreifen kannst, und durch die style-Eigenschaft dieser Objekte die Style-Eigenschaften auch manipulieren kannst. Die Tastendrücke könntest du dann in deiner Update-Schleife abfangen.

Allgemein ist dir dieses Tutorial sehr einsteigerfreundlich und einfach gelungen, die minimalen Fehler sind zu vernachlässigen. Es freut mich, dass du dich da ran gesetzt hast und dir die Mühe gemacht hast, diesen langen Text nieder zu schreiben.
-0
+0

Re: [Guide] Pong = Browser-Spi...

#890513 von DerSpieler
09.04.2012, 02:58
Ich habe auch damit angefangen nochmal alles zu lesen und mir sind in der Tat auch ein paar kleinere Fehler aufgefallen.
Einige Sätze habe ich deswegen etwas umformuliert oder ein kleines Wörtchen eingefügt.

CSS wurde aber auch schon in der ersten Fassung erwähnt. Auf das Ansprechen von CSS-Stylesheets usw. habe ich absichtlich verzichtet um nicht unnötige Verwirrung zu stiften. Ich denke es ist für den Anfang einfacher wenn der Style-Code, der zu einem Element gehört auch in dessen unmittelbarer Nähe steht und bei relativ kleinen Seiten (wie hier) verwende ich auch so ganz gerne mal Inline-Styles (besonders wenn auf Klassen verzichtet wird würde man sich auch keine Schreibarbeit damit sparen ^^).
looper hat geschrieben:Die Codeanweisung alert(1+1-5); gibt keinesfalls -4 aus, sondern -3.
Aua..!
Der Satz über das jQuery-Objekt ist wahrscheinlich wirklich etwas unglücklich formuliert. Gemeint ist wie du sagtest etwas wie die "Funktion "$" gibt ein jQuery-Objekt zurück". Ich werde diesen (wenn ich mit Durchlesen dort ankomme) sicherlich überdenken. Gleiches gilt für die "und"-Verknüpfung.
Mir ist natürlich klar, dass das jQuery Objekt bei anderer Anwendung auch Informationen zu mehr als einem Element beinhalten kann. Es ist wie oben wegen der Anti-Verwirrungs-Politik unterschlagen worden, da für den Guide irrelevant.

Der Grund für Probleme mit Endlosschleifen war mir selbst tatsächlich nicht vollständig klar. Ich wusste eben nur so viel, dass sie nicht funktionieren und eine Meldung wie "Firefox reagiert nicht" genrieren können. Ich würde für den Guide aber gern über eine Erklärung zu "Threads" verzichten - darum lasse ich die "phänomenoligische" Erklärung mal so stehen.

Es ist auch klar, dass man (was allgemein gilt) auch ohne jQuery klar kommt. Gerade mit dem Zugriff auf CSS-Eigentschaften mit reinem (roh) Javascript habe ich aber keine große Erfahrung und ich schreibe gern über das, was ich kann. Es schadet auch sicherlich nicht jQuery zu lernen, wenn man in Zukunft vor hat, auch größere Projekte mit Javascript zu erstellen und das eigentliche Ziel des Guide bleibt ja das Erlernen wertvoller "Skills".
Tastaturabfrage ohne Action-Listener würde mich aber auch ganz privat interessieren, da das bekanntlich auch mal "sicherer" sein kann. Ich werde mich in dieser Richtung also mal weiterbilden.

Jedenfalls großes DANKE für die Mühe und die vielen hilfreichen Hinweise.
-0
+0

Re: [Guide] Pong = Browser-Spi...

#897906 von Dark_Fire
14.05.2012, 16:01
Ja, ist zwar schon älter das Thema, ich gebe trotzdem noch Feedback.

Ich finde diesen Guide ... ja ... "etwas" lang, sprich 5 Minuten ist nich^^
Ich habe den Guide zwar net komplett gelesen, doch erkennt man das duz dir Mühe gegeben hast! Und zwar ne Menge!
Mach weiter so ;)
-0
+0

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast