Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage
<< | < | > | >> | API | Kapitel 39 - Applets I

## 39.4 Animation in Applets

- 39.4 Animation in Applets

Animation ist in Applets ebenso möglich wie in Applikationen. Alle Techniken, die in Kapitel 34 erklärt wurden, sind grundsätzlich auch auf Applets anwendbar. Aufgrund der Tatsache, daß Applets in einem Browser laufen und über eine Netzwerk-Fernverbindung mit Daten versorgt werden müssen, sollten folgende Besonderheiten beachtet werden:

- Ein animiertes Applet sollte in einem eigenen Thread laufen. Andernfalls würde möglicherweise der Browser lahmgelegt werden und nicht mehr auf Benutzereingaben reagieren.
- Die Animation in Applets kann durch Sound unterstützt werden.
- Das Laden von Sound- und Image-Dateien kann unter Umständern sehr lange dauern und liegt in der Regel um Größenordnungen über den Ladezeiten im lokalen Betrieb. Müssen während der Applet-Initialisierung größere Dateien geladen werden, kann das Starten des Applets für Anwender mit langsamen Netzwerkverbindungen schwierig werden.

Wir wollen uns diese Regeln zu eigen machen und in diesem Abschnitt ein einfaches animiertes Applet entwickeln. Das Programm soll die Skyline einer Großstadt bei Nacht darstellen. Dabei gehen in den Wolkenkratzern die Lichter an und aus, auf einigen Dächern gibt es rote Blinklichter, und von Zeit zu Zeit schlägt der Blitz mit Krachen in einen der Wolkenkratzer ein. (Diese Aufgabenstellung erinnert nicht ganz zu Unrecht an einen bekannten Bildschirmschoner.) Abbildung 39.4 zeigt einen Schnappschuß des laufenden Programms.

Abbildung 39.4: Das Wolkenkratzer-Beispielprogramm

Das Programm implementiert zwei Klassen, `Skyscraper` und `SkyscraperApplet`. `Skyscraper` repräsentiert einen Wolkenkratzer, der die Membervariablen x- und y-Position, Höhe, Breite und Anzahl der Fenster in x- und y-Richtung besitzt. Zusätzlich kann ein `Skyscraper`-Objekt auf Simulations-Events reagieren, die durch den Aufruf der Methode `LightEvent` ausgelöst werden. In diesem Fall wird das Licht in einem der Fenster an- oder ausgeschaltet oder das rote Blinklicht auf dem Dach getriggert.

Das eigentliche Applet wird durch die Klasse `SkyscraperApplet` realisiert. In der `init`-Methode wird zunächst eine Reihe von `Skyscraper`-Objekten erzeugt und im `Vector c` abgelegt. Zusätzlich werden die Parameter `DELAY`, `FLASH` und `THUNDER` eingelesen, die zur Steuerung der Animationsverzögerung, der Blitzwahrscheinlichkeit und der Sound-Datei für den Donner dienen. In der Methode `start` wird ein Thread erzeugt, so daß die eigentliche Animation mit der `repaint`-Schleife in `run` abläuft. Um das Bildschirmflackern zu verringern, wird `update` überlagert, wie in Kapitel 34 erläutert. In `paint` wird per Zufallszahlengenerator eines der in `v` gespeicherten `Skyscraper`-Objekte ausgewählt und dessen `LigthEvent`-Methode aufgerufen, um ein Beleuchtungsereignis zu simulieren.

Manchmal wird auch noch die Methode `Lightning` aufgerufen, um einen Blitzeinschlag darzustellen. Ein Blitz wird dabei durch einen Streckenzug vom oberen Bildrand bis zur Dachspitze eines Hochhauses dargestellt. Dieser Streckenzug wird für einen kurzen Augenblick in weißer Farbe auf den Bildschirm gezeichnet und anschließend durch erneutes Zeichnen in schwarzer Farbe wieder entfernt. Um ein realistisches Flackern zu erreichen, wird dieser Vorgang noch einmal wiederholt. Unmittelbar vor der Darstellung des Blitzes wird das zuvor geladene Donnergeräusch abgespielt.

