Benutzer-Werkzeuge

Webseiten-Werkzeuge


api:projects:pong:start

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
api:projects:pong:start [2020/12/29 13:57] Martin Pabstapi:projects:pong:start [2021/12/29 11:29] (aktuell) – Externe Bearbeitung 127.0.0.1
Zeile 1: Zeile 1:
-====== Beispielprojekt: Pong ====== +====== Projekt: Pong ====== 
-Pong ist eines der ersten ComputerspieleEs wurde 1972 von Atari entwickelt, [[https://de.wikipedia.org/wiki/Pong|mehr dazu hier im Wikipedia-Artikel]]. Ziel des Spiel ist es - ähnlich wie beim Tennisden Ball mit dem eigenen Schläger in die Hälfte des Gegners zu schlagen. Verfehlt man den Ballso erhält der Gegner einen Punkt. Der linke Schläger wird mit den Tasten a und q gesteuert, der rechte mit den Tasten ö und p.+{{ :projects:pong:pong.png?200|Quelle: https://commons.wikimedia.org/wiki/File:Pong.png}} 
 +<WRAP center round info 50%> 
 +Das 1972 von Atari veröffentlichte Pong war eines der ersten Computerspiele, [[https://de.wikipedia.org/wiki/Pong|hier mehr zu seiner Geschichte.]] \\ \\  
 +Zwei Spieler steuern je einen Schläger am linken bzwrechten Bildschirmrand und versucheneinen Ball so abprallen zu lassendass ihn der Gegner mit seinem Schläger nicht mehr erwischt, ähnlich wie beim Tennis. Der Ball prallt sowohl an den Schlägern als auch am oberen und unteren Bildschirmrand ab. Das gestrichelte "Netz" in der Mitte des Bildschirms hat spieltechnisch keine Bedeutung. 
 +</WRAP> 
 + \\  
 +===== Programmierung des Schlägers ===== 
 +{{ youtube>JdJu09JU7l4?large }} 
 +<HTML>
  
 +<div class="java-online" style="height: 400px; width: 80%" data-java-online="{'withBottomPanel': false, 'id': 'pongSchlaeger'}">
 +
 +<script type="text/plain" title="PongSchlaeger.java">
 +new Schläger(0, 20, 200, "q", "a");
 +new Schläger(800 - 20, 20, 200, Key.ArrowUp, Key.ArrowDown);
 +
 +class Schläger extends Rectangle {
 +   
 +   String tasteRauf;
 +   String tasteRunter;
 +
 +   double dy = 5;
 +   
 +   Schläger(double x, double breite, double höhe, String tasteRauf, String tasteRunter) {
 +      super(x,(600 - höhe) / 2, breite, höhe);
 +      
 +      this.tasteRauf = tasteRauf;
 +      this.tasteRunter = tasteRunter;
 +      
 +      setFillColor(Color.white);
 +      
 +   }
 +
 +   public void act() {
 +      if(isKeyDown(tasteRauf)) {
 +         if(getCenterY() > getHeight() / 2) {
 +            move(0, -dy);
 +         }
 +      }
 +      
 +      if(isKeyDown(tasteRunter)) {
 +         if(getCenterY() < 600 - getHeight() / 2) {
 +            move(0, dy);
 +         }
 +      }
 +      
 +   }
 +}
 +</script>
 +
 +</div>
 +
 +</HTML>
 +
 +
 + \\ 
 +===== Programmierung des Balls =====
 +{{ youtube>DIKP2A2S2x8?large }}
 <HTML> <HTML>
-<div class="java-online" style="height: 620px; width: 100%" data-java-online="{'withBottomPanel': true, 'id': 'Pong'}"> 
  
-<script type="text/plain" title="Pong.java"> +<div class="java-online" style="height: 400px; width: 80%" data-java-online="{'withBottomPanel': true, 'id': 'pongBall'}"> 
-// Im Hauptprogramm wird nur ein Pong-Objekt instanziertDadurch + 
-// wird der Konstruktor der Klasse Pong aufgerufenin dem  +<script type="text/plain" title="PongSchlaeger2.java"> 
-// die weiteren Objekte (SchlägerBall, ...) instanziert werden.+Schläger links = new Schläger(0, 20, 200, "q", "a"); 
 +Schläger rechts = new Schläger(800 - 20, 20, 200, Key.ArrowUp, Key.ArrowDown); 
 +new Ball(20, 400, 300, links, rechts); 
 + 
 +class Schläger extends Rectangle { 
 +    
 +   String tasteRauf; 
 +   String tasteRunter; 
 + 
 +   double dy = 5; 
 +    
 +   Schläger(double x, double breite, double höhe, String tasteRauf, String tasteRunter) { 
 +      super(x,(600 - höhe) 2, breite, höhe); 
 +       
 +      this.tasteRauf = tasteRauf; 
 +      this.tasteRunter = tasteRunter; 
 +       
 +      setFillColor(Color.white); 
 +       
 +   } 
 + 
 +   public void act() { 
 +      if(isKeyDown(tasteRauf)) { 
 +         if(getCenterY() > getHeight() 2) { 
 +            move(0, -dy); 
 +         } 
 +      } 
 +       
 +      if(isKeyDown(tasteRunter)) { 
 +         if(getCenterY() < 600 - getHeight() / 2) { 
 +            move(0, dy); 
 +         } 
 +      } 
 +   } 
 +
 +</script> 
 +<script type="text/plain" title="PongBall2.java"> 
 +class Ball extends Rectangle { 
 +    
 +   double vx; 
 +   double vy; 
 +   Schläger schlägerLinks; 
 +   Schläger schlägerRechts; 
 + 
 + 
 +   Ball(double breite, double x, double y, Schläger schlägerLinks, Schläger schlägerRechts) { 
 +      super(x - breite 2, y - breite 2breite, breite); 
 +      setFillColor(Color.white); 
 +      this.schlägerLinks = schlägerLinks; 
 +      this.schlägerRechts = schlägerRechts; 
 + 
 +      setzeZufallsGeschwindigkeit(); 
 +   } 
 + 
 +   public void act() { 
 +       
 +      move(vx, vy); 
 + 
 +      if(getCenterY() < getWidth() 2) { 
 +         vy = vy * (-1); 
 +      } 
 + 
 +      if(getCenterY() > 600 - getWidth() 2) { 
 +         vy = vy * (-1); 
 +      } 
 + 
 +      if(collidesWith(schlägerLinks) || collidesWith(schlägerRechts)) { 
 +         vx = vx * (-1); 
 +      } 
 + 
 +      if(getCenterX() < - getWidth() / 2) { 
 +         setzeZufallsGeschwindigkeit(); 
 +         setCenter(400300); 
 +      } 
 + 
 +      if(getCenterX() > 800 + getWidth() / 2) { 
 +         setzeZufallsGeschwindigkeit(); 
 +         setCenter(400300); 
 +      } 
 + 
 +   } 
 +    
 + 
 +   void setzeZufallsGeschwindigkeit() { 
 + 
 +      double r = Math.random() * 5 + 5; 
 +      double winkelGrad = Math.random() * 50 + 20; 
 +      double winkelRad = winkelGrad / 180 * Math.PI; 
 +       
 +      vx = r * Math.cos(winkelRad)
 +      vy = - r * Math.sin(winkelRad); 
 + 
 +      if(Math.random() < 0.5) { 
 +         vx = -vx; 
 +      } 
 + 
 +      if(Math.random() < 0.5) { 
 +         vy = -vy; 
 +      } 
 +   } 
 +
 +</script> 
 + 
 +</div> 
 + 
 +</HTML> 
 + \\  
 +===== Hauptprogramm, Punkteanzeige, Startbildschirm, Game over ===== 
 +{{ youtube>V0LthmW7Qqo?large }} 
 +<HTML> 
 + 
 +<div class="java-online" style="height: 500px; width: 80%" data-java-online="{'withBottomPanel': true, 'id': 'pongKomplett'}"> 
 + 
 +<script type="text/plain" title="Pong3.java">
 new Pong(); new Pong();
  
-class Pong {+class Pong extends Actor {
        
-   private Schläger schlägerLinks+   Text punkteanzeige; 
-   private Schläger schlägerRechts+    
-   private Ball ball;+   Text großeAnzeige; 
 + 
 +   int punkteLinks = 0; 
 +   int punkteRechts = 0; 
 + 
 +   String zustand; 
 + 
 +   Schläger links
 +   Schläger rechts
 +   Ball ball
 + 
 +   Pong() { 
 +      super(); 
 +      links = new Schläger(0, 20, 200, "q", "a"); 
 +      rechts = new Schläger(800 - 20, 20, 200, Key.ArrowUp, Key.ArrowDown); 
 +      ball = new Ball(20, 400, 300, links, rechts, this);
  
-   private Text punkteAnzeige;+      punkteanzeige = new Text(400, 20, 64, ""); 
 +      punkteanzeige.setAlignment(Alignment.center); 
 +      punkteanzeige.setFillColor(Color.white); 
 +      punkteAnzeigen();
  
-   // In diesen Attributen wird der Spielstand gespeichert: +      großeAnzeige new Text(400, 150, 140, "PONG")
-   private int punkteLinks 0+      großeAnzeige.setAlignment(Alignment.center); 
-   private int punkteRechts = 0;+      großeAnzeige.setFillColor(Color.white);
  
-   /* +      setZustand("Vor dem Spiel");
-    * Im Konstruktor werden die Schläger, der Ball und die Punkteanzeige  +
-    * instanziert. Danach ist das Hauptprogramm beendet. Weiter gehts in  +
-    * den act-Methoden der Schläger und des Balls, die 30-mal pro Sekunde +
-    * vom Browser aufgerufen werden. +
-    */ +
-   public Pong() { +
-      schlägerLinks = new Schläger(0, 100, "q", "a"); +
-      schlägerRechts = new Schläger(800 - 30, 100, "p", "ö"); +
-      ball = new Ball(schlägerLinks, schlägerRechts, this); +
-      punkteAnzeige = new Text(400, 10, 48, "0 : 0"); +
-      punkteAnzeige.setAlignment(Alignment.center); +
-      punkteAnzeige.setFillColor(Color.white);+
    }    }
  
-   /* +   public void onKeyTyped(String key) { 
-    * Zeigt den aktuellen Punktestand an +      if(key == " " && zustand == "Vor dem Spiel") { 
-    */ +         setZustand("Im Spiel"); 
-   private void zeigePunkte() { +      } else  
-      punkteAnzeige.setText(punkteLinks + + punkteRechts);+      if(key == " " && zustand == "Game over") { 
 +         setZustand("Vor dem Spiel"); 
 +      }
    }    }
  
-   /* +   void punkteAnzeigen() { 
-    * Wird von der act-Methode des Balls aufgerufen, wenn der Ball den rechten +      punkteanzeige.setText(punkteLinks + " : " punkteRechts)
-    * Bildschirmrand überschreitet. +       
-    */ +      if((punkteLinks == 3 || punkteRechts == 3) && zustand == "Im Spiel") { 
-   public void punktFürLinkenSpieler() { +         setZustand("Game over");    
-      punkteLinks++; +      }
-      zeigePunkte();+
    }    }
  
-   /* +   void punktFürRechtenSpieler() {
-    * Wird von der act-Methode des Balls aufgerufen, wenn der Ball den linken +
-    * Bildschirmrand überschreitet. +
-    */ +
-   public void punktFürRechtenSpieler() {+
       punkteRechts++;       punkteRechts++;
-      zeigePunkte();+      punkteAnzeigen();
    }    }
  
 +   void punktFürLinkenSpieler() {
 +      punkteLinks++;
 +      punkteAnzeigen();
 +   }
 +
 +   void setZustand(String neuerZustand) {
 +      
 +      if(neuerZustand == "Vor dem Spiel") {
 +         links.setVisible(false);
 +         rechts.setVisible(false);
 +         ball.setVisible(false); 
 +         punkteanzeige.setVisible(false);
 +         großeAnzeige.setVisible(true);
 +         großeAnzeige.setText("PONG");
 +      } else if(neuerZustand == "Im Spiel") {
 +         links.setVisible(true);
 +         rechts.setVisible(true);
 +         ball.setVisible(true); 
 +         punkteanzeige.setVisible(true);
 +         großeAnzeige.setVisible(false);
 +         ball.setzeZufallsGeschwindigkeit();
 +         ball.setCenter(400, 300);
 +         punkteLinks = 0;
 +         punkteRechts = 0;
 +         punkteAnzeigen();
 +      } else if(neuerZustand == "Game over") {
 +         links.setVisible(false);
 +         rechts.setVisible(false);
 +         ball.setVisible(false); 
 +         großeAnzeige.setVisible(true);
 +         großeAnzeige.setText("Game over"); 
 +      }
 +
 +      zustand = neuerZustand;
 +
 +   }
 } }
 </script> </script>
  
-<script type="text/plain" title="Schläger.java"> +<script type="text/plain" title="Schlaeger3.java">
-/** +
- * Ein Objekt der Klasse Schläger stellt den Schläger als Rechteck dar und bewegt ihn nach +
- * oben/unten wenn die Taste tasteHoch/tasteRunter gedrückt wird. +
- */+
 class Schläger extends Rectangle { class Schläger extends Rectangle {
        
-   private String tasteHoch       // Taste, mit der der Schläger hochbewegt wird +   String tasteRauf
-   private String tasteRunter;      // Taste, mit der der Schläger runterbewegt wird+   String tasteRunter; 
 + 
 +   double dy = 5;
        
-   private int geschwindigkeit = 8; // Geschwindigkeit des Schlägers in Pixel pro 1/30 s +   Schläger(double x, double breite, double höhe, String tasteRauf, String tasteRunter) { 
-    +      super(x,(600 - höhe) / 2breite, höhe); 
-   /** +       
-    * Im Konstruktor wird das Schläger-Rechteck initialisiert. Damit die Schläger-Klasse sowohl zum  +      this.tasteRauf tasteRauf;
-    * Erzeugen des linken als auch des rechten Schläger-Objekts verwendet werden kann, werden dem Konstruktor +
-    * die x-Koordinate des linken Randes sowie die zwei Tasten zur Steuerung des Schlägers als Parameter übergeben. +
-    */ +
-   public Schläger(double links, double höhe, String tasteHoch, String tasteRunter) { +
-      super(links020, höhe); +
-      this.tasteHoch tasteHoch;+
       this.tasteRunter = tasteRunter;       this.tasteRunter = tasteRunter;
-      move(0,(getWorld().getHeight() - höhe) / 2);+      
       setFillColor(Color.white);       setFillColor(Color.white);
 +      
    }    }
  
-   /** 
-    * Die Methode act wird 30-mal pro Sekunde vom Browser aufgerufen. 
-    */ 
    public void act() {    public void act() {
-      /* +      if(isKeyDown(tasteRauf)) {
-       * Die Klasse Rectangle besitzt eine Methode isKeyDown, die genau dann true zurückgibt, wenn +
-       * eine bestimmte Taste gerade gedrückt ist.  +
-       */ +
-      if(isKeyDown(tasteHoch)) { +
-         // Falls der Schläger noch nicht am oberen Rand anschlägt, bewege ihn hoch:+
          if(getCenterY() > getHeight() / 2) {          if(getCenterY() > getHeight() / 2) {
-            move(0, -geschwindigkeit);+            move(0, -dy);
          }          }
       }       }
              
       if(isKeyDown(tasteRunter)) {       if(isKeyDown(tasteRunter)) {
-         // Falls der Schläger noch nicht am unteren Rand anschlägt, bewege ihn runter: +         if(getCenterY() < 600 - getHeight() / 2) { 
-         if(getCenterY() < getWorld().getHeight() - getHeight() / 2) { +            move(0, dy);
-            move(0, geschwindigkeit);+
          }          }
       }       }
 +      
    }    }
-    +}
-+
 </script> </script>
  
