As threads, both behave the same. However, a thread that implements runnable can also extend another class.
To give other waiting threads time to execute and prevent deadlock. Thread.yield()
also works for this purpose.
import java.awt.Graphics;
import java.applet.Applet;
import java.awt.Rectangle;
import java.awt.Color;
import java.awt.Event;
import java.awt.Dimension;
public class TwoBall extends Applet implements Runnable {
Ball b1, b2;
boolean bouncing;
Thread t;
public void init () {
b1 = new Ball(10, 32, size(), Color.red);
b1.start();
b2 = new Ball(155, 75, size(), Color.yellow);
b2.start();
bouncing = true;
t = new Thread(this);
t.start();
}
public void paint (Graphics g) {
g.setColor(b1.getColor());
g.fillOval(b1.getX(), b1.getY(), b1.getWidth(), b1.getHeight());
g.setColor(b2.getColor());
g.fillOval(b2.getX(), b2.getY(), b2.getWidth(), b2.getHeight());
}
public boolean mouseUp(Event e, int x, int y) {
if (bouncing) {
b1.stop();
b2.stop();
t.stop();
bouncing = false;
}
else {
b1.start();
b2.start();
t.start();
bouncing = true;
}
return true;
}
public void run() {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (true) { // infinite loop
repaint();
try {
Thread.currentThread().sleep(10);
}
catch (Exception e) {
}
}
}
}
import java.awt.Rectangle;
import java.awt.Color;
import java.awt.Dimension;
class Ball extends Thread {
private Rectangle r;
private int x_increment = 1;
private int y_increment = 1;
private Dimension bounds;
Color theColor;
public Ball(int x, int y, Dimension d) {
r = new Rectangle(x, y, 20, 20);
bounds = d;
theColor = Color.black;
}
public Ball(int x, int y, Dimension d, Color c) {
r = new Rectangle(x, y, 20, 20);
bounds = d;
theColor = c;
}
public int getX() {
return r.x;
}
public int getY() {
return r.y;
}
public int getHeight() {
return r.height;
}
public int getWidth() {
return r.width;
}
public Color getColor() {
return theColor;
}
public void setColor(Color c) {
theColor = c;
}
public void run() {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (true) { // infinite loop
r.x += x_increment;
r.y += y_increment;
if (r.x + r.width >= bounds.width || r.x < 0) x_increment *= -1;
if (r.y + r.height >= bounds.height || r.y < 0) y_increment *= -1;
try {
Thread.currentThread().sleep(10);
}
catch (Exception e) {
}
}
}
}
The trick to this problem is to use doubles to represent the position and and increment of the balls. This requires substantial changes to the internal structure of the Ball class, but the external interface remains unchanged except for the appearance of a couple of new constructors.
import java.awt.Rectangle;
import java.awt.Color;
import java.awt.Dimension;
public class Ball extends Thread {
private double x, y, width, height;
private double x_increment;
private double y_increment;
private Dimension bounds;
Color theColor;
public Ball(int x, int y, Dimension d) {
this(x, y, d, Color.black, 20.0, 20.0, 1.0, 1.0);
}
public Ball(int x, int y, Dimension d, Color c) {
this(x, y, d, c, 20.0, 20.0, 1.0, 1.0);
}
public Ball(int x, int y, Dimension d, Color c, double x_increment, double y_increment) {
this(x, y, d, c, 20.0, 20.0, x_increment, y_increment);
}
public Ball(int x, int y, Dimension d, double x_increment, double y_increment) {
this(x, y, d, Color.black, 20.0, 20.0, x_increment, y_increment);
}
public Ball(double x, double y, Dimension d, Color c, double width, double height, double x_increment, double y_increment) {
this.x = x;
this.y = y;
this.x_increment = x_increment;
this.y_increment = y_increment;
this.width = width;
this.height = height;
bounds = d;
theColor = c;
}
public int getX() {
return (int) x;
}
public int getY() {
return (int) y;
}
public int getHeight() {
return (int) height;
}
public int getWidth() {
return (int) width;
}
public Color getColor() {
return theColor;
}
public void setColor(Color c) {
theColor = c;
}
public void run() {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (true) { // infinite loop
x += x_increment;
y += y_increment;
if (x + width >= bounds.width || x < 0) x_increment *= -1;
if (y + height >= bounds.height || y < 0) y_increment *= -1;
try {
Thread.currentThread().sleep(10);
}
catch (Exception e) {
}
}
}
}
import java.awt.Graphics;
import java.applet.Applet;
import java.awt.Rectangle;
import java.awt.Color;
import java.awt.Event;
import java.awt.Dimension;
import java.util.StringTokenizer;
public class MultiBall extends Applet implements Runnable {
Ball[] balls;
boolean bouncing;
Thread t;
public void init () {
int numballs;
try {
numballs = Integer.parseInt(getParameter("numballs"));
}
catch (Exception e) {
numballs = 0;
}
balls = new Ball[numballs];
// Read Ball parameters in format
//
for (int i = 0; i < numballs; i++) {
String s = getParameter("Ball" + i);
// missing parameter
if (s == null) continue;
StringTokenizer st=new StringTokenizer(s);
if (st.countTokens() < 5) continue;
double x = Double.valueOf(st.nextToken()).doubleValue();
double y = Double.valueOf(st.nextToken()).doubleValue();
double x_increment = Double.valueOf(st.nextToken()).doubleValue();
double y_increment = Double.valueOf(st.nextToken()).doubleValue();
String color = st.nextToken();
Color c;
if (color.equalsIgnoreCase("red")) {
c = Color.red;
}
else if (color.equalsIgnoreCase("yellow")) {
c = Color.yellow;
}
else if (color.equalsIgnoreCase("blue")) {
c = Color.blue;
}
else if (color.equalsIgnoreCase("white")) {
c = Color.white;
}
else if (color.equalsIgnoreCase("green")) {
c = Color.green;
}
else {
c = Color.black;
}
balls[i] = new Ball(x, y, size(), c, 20.0, 20.0, x_increment, y_increment);
balls[i].start();
}
bouncing = true;
t = new Thread(this);
t.start();
}
public void paint (Graphics g) {
for (int i = 0; i < balls.length; i++) {
g.setColor(balls[i].getColor());
g.fillOval(balls[i].getX(), balls[i].getY(), balls[i].getWidth(), balls[i].getHeight());
}
}
public boolean mouseUp(Event e, int x, int y) {
if (bouncing) {
for (int i = 0; i < balls.length; i++) {
balls[i].stop();
}
t.stop();
bouncing = false;
}
else {
for (int i = 0; i < balls.length; i++) {
balls[i].start();
}
t.start();
bouncing = true;
}
return true;
}
public void run() {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (true) { // infinite loop
repaint();
try {
Thread.currentThread().sleep(10);
}
catch (Exception e) {
}
}
}
}