Hier ist der Quellcode des Applets:

    001 /* SkyscraperApplet.java */
    002
    003 import java.awt.*;
    004 import java.util.*;
    005 import java.applet.*;
    006
    007 class Skyscraper
    008 {
    009   public int x;
    010   public int y;
    011   public int width;
    012   public int height;
    013   int        wndcntx;
    014   int        wndcnty;
    015   boolean    blinkon = false;
    016
    017   Skyscraper(int x, int y)
    018   {
    019     this.x = x;
    020     this.y = y;
    021     this.width = (int)(30*(0.5+Math.random()));
    022     this.height = (int)(100*(0.5+Math.random()));
    023     wndcntx = (width-4)/5;
    024     wndcnty = (height-4)/5;
    025   }
    026
    027   void LightEvent(Graphics g)
    028   {
    029     double rnd  = Math.random();
    030     int    xwnd = (int)(Math.random()*wndcntx);
    031     int    ywnd = (int)(Math.random()*wndcnty);
    032     if (blinkon) {
    033       g.setColor(Color.black);
    034       g.fillRect(x+width/2,y-height-20,2,2);
    035       blinkon = false;
    036     }
    037     if (rnd >= 0.9) {
    038       blinkon = true;
    039       g.setColor(Color.red);
    040       g.fillRect(x+width/2,y-height-20,2,2);
    041     } else if (rnd >= 0.7) {
    042       g.setColor(Color.black);
    043       g.fillRect(x+2+xwnd*5,y-height+2+ywnd*5,2,2);
    044     } else {
    045       g.setColor(Color.yellow);
    046       g.fillRect(x+2+xwnd*5,y-height+2+ywnd*5,2,2);
    047     }
    048   }
    049 }
    050
    051 public class SkyscraperApplet
    052 extends Applet
    053 implements Runnable
    054 {
    055   //Membervariablen
    056   Thread th;
    057   Vector v = new Vector();
    058   AudioClip thunder;
    059   boolean running;
    060
    061    //Parameter
    062   int    DELAY;
    063   float  FLASH;
    064   String THUNDER;
    065
    066   public void init()
    067   {
    068     Skyscraper house;
    069     int x = 5;
    070
    071     //Häuser erzeugen
    072     while (this.getSize().width-x-1 >= 30) {
    073       house = new Skyscraper(x,this.getSize().height-10);
    074       v.addElement(house);
    075       x += house.width + 5;
    076     }
    077     setBackground(Color.black);
    078
    079     //Parameter einlesen
    080     try {
    081       DELAY = Integer.parseInt(getParameter("delay"));
    082     } catch (NumberFormatException e) {
    083       DELAY = 75;
    084     }
    085     try {
    086       FLASH = (new Float(getParameter("flash"))).floatValue();
    087     } catch (NumberFormatException e) {
    088       FLASH = 0.01F;
    089     }
    090     THUNDER = getParameter("thunder");
    091     if (THUNDER != null) {
    092       thunder = getAudioClip(getCodeBase(),THUNDER);
    093     }
    094     System.out.println("DELAY = "+DELAY);
    095     System.out.println("FLASH = "+FLASH);
    096     System.out.println("THUNDER = "+THUNDER);
    097   }
    098
    099   public void start()
    100   {
    101     if (th == null) {
    102       running = true;
    103       th = new Thread(this);
    104       th.start();
    105     }
    106   }
    107
    108   public void stop()
    109   {
    110     if (th != null) {
    111       running = false;
    112       th = null;
    113     }
    114   }
    115
    116   public void run()
    117   {
    118     while (running) {
    119       repaint();
    120       try {
    121         Thread.sleep(DELAY);
    122       } catch (InterruptedException e) {
    123         //nothing
    124       }
    125     }
    126   }
    127
    128   public void update(Graphics g)
    129   {
    130     paint(g);
    131   }
    132
    133   public void paint(Graphics g)
    134   {
    135     int i;
    136     Skyscraper house;
    137
    138     i = (int)Math.floor(Math.random()*v.size());
    139     house = (Skyscraper)v.elementAt(i);
    140     house.LightEvent(g);
    141     if (Math.random() < FLASH) {
    142       Lightning(g,house.x+10,house.y-house.height);
    143     }
    144   }
    145
    146   public void Lightning(Graphics g, int x, int y)
    147   {
    148     Vector poly = new Vector();
    149     int dx, dy, i, polysize;
    150
    151     thunder.play();
    152     //Blitzpolygon berechnen
    153     poly.addElement(new Point(x,y));
    154     polysize = 1;
    155     while (y > 10) {
    156       dx = 10 - (int)(Math.floor(Math.random()*20));
    157       dy = - (int)(Math.floor(Math.random()*20));
    158       x += dx;
    159       y += dy;
    160       poly.addElement(new Point(x,y));
    161       ++polysize;
    162     }
    163     //Blitzvector in Koordinaten-Arrays umwandeln
    164     int[] xpoints = new int[poly.size()];
    165     int[] ypoints = new int[poly.size()];
    166     for (i = 0; i < polysize; ++i) {
    167       Point p = (Point)poly.elementAt(i);
    168       xpoints[i] = p.x;
    169       ypoints[i] = p.y;
    170     }
    171     //Blitz zeichnen
    172     for (i = 0; i <= 1; ++i) {
    173       g.setColor(Color.white);
    174       g.drawPolyline(xpoints, ypoints, polysize);
    175       try {
    176         Thread.sleep(20);
    177       } catch (InterruptedException e) {}
    178       g.setColor(Color.black);
    179       g.drawPolyline(xpoints, ypoints, polysize);
    180       try {
    181         Thread.sleep(20);
    182       } catch (InterruptedException e) {}
    183     }
    184   }
    185 }
| SkyscraperApplet.java

Listing 39.9: Das Wolkenkratzer-Applet

Zum Aufruf des Applets kann beispielsweise folgende HTML-Datei verwendet werden:

    001 <html>
    002 <head>
    003 <title>Skyscraper</title>
    004 </head>
    005 <body>
    006 <h1>Skyscraper</h1>
    007 <applet code=SkyscraperApplet.class width=500 height=300>
    008 <param name="delay"   value=75>
    009 <param name="flash"   value=0.01>
    010 <param name="thunder" value="thunder.au">
    011 Hier steht das Applet Skyscraper.class
    012 </applet>
    013 </body>
    014 </html>
| SkyscraperApplet.html

Listing 39.10: Die HTML-Datei zum Aufrufen des Wolkenkratzer-Applets

Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage, Addison Wesley, Version 3.0
<< | < | > | >> | API | © 1998-2002 Guido Krüger, http://www.javabuch.de