P. Pfahler, E. Stümpel

Programmieren in Java, Winter 1997/98

6. Übungsblatt, Lösungsvorschlag


Aufgabe 10 (Arrays, Applets, Animationen)

Vorgegeben war ein Animations-Applet, das einen Kreis in einem Rechteck bewegt. Diese Applet sollte so erweitert werden, daß als Parameter des Applets die Anzahl der darzustellenden Kreise angegeben werden kann.

Dafür sind im Quellcode folgende Veränderungen vorzunehmen:

Hier der veränderte Java - Quellcode:


//animnew.java

import java.applet.*;
import java.awt.*;

// Einfache Animation mit Double-Buffering

public class animnew extends Applet implements Runnable
{
  //eine innere Klasse fuer Kreise

  class kreis
  {
     final  int r;		//Radius
     final  Color f;		//Farbe
     public int x, y;		//Position
     public int dx, dy;		//Richtung

     public kreis ()
     {
        //Radius
        r = (int) (Math.random()*50+1);
	//Farbe
	f = new Color((float)Math.random(),(float)Math.random(),(float)Math.random());

        //Anfangspunkt
        x = (int) (Math.random() * animnew.this.size.width)/2 + r;
        y = (int) (Math.random() * animnew.this.size.height)/2 + r;
        //Anfangsrichtung
        dx = (int) (Math.random() * animnew.this.size.width)/50 + 3;
        dy = (int) (Math.random() * animnew.this.size.height)/50 + 3;

     }
  }

  //hier sind einige Attribute weggefallen, die jetzt in der Klasse Kreis enthalten sind
  Dimension size;                 // Größe des Applets
  Image offscreen;                // Off-sceen Bild
  Graphics offgraphics;           // Grafik-Object dafür
  Thread animator;                // Thread für die Animation
  boolean stop;                   // Zum Anhalten der Animation
  //neue Attribute
  int kreis_anz;		  // Anzahl zu animierender Kreise
  kreis kreise[];		  // Array für die Kreise

  public void init()
  { String rs;  //zum Einlesen des Parameters

    // Initialisierung der Off-Screen-Grafik
    size = this.size();

    //Parameter einlesen
    rs = getParameter("kreise");
    if (rs == null)               // keine Angabe
      rs="1";			  // -> ein Kreis
    kreis_anz = Integer.parseInt(rs);

    //Initialisierung der Kreisdaten
    kreise = new kreis[kreis_anz];
    for (int i = 0; i < kreis_anz; i++)
	kreise[i] = new kreis();

    offscreen = this.createImage(size.width, size.height);
    offgraphics = offscreen.getGraphics();
  }

  public void paint(Graphics g)
  { // Zeichne in den Off-Screen-Puffer 
    offgraphics.setColor(this.getBackground());  // Hintergrundfarbe
    offgraphics.fillRect(0, 0, size.width, size.height); // l÷schen

    //zeichne alle Kreise
    for (int j = 0; j < kreis_anz; j++)
    {
     offgraphics.setColor(kreise[j].f);
     offgraphics.fillOval(kreise[j].x-kreise[j].r, kreise[j].y-kreise[j].r, kreise[j].r*2, kreise[j].r*2);
    }
    // Kopiere die Zeichnung in die Anzeige
    g.drawImage(offscreen, 0, 0, this);
  }

  public void update(Graphics g)
  { // Sofort zeichnen ohne zu l÷schen
    paint(g);
  }

  public void run()
  { // Der Rumpf des Animations-Threads
    while (!stop)
      { // Bewegen, neuzeichnen, schlafen
	for (int i = 0; i < kreis_anz; i++)
	{
	 int oldx = kreise[i].x, oldy = kreise[i].y;  // alte Position merken
	 newposition(i);	                      // neue Position berechnen
         // alte Position neuzeichnen
	 repaint(oldx-kreise[i].r, oldy-kreise[i].r, 2*kreise[i].r, 2*kreise[i].r);
         // neue Position neuzeichnen
         repaint(kreise[i].x-kreise[i].r, kreise[i].y-kreise[i].r, 2*kreise[i].r, 2*kreise[i].r);
	 // die beiden repaints werden zu einem paint-aufruf verschmolzen
        }
        sleep(20);
      }
    animator = null;
  }

  public void newposition(int i)
  { // neue Position des Kreises
    kreise[i].x += kreise[i].dx;
    kreise[i].y += kreise[i].dy;
    // mal sehen, wo wir sind
    if (kreise[i].x - kreise[i].r < 0 || kreise[i].x + kreise[i].r > size.width)
      kreise[i].dx = -kreise[i].dx;
    if (kreise[i].y - kreise[i].r < 0 || kreise[i].y + kreise[i].r > size.height)
      kreise[i].dy = -kreise[i].dy;
  }
    
  public void sleep(int milliseconds)
  { // kleine Pause
    try 
      { 
	Thread.sleep(milliseconds);
      }
    catch (InterruptedException e) {}
  }
    
  public void start()
  { // Start des Animations-Threads
    if (animator == null)
      { 
	stop = false;
	animator = new Thread(this);       
	animator.start();                  // loslaufen 
      }
  }


  public void stop()
  { // Anhalten des Animations-Threads
    stop = true;
  }

  // Starten und stoppen per Maus-Klick
  public boolean mouseDown(Event e, int x, int y)
  {
    if (animator != null)
      stop = true;
    else start();
    return true;
  }
}
    

Gestartet mit dem Parameter 9 sieht das Ganze dann so aus:

animnew.java zum Mitnehmen