CSCI A201/A597

Lab Notes 12

Spring 2000


Help with homework 9.

Last lecture on Tuesday we created random circles and drew them on the screen.

Let's implement a program that creates 10 random circles and places them on the screen.

Then waits for the user to press the mouse somewhere in the window.

If the mouse was pressed inside one of the circles then the first circle that contains the point where the mouse was pressed will be following the mouse in its movement while the mouse is being pressed.

As soon as the mouse is released the circle no longer follows the mouse.

How are we going to implement such a thing?

First of all, have we ever seen anything like it?

The answer is: yes, the rubber band was doing just that.

The lines were (both) following the mouse pointer while the mouse button was being kept pressed.

Was there anything special with that example?

Perhaps the way the lines were drawn and erased was more special than anything else.

The window was in a special painting mode, called invertMode().

In that mode if you draw one thing once it appears on the screen and if you draw it again in the same place it disappears and the background is restored. It's a property of the window so if it worked with lines it should work with circles too.

Here now is the program.

import element.*;
import java.util.*; 

public class MovingCircles {
    public static void main(String[] args) {
	Random gen = new Random(); 
	Circle[] circles = new Circle[10];
	DrawingWindow d = new DrawingWindow(); 
	d.invertMode(); 
	for (int i = 0; i < 10; i++) {
	    int x = Math.abs(gen.nextInt()) % 200; 
	    int y = Math.abs(gen.nextInt()) % 200; 
	    int r = Math.abs(gen.nextInt()) % 15 + 5; 
	    circles[i] = new Circle(x, y, r); 
	    d.draw(circles[i]); 
	} 
	while (true) {
	    Pt p = d.awaitMousePress(); 
	    boolean circleHit = false; 
	    int index = -1; 
	    for (int i = 0; i < circles.length && !circleHit; i++) {
		if (circles[i].contains(p)) {
		    circleHit = true;
		    index = i; 
		}
	    } 
	    while (d.mousePressed()) {
		Pt m = d.getMouse(); 
		if (circleHit) {
		    d.draw(circles[index]);
		    m = new Pt(m.x() - circles[index].radius(), 
			       m.y() - circles[index].radius());
		    circles[index].moveTo(m); 
		    d.draw(circles[index]);
		} 
	    } 
	} 
    } 
} 
Here's the Tetris-like game:
import element.*;         // for graphics and circles 
import java.util.Random;  // for random numbers 

class T {       
    public static void main(String[] args) {
	Random r = new Random();                                         // our generator 

	DrawingWindow d = new DrawingWindow(); d.invertMode(); 

	Rect le = new Rect(0, 0, 10, 10),       // wind blowing towards left (east)
	    ri = new Rect(190, 0, 10, 10);      // wind blowing towards right (west)
	d.draw(le); d.draw(ri);  // placing the mouse in these rectangles amounts to that 

	Line left, bottom, right;                                    // creating the bin
	left = new Line(new Pt(20, 40), new Pt(20, 180));            // left margin 
	right = new Line(new Pt(180, 40), new Pt(180, 180));         // right margin 
	bottom = new Line(new Pt(20, 180), new Pt(180, 180));        // bottom of bin 

        d.draw(left); d.draw(right); d.draw(bottom);                 // draw it 

        boolean gameGoesOn = true;     // originally we want to start the game 

	Circle[] c = new Circle[200];  // so many circles 
	int i = 0;                     // currently working on circle i 
        double score = 0;              // your score is the percent of area covered 

	while (gameGoesOn) {

	    int radius = Lib.rand(r, 10, 20);     // give me a random size 

	    score += 3.14 * radius * radius;      // score increased by the area of the circle 

	    c[i] = new Circle(Lib.rand(r, 20 + radius, 180 - radius), 40, radius); // the circle 

	    d.draw(c[i]);                         // draw it, where it starts falling 

	    boolean circleMoving = true;          // before anything it moves 

	    for (int j = 0; j < i; j++) 
		if (Lib.overlap(c[i], c[j])) 
		    circleMoving = false;         // movement stops if it overlaps any other circle 

	    while (circleMoving) { // here's how the circle moves if it should be moving 
		Lib.wait(0.5);                    // wait half a second 
		d.draw(c[i]);                     // then draw it (again) thus erasing it 
		c[i].move(0, 3);                  // then move it 3 pixels down 
		if (le.contains(d.getMouse())) {  // it should also move three pixels to the left
		    c[i].move(-3, 0);             // if the wind is blowing in that direction 
		} else if (ri.contains(d.getMouse())) { // or three pixels to the right 
		    c[i].move(3, 0);              // if the wind is blowing in that direction 
		} 
		d.draw(c[i]);                     // now draw it (for the first time) in this
                   		                  // new position 
		// we now asses if the movement should continue 
		for (int j = 0; j < i; j++) {
		    if (Lib.overlap(c[i], c[j])) { 
			// if circles overlap the movement of this circle should stop 
			circleMoving = false;        
		    }
		}
		if (c[i].center().y() + c[i].radius() > 180 
		    || (c[i].center().x() - c[i].radius() < 20)
		    || (c[i].center().x() + c[i].radius() > 180)) {
		    // the falling of a circle also stops if it hits the border 
		    circleMoving = false;
		} 
	    } // end of while if we reach this place the movement of circlec[i] has ended
	    if (i == 200 - 1 || c[i].center().y() < 80) {
		// the game stops when the user has placed all 200 circles
		//(s)he's allowed to place or the stack of circles too tall 
		gameGoesOn = false; 
	    } 
	    // c[i] becomes permanent and gets drawn filled 	    
	    d.paintMode();
	    d.fill(c[i]); 
	    d.invertMode(); 
	    i += 1; // getting ready to work with a new circle, with an index one higher 
	}
	System.out.println("Game over."); 
	System.out.println("Final score: " + (score / 22400)); 
	// divide the covered area by the total area for the score 
    } 
} 

class Lib {
    public static int rand(Random gen, int left, int right) {
	return Math.abs(gen.nextInt()) % (right - left + 1) + left; 
    } 
    public static boolean overlap(Circle a, Circle b) {
	return Lib.distance(a.center(), b.center()) < a.radius() + b.radius(); 
    } 
    public static double distance(Pt a, Pt b) {
	int h, v;
	h = Math.abs(a.x() - b.x()); 
	v = Math.abs(a.y() - b.y()); 
	return Math.sqrt(h * h + v * v);
    } 
    public static void wait(double s) {
	long now, then;
	now = System.currentTimeMillis(); 
	then = now + (long)(s * 1000); 
	while (System.currentTimeMillis() < then) {

	}
    } 
} 

Last updated Apr 6, 2000 by Adrian German.