-<script type="text/plain" title="Ball.java"> +<script type="text/plain" title="Ball3.java">
-/** +
- * Die Klasse Ball stellt den Ball am Bildschirm dar, bewegt ihn, reagiert auf Kollision +
- * mit den Schlägern und dem oberen/unteren Bildschirmrand. Sie registriert auch, ob der Ball +
- * den sichtbaren Bereich rechts oder links verlässt und veranlasst dann die Änderung des Spielstands  +
- * sowie einen Abstoß in der Mitte des Bildschirms. +
- */+
 class Ball extends Rectangle { class Ball extends Rectangle {
        
-   private double vx;   // x-Komponente der Ballgeschwindigkeit (in Pixel je 1/30 s) +   double vx; 
-   private double vy;   // y-Komponente der Ballgeschwindigkeit+   double vy; 
 +   Schläger schlägerLinks; 
 +   Schläger schlägerRechts; 
 +   Pong pong;
  
-   private double breite = 20;   // Breite und zugleich Höhe des Ball-Rechtecks 
  
-   private Schläger schlägerLinks;  // Referenz auf das linke Schläger-Objekt +   Ball(double breite, double x, double y, Schläger schlägerLinks, Schläger schlägerRechts,  
-   private Schläger schlägerRechts; // Referenz auf das rechte Schläger-Objekt +      Pong pong) { 
- +      super(- breite / 2, - breite / 2, breite, breite);
-   private Pong pong;               // Referenz auf das Pong-Objekt +
- +
-   /** +
-    * Der Konstruktor der Klasse Ball initialisiert das Ball-Rechteck. +
-    */ +
-   public Ball(Schläger schlägerLinks, Schläger schlägerRechts, Pong pong) { +
-      super(400 - breite / 2, 300 - breite / 2, breite, breite);  // Aufruf des Konstruktors der Oberklasse Rectangle +
-      setzeZufallsGeschwindigkeit();+
       setFillColor(Color.white);       setFillColor(Color.white);
- 
-      this.schlägerRechts = schlägerRechts; 
       this.schlägerLinks = schlägerLinks;       this.schlägerLinks = schlägerLinks;
 +      this.schlägerRechts = schlägerRechts;
       this.pong = pong;       this.pong = pong;
 +
 +      setzeZufallsGeschwindigkeit();
    }    }
  
-   /** 
-    * Die Methode act wird vom Browser 30-mal pro Sekunde aufgerufen. Sie bewegt den Ball und 
-    * reagiert auf Kollisionen mit den Schlägern, dem oberen/unteren Rand sowie auf das Verlassen 
-    * des Grafikbereichs rechts/links. 
-    */ 
    public void act() {    public void act() {
-      move(vx, vy);  // bewegt den Ball 
              
-      // stößt der Ball am oberen/unteren Rand an? => vy umkehren +      if(pong.zustand != "Im Spiel") { 
-      if(getCenterY() < breite / 2 || getCenterY() > getWorld().getHeight() - breite / 2) { +         return
-         vy *= -1+      }
-      } +
  
-      // Kollision mit Schläger links?  +      move(vx, vy);
-      if(this.collidesWith(schlägerLinks)) { +
-         vx *= -1  // vx umkehren+
  
-         // Abhängig von der Auftreffstelle auf dem Schläger ändern wir vy +      if(getCenterY() < getWidth() / 2) { 
-         double dy = schlägerLinks.getCenterY() - getCenterY(); +         vy = vy * (-1);
-         vy +dy / schlägerLinks.getHeight() * 3;+
       }       }
  
-      // Kollision mit Schläger rechts? +      if(getCenterY() > 600 getWidth() / 2) { 
-      if(this.collidesWith(schlägerRechts)) { +         vy = vy * (-1);
-         vx *= -1; +
-         double dy = schlägerRechts.getCenterY() - getCenterY(); +
-         vy +dy / schlägerRechts.getHeight() * 2;+
       }       }
  
