import scala.actors.Actor import scala.actors.Actor._ import java.awt.Color; import Color._ import scala.math._ /** Diese Klasse implementiert ein Raumschiff, das sich mit zufällig gewählter * Geschwindigkeit durchs Weltall bewegt und mit konstanter Frequenz Wellen aussendet. */ class Raumschiff(val name: String, val farbe: Color) extends Actor { /** Ellipsenhalbachsen [in Pixel] der Raumschiffform. */ val a = (20 * random).toInt + 5; val b = a/2 /** Entstehungszeitpunkt. */ val baujahr = System.currentTimeMillis() /** Schwerpunkt zum Entstehungszeitpunkt [in Pixelkoordinaten des Weltalls]. */ val x_0 = (((Weltall.width - 2*a)*random).toInt + a, ((Weltall.height - 2*b)*random).toInt + b) /** Geschwindigkeitsvektor [in Pixel / sec]. */ var v = (100*random - 25, 50*random - 25) /** Sendefrequenz [in Hz]. */ val f = 1./2. start def act { Weltall ! ('erzeuge, self) for (i <- 1 to 10000) { val t = (System.currentTimeMillis() - baujahr) / 1000. // Alter in sec val x = Weltall.add(x_0, (v._1 * t, v._2 * t)) if (i % (Weltall.bildfrequenz/f).toInt == 0) new Wellenfront(x, farbe) Thread.sleep((1000. / Weltall.bildfrequenz).toInt) } } } /** Diese Klasse implementiert einen Fixstern, das sich mit zufällig gewählter * Geschwindigkeit durchs Weltall bewegt und mit konstanter Frequenz Wellen aussendet. */ class Stern(val name: String, val farbe: Color) extends Actor { /** Radius [in Pixel]. */ val r = (10 * random).toInt + 5 /** Mittelpunkt [in Pixelkoordinaten des Weltalls]. */ var x = (((Weltall.width - 2*r)*random).toInt + r, ((Weltall.height - 2*r)*random).toInt + r) start def act { Weltall ! ('erzeuge, self) loop { react { case 'senden => new Wellenfront(x, farbe) } } } } class Wellenfront(val zentrum: (Int,Int), val farbe: Color) { /** Entstehungszeit der Wellenfront.*/ val geburt = System.currentTimeMillis /** Wellengeschwindigkeit [Pixel / Millisekunde]. */ val c = 50./1000. Weltall ! ('erzeuge, this) } object Weltenzeichner extends Actor { // Singleton! def act { loop { Thread.sleep((1000. / Weltall.bildfrequenz).toInt) Weltall.repaint() } } } object Weltall extends scala.swing.Panel with Actor { // Singleton! val width = 1200; val height = 700; //val width = 800; val height = 600; val bildfrequenz = 20. // [Hz] var sterne = List.empty[Stern] var raumschiffe = List.empty[Raumschiff] var wellen = List.empty[Wellenfront] peer.addMouseListener(new java.awt.event.MouseAdapter() { override def mouseClicked(evt: java.awt.event.MouseEvent) { val x = (evt.getX(), evt.getY()) for (stern <- sterne) { if (Weltall.abstand(stern.x, x) < stern.r) { stern ! 'senden } } } }); start Weltenzeichner.start /** Zeichnet die Fläche dieses Panels. Wird auch von repaint aufgerufen. */ override def paint(g: java.awt.Graphics2D) { g.setColor(BLACK) g.fillRect(0, 0, peer.getWidth, peer.getHeight) for (stern <- sterne) { g.setColor(stern.farbe) g.fillOval(stern.x._1 - stern.r, stern.x._2 - stern.r, 2*stern.r, 2*stern.r) } for (rs <- raumschiffe) { val t = (System.currentTimeMillis() - rs.baujahr) / 1000. // Alter in sec val x = Weltall.add(rs.x_0, (rs.v._1 * t, rs.v._2 * t)) g.setColor(rs.farbe) g.fillOval(x._1 - rs.a, x._2 - rs.b, 2*rs.a, 2*rs.b) } val daempfung = 1.5 // linearer Dämpfungsfaktor der Welle ( for (w <- wellen) { val radius = ((System.currentTimeMillis() - w.geburt) * w.c).round.toInt if (radius < Weltall.width / daempfung) { val alpha = (255*(1 - daempfung*radius/Weltall.width)).toInt g.setColor(new Color(w.farbe.getRed, w.farbe.getGreen, w.farbe.getBlue, alpha)) g.drawOval(w.zentrum._1 - radius, w.zentrum._2 - radius, 2*radius, 2*radius) } else { // die Welle erstirbt ... wellen = wellen filterNot (_ == w) } } } def abstand(x: (Int,Int), y: (Int,Int)) = { sqrt((x._1 - y._1)*(x._1 - y._1) + (x._2 - y._2)*(x._2 - y._2)) } /** Vektoraddition modulo Weltallgrenzen.*/ def add(x: (Int,Int), y: (Double,Double)) : (Int, Int) = { var z1 = (x._1 + y._1) % Weltall.width; var z2 = (x._2 + y._2) % Weltall.height if (z1 < 0) z1 = Weltall.width + z1 if (z2 < 0) z2 = Weltall.height + z2 return (z1.round.toInt, z2.round.toInt) } def act { var i = 0; loop { react { case ('erzeuge, p: Stern) => sterne = p :: sterne case ('erzeuge, r: Raumschiff) => raumschiffe = r :: raumschiffe case ('erzeuge, w: Wellenfront) => wellen = w :: wellen } } } def main(args: Array[String]) { val fenster = new Fenster(width,height,Weltall.peer); val sirius = new Stern("Sirius", new Color(0,0,255)) val aldebaran = new Stern("Aldebaran", RED) val sonne = new Stern("Sonne", YELLOW) val orion = new Raumschiff("Orion", GREEN) Thread.sleep((1000*random).toInt) val enterprise = new Raumschiff("Enterprise", MAGENTA) } }