Two examples are presented: in the first one, a ball draws a circle as result of being moved by two distinct Junior reactive programs; the second example shows the use of broadcast events and of dynamic creation of objects.
These two examples are also coded using fair threads; you can click here to see what the two examples coded in FairThreads look like.
Demo1 |
Two fair threads are moving the same ball; one thread
follows a sine path, and the other a cosine path. An applet is created
which adds a third fair thread, for painting traces of the ball. At
each phase, color of the ball changes, to visualize ball moves. One
gets a circle; this is basically because the two reactive behaviors share common instants.
threads is fair.
The Ball
class Ball
{
double x, y, angleX = 0, angleY = 0;
int radius = 8, steps = 100, scale = 5;
Color color;
public Ball(int x,int y,Color color){
this.x = x; this.y = y; this.color = color;
}
public Ball(int x,int y){ this(x,y,ColorBall.nextColor()); }
public void paint(Graphics g){
g.setColor(color);
g.fillOval((int)x-radius, (int)y-radius,radius*2,radius*2);
}
public void sine(){
angleY += (2*Math.PI/steps);
y += scale*Math.sin(angleY);
}
public void cosine(){
angleX += (2*Math.PI/steps);
x += scale*Math.sin(angleX+Math.PI/2);
}
}
class Sin implements Action { public void execute(Environment env){ Ball ball = (Ball)env.linkedObject(); ball.sine(); } }
class ReactiveApplet extends DoubleBufferedApplet implements Runnable { Thread thread; Machine machine = Jr.SafeMachine(); public void init(){ thread = new Thread(this); thread.start(); } public void run(){ while(true){ try{ Thread.sleep(1); }catch(Exception e){} machine.react(); paint(getGraphics()); } } }
public class SinCos extends ReactiveApplet { Ball ball = new Ball(startx,starty); public void paint(Graphics g) { super.paint(g); ball.paint(g); ball.color = ColorBall.nextColor(); } Program sine(Ball ball){ return Jr.Link(ball,Jr.Loop(Jr.Seq(Jr.Atom(new Sin()),Jr.Stop()))); } Program cosine(Ball ball){ return Jr.Link(ball,Jr.Loop(Jr.Seq(Jr.Atom(new Cos()),Jr.Stop()))); } Program circle(Ball ball){ return Jr.Par(sine(ball),cosine(ball)); } public void init(){ super.init(); machine.add(circle(ball)); } }
Adding a new behavior that move the ball following a cosine path, one gets a Lissajous figure (produced by two cosine and one sine threads):
public void init(){ super.init(); machine.add(cosine(ball)); }
Demo2 |
Balls are now dynamically created; they have two
associated behaviors which are waiting for an event to start moving
(following a sine or a cosine path). A button is used to create new
balls at random positions; the sine button broadcasts the
sine event to all behaviors; the cosine button broadcasts
the cosine event; the sine+cosine button broadcasts both
sine and cosine events.
Mouse click -> event
public class GenerateAdapter extends MouseAdapter
{
Machine machine;
Vector events;
public GenerateAdapter(Machine machine,Vector events){
this.machine = machine; this.events = events;
}
public void mouseClicked(MouseEvent evt){
Enumeration enum = events.elements();
while(enum.hasMoreElements()){
String event = (String)enum.nextElement();
machine.generate(Jr.StringIdentifier(event));
}
}
}
The applet
public class DynSinCos extends ReactiveApplet
{
int rand(int n){ return (int)(Math.random()*1000)%n; }
Vector items = new Vector();
public void paint(Graphics g){
synchronized (items) {
Enumeration enum = items.elements();
while(enum.hasMoreElements()) ((Ball)enum.nextElement()).paint(g);
}
}
void createBall(){
Ball ball =
new Ball(rand(size().width),rand(size().height));
ball.radius = 5;
items.addElement(ball);
Program sin =
Jr.Seq(Jr.Await("sin"),
Jr.Loop(Jr.Seq(Jr.Atom(new Sin()),Jr.Stop())));
Program cos =
Jr.Seq(Jr.Await("cos"),
Jr.Loop(Jr.Seq(Jr.Atom(new Cos()),Jr.Stop())));
machine.add(Jr.Link(ball,Jr.Par(sin,cos)));
}
public void init(){
super.init();
Button sin = new Button("sin");
Button cos = new Button("cos");
Button sincos = new Button("sin+cos");
Button start = new Button("new ball");
Vector params = new Vector();
params.addElement("sin");
sin.addMouseListener(new GenerateAdapter(machine,params));
params = new Vector();
params.addElement("sin");
params.addElement("cos");
sincos.addMouseListener(new GenerateAdapter(machine,params));
params = new Vector();
params.addElement("cos");
cos.addMouseListener(new GenerateAdapter(machine,params));
start.addMouseListener(new CreateBall(this));
Panel p = new Panel();
p.setBackground(Color.lightGray);
setLayout(new BorderLayout());
p.setLayout(new GridLayout(1,5,5,20));
add("South",p);
p.add(sin);
p.add(cos);
p.add(sincos);
p.add(start);
createBall();
}
}
Sources |
Click here to get the source code of the demos.