-      // Wenn sich der Ball schon um vx weiter links befindet als bei Berührung mit dem linken Schläger, +      if(collidesWith(schlägerLinks) || collidesWith(schlägerRechts)) { 
-      // dann lassen wir kein Abprallen mit dem Schläger mehr zu, sondern werten es als Punkt für den  +         vx = vx * (-1);
-      // rechten Spieler: +
-      if(getCenterX() < schlägerLinks.getWidth(+ breite / 2 - Math.abs(vx)) { +
-         setCenter(400, 300);             // Abstoß in der Mitte des Grafikbereichs +
-         setzeZufallsGeschwindigkeit(); +
-         pong.punktFürRechtenSpieler();+
       }       }
-       + 
-      // ... entsprechend für den rechten Bildschirmrand: +      if(getCenterX() - getWidth() / 2) { 
-      if(getCenterX() > getWorld().getWidth() schlägerRechts.getWidth() - breite / 2 + Math.abs(vx)) { +         pong.punktFürRechtenSpieler();
-         setCenter(400, 300);+
          setzeZufallsGeschwindigkeit();          setzeZufallsGeschwindigkeit();
 +         setCenter(400, 300);
 +      }
 +
 +      if(getCenterX() > 800 + getWidth() / 2) {
          pong.punktFürLinkenSpieler();          pong.punktFürLinkenSpieler();
 +         setzeZufallsGeschwindigkeit();
 +         setCenter(400, 300);
       }       }
  
    }    }
 +   
  
