1  // CPS616 Assignment 2
  2  // Mehmet SEN
  3  // Using threads to construct a applet, in which dynamically sizing
  4  // bubbles are moving.
  5  // HOW TO USE THREADS?
  6  // 1. Add the words "implements Runnable" to the applet class
  7  // 2. Define an instance variable to hold the applet's thread
  8  // 3. Modify start() method to spawn a thread and start it running.
  9  // 4. Create a run() method that contains the actual code that starts 
 10  //    your applet running
 11  // 
 12  // In the following program Bubble class constructs a thread and 
 13  // BubblesApplet class creates an array of independent threads using the 
 14  // Bubble class.  You can watch all four steps by looking at the Bubble 
 15  // class to create an independent thread
 16  
 17  import java.awt.*;
 18  import java.lang.Math;
 19  import java.util.Random;
 20  
 21  public class BubblesApplet extends java.applet.Applet {
 22  
 23    public int W = 400;
 24    public int H = 300;
 25    public int N = 15;
 26    public final int minSize = 10;
 27    public final int maxSize = 50;
 28    public final int minNaptime = 1;
 29    public final int maxNaptime = 500;
 30    public final Color colors[] = {
 31      Color.red,
 32      Color.pink,
 33      Color.orange,
 34      Color.yellow,
 35      Color.green,
 36      Color.magenta,
 37      Color.blue,
 38      Color.cyan,
 39      Color.white,
 40      Color.gray,
 41      Color.lightGray,
 42      Color.darkGray
 43    };
 44    public final Color bg = Color.black;
 45    boolean threadSuspended = false;
 46    Image im;
 47    Graphics offscreen;
 48    Random rand;
 49    Bubble bubbles[] = new Bubble[N];
 50  
 51    public void init() {
 52      Rectangle r=bounds();
 53      W = r.width;
 54      H = r.height;
 55      resize(W, H);
 56      rand = new Random((long)System.currentTimeMillis());
 57      try {
 58        im = createImage(W, H);
 59        offscreen = im.getGraphics();
 60      } catch (Exception e) {
 61        offscreen = null;
 62      }
 63    }
 64  
 65  /*
 66    Create each bubble with some random parameters and start its thread
 67  */
 68  
 69    public void start() {
 70      for (int i=0; i<N; i++) {
 71        if (bubbles[i] == null) {
 72          bubbles[i] = new Bubble(this,
 73          (int)((double)W*rand.nextDouble()),
 74          (int)((double)H*rand.nextDouble()),
 75          minSize + (int)((double)(maxSize-minSize)*rand.nextDouble()),
 76          minNaptime + (int)((double)(maxNaptime-minNaptime)*rand.nextDouble()),
 77          colors[(int)((double)colors.length*rand.nextDouble())],
 78          bg, bounds());
 79          bubbles[i].start();
 80        }
 81      }
 82      repaint();
 83    }
 84  
 85  /* when applet is stopped, stop individual threads */
 86    public void stop() {
 87      for (int i=0; i<N; i++) {
 88        bubbles[i].stop();
 89      }
 90    }
 91  
 92  /* override the update method to reduce flashing */
 93    public void update(Graphics g) {
 94      paint(g);
 95    }
 96  
 97  /* we are using double buffering to reduce flashing */
 98    public void paint(Graphics g) {
 99      if (offscreen != null) {
100        paintApplet(offscreen);
101        g.drawImage(im, 0, 0, this);
102      } else {
103        paintApplet(g);
104      }
105    }
106  
107  /* call each bubble's paint method */
108    public void paintApplet(Graphics g) {
109      boolean changed = false;
110      g.setColor(bg);
111      g.fillRect(0, 0, W, H);
112      for (int i=0; i<N; i++) {
113        bubbles[i].paint(g);
114      }
115    }
116    
117  } // end BubblesApplet class
118  
119  /**
120    This class implements a Bubble.  Each bubble will call its applet's paint method
121    asynchronously when it is time for growth or decay.
122  */
123  
124  class Bubble implements Runnable {
125  
126    static int threadNum = 1;
127    private Color color = null;
128    private Color bg = Color.black;
129    private int naptime = 500;
130    private int size = 50;
131    private int growthFactor = 1;
132    private int ox = 0;   /* location within applet's frame of reference */
133    private int oy = 0;   /* center of the bubble */
134    private int dx=2;
135    private int dy=2;
136    private Rectangle rect;
137    private Graphics graphics;
138    private int current;
139    private int previous;
140    private boolean growing = false;
141  
142    public Thread thread = null;
143    public boolean changed = true;
144  
145    BubblesApplet applet;
146  
147    public Bubble(BubblesApplet applet, int x, int y, int s, int n, Color c, Color bg, Rectangle r) {
148      this.applet = applet;
149      ox = x;
150      oy = y;
151      size = s;
152      naptime = n;
153      color = c;
154      rect = r;
155      dx = (Math.random()>.5)?-2:2;
156      dy = (Math.random()>.5)?-2:2;
157    
158      if (color == null) {
159        color = Color.black;
160      }
161      current = previous = s;
162    }
163  
164  /* main thread run method */
165    public void run() {
166      thread.setPriority(Thread.MIN_PRIORITY+1);
167      while (thread != null) {
168        changed = true;
169        previous = current;
170        if (growing) {
171          current += growthFactor;
172        } else {
173          current -= growthFactor;
174        }
175        if (current == size || current == 0) {
176          growing = !growing;
177        }
178        try { thread.sleep(naptime); } 
179        catch (InterruptedException e) {};
180        applet.repaint();
181      }
182      thread = null;
183    }
184  
185  /* Here , thread is started */
186    public void start() {
187      if (thread == null) {
188        thread = new Thread(this, Integer.toString(threadNum++));
189        thread.start();
190      }
191    }
192  
193    public void stop() {
194      thread = null;
195    }
196  
197  /* Erase last position and paint the new one */
198    public void paint(Graphics g) {
199      int prevHalf = (int)(previous/2);
200      int curHalf = (int)(current/2);
201    
202      g.setColor(bg);
203      g.fillOval(ox-prevHalf, oy-prevHalf, previous, previous);
204      
205      checkboundary();
206      ox += dx;
207      oy += dy;
208      g.setColor(color);
209      g.fillOval(ox-curHalf, oy-curHalf, current, current);
210    }
211  
212    public void checkboundary() {
213      int curHalf = (int)(current/2);
214      int nx = ox+dx; /* caculate new location */
215      int ny = oy+dy;
216    
217      /* check if new location out of boundary */
218      if ( (nx < curHalf) || (nx+current >= rect.width+curHalf) ) dx = -dx;
219      if ( (ny < curHalf) || (ny+current >= rect.height+curHalf) ) dy = -dy;
220      // System.out.println("nx:"+nx+ " ny:"+ny + "cur:"+current+ " dy:"+dy +"rect.y "+rect.y+ " rect.height "+ rect.height+"rect.x "+rect.x+ " rect.width "+ rect.width); 
221    }
222    
223  } // end Bubble class
224  
225  
226  
227  
228