-   /** +   void setzeZufallsGeschwindigkeit() {
-    * Diese Methode gibt dem Ball eine zufällige Geschwindigkeit. Dabei dürfen aber keine Geschwindigkeitsvektoren +
-    * entstehen, die zu "flach" oder "steil" sind, da das Spiel sonst langweilig wird. +
-    */ +
-   public void setzeZufallsGeschwindigkeit() { +
-      double v = Math.random() * 4 + 8;      // Betrag der Geschwindigkeit zwischen 8 und 12 (Pixel je 1/30 s) +
-      double winkel = Math.random() * Math.PI / 4 + Math.PI / 8;  // Winkel zwischen 22,5 und 67,5 Grad +
-      vx = Math.cos(winkel) * v; +
-      vy = Math.sin(winkel) * v; +
-      if(Math.random() < 0.5) vx *= -1;   // mit 50% Wahrscheinlichkeit: Spiegeln an der y-Achse +
-      if(Math.random() < 0.5) vy *= -1;   // mit 50% Wahrscheinlichkeit: Spiegeln an der x-Achse +
-   }+
  
 +      double r = Math.random() * 5 + 5;
 +      double winkelGrad = Math.random() * 50 + 20;
 +      double winkelRad = winkelGrad / 180 * Math.PI;
 +      
 +      vx = r * Math.cos(winkelRad);
 +      vy = - r * Math.sin(winkelRad);
 +
 +      if(Math.random() < 0.5) {
 +         vx = -vx;
 +      }
 +
 +      if(Math.random() < 0.5) {
 +         vy = -vy;
 +      }
 +   }
 } }
 </script> </script>
 +
 </div> </div>
 +
 </HTML> </HTML>
 + \\ 
 +===== Aufgaben =====
 +Erweitere das PONG-Spiel folgendermaßen:
 +  - Wenn der Ball am oberen oder unteren Rand abprallt, soll ein tiefer Ton zu hören sein (Anweisung ''Sound.playSound(Sound.pong_d);''), wenn er an einem Schläger abprallt, soll ein hoher Ton zu hören sein (Anweisung ''Sound.playSound(Sound.pong_f);'').
 +  - Oft dauert es ewig, bis ein Tor erzielt wird. Je länger der Ball im Spiel ist, desto schneller soll er werden. Gleichzeitig soll auch die Geschwindigkeit der Schläger zunehmen. Sobald ein Tor erzielt wird, soll die Geschwindigkeit der Schläger wieder auf den ursprünglichen Wert zurückgesetzt werden.
 +  - Herausforderung (freiwillig): Wenn der Ball einen Schläger mittig trifft, soll er ganz normal abprallen. Je weiter außen er den Schläger trifft, desto stärker soll er zusätzlich in diese Richtung abgelenkt werden.
 +
 +
api/projects/pong/start.1609246655.txt.gz · Zuletzt geändert: 2021/12/29 11:29 (Externe Bearbeitung)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki