CPSC 225, Spring 2016
Lab 6: Some Kinetic Art
For this lab, you will work on a GUI program that displays an abstract, and perhaps interesting, animated image. In the first part of the lab, you will work with lists in the form of the ArrayList class. In the second part of the lab, you will work with recursion,
The lab uses the files SpikeyMain.java and Spikey.java, which you will find in the folder /classes/cs431/Lab6-files. You should create a project named Lab6 and copy the two Java files into your project.
This lab should be due before class on Friday, October 14. However, because of Fall break, I will consider postponing it until Saturday or Monday. We can discuss the due date in class.
The Part About ArrayList
The program SpikeyMain opens a window that contains a simple animated object. The object is represented by an object of type Spikey that is drawn as a colored disk with lines radiating out from the edge of the disk. The animation shows the lines growing and shrinking, with some randomness in the speed. Here is a picture of a Spikey from the program:
Currently, the program only allows for one Spikey. In the first part of the lab, you will extend the program to use an ArrayList<Spikey> to hold a list of Spikeys. The user will be able to add Spikeys to the list by clicking on the window, and will be able to remove a Spikey by clicking on the colored disk in the center. Furthermore, the Spikeys will have some random motion. Here is a part of a window showing a list of Spikeys:
All of the work for this part of the lab will be done in the file SpikeyMain.java. Open that file for editing. But you will also want to consult the file Spikey.java to learn about what you can do with a Spikey.
The program has an instance variable of type Spikey. You should replace that variable with a variable of type ArrayList<Spikey>. Recall that an ArrayList named list has methods including
- list.size() — returns the number of items in the list.
- list.get(i) — returns the ith item in the list (without removing it).
- list.add(item) — adds item to the end of the list.
- list.remove(item) — removes item from the list, if it is in the list.
You should modify the program to work with a list of Spikeys and allow the user to add and delete Spikeys. The SpikeyMain constructor can still, optionally, add the first Spikey to the list. The paintComponent() method has to be modified to draw all the Spikeys, and the timeStep() method should update all of the Spikeys.
The most interesting part is the mouse interaction, which you should implement in the doMouseDown method at the bottom of the class. If the user clicks on the center disk of a Spikey, that Spikey should be removed from the list. If the user's click is not on the center of any Spikey, then a new Spikey should be added at the point where the user clicked. Don't forget to repaint!
Note: To test whether the user's click is on the center disk of a given Spikey, you need to test whether the distance from the center point of the Spikey to the point where the user clicked is less than the Spikey's ballRadius. If the user's point is (x,y), the center of the Spikey is (cx,cy), and the radius is r, then the test is
if ( Math.sqrt( (cx-x)*(cx-x) + (cy-y)*(cy-y) ) < r ) ...
As a final enhancement, which you might want to return to later, you should make the Spikeys move around during the animation. I found that a simple "Brownian motion" looks interesting. You can implement Brownian motion in timeStep by adding a small random amount to the centerX and centerY values of each Spikey. You want the values that are added to be chosen randomly in the range -N to N for some N. (If you can think of a more interesting kind of motion, you are welcome to use that instead.)
The Part About Recursion
Now it's time to make the Spikeys recursive. To do that, you need to work on Spikey.java. In the recursive version, a Spikey of level N, for N greater than zero, has a smaller Spikey of level (N-1) on the end of each spike. A Spikey of level zero is just the regular version, with nothing on the ends of its spikes. You should add the level as a parameter to the Spikey constructor.
A recursive Spikey is a kind of tree structure. The small Spikeys at the ends of the spikes are children of the big Spikey. You should declare an array or an ArrayList as an instance variable and use it to hold (pointers to) the child Spikeys. The children should be created in the Spikey constructor. The question of how much smaller the children should be than the original is up to you. Try to make it look good!
To animate the children, the timeStep() method in the Spikey class must call the timeStep() function in each child (if there are any children).
To draw the recursive Spikey, the draw() method in the Spikey class must also draw the children, if any. But there is a technicality: Somehow, as the spikes of the big Spikey grow and shrink, the child Spikeys have to be moved so that their centers are at the ends of the big Spikey's spikes. By far, the easiest place to do that is in the draw() method, before you draw the children. Note that the draw() method already computes two numbers x2 and y2 which give the position of the end of a spike. You can use x2 and y2 to set the centerX and centerY of the child.
With that much done, you can modify SpikeyMain.java to make recursive Spikeys. Don't try to give a recursive Spikey too many spikes, and don't try to make the level too big. (My program uses 8 spikes and level 3.)
The final requirement is to make the setter functions setBallColor() and setSpikeColor() in Spikey.java apply recursively to the children of a Spikey. By default, Spikeys have random colors. The work on the two methods will make it possible to have uniformly colored recursive Spikeys. (In the pictures of recursive Spikeys above, the one on the left has the default multi-color appearance. The one on the right has a uniform ball color and a uniform spike color.) Then in SpikeyMain.java, you should modify doMouseDown() so that if the user is holding down the shift key when the user clicks an empty spot, then the Spikey that is created is set to have uniform colors by calling its setBallColor() and setSpikeColor() methods.
More Enhancements?
You are encouraged to do some extra work on the program (possibly for a little extra credit). For example, you could try varying the number of spikes or the spike width on different levels of the recursion.
Or add a copy constructor to Spikey.java, with a parameter of type Spikey that constructs an exact copy of its parameter. Then during the animation you might occasionally make a copy of a Spikey. Initially, the two Spikeys will be identical but they will drift apart because of the random motion. Spikeys could also disappear at random.
Or you might give the user the ability to control the size or recursion level of a Spikey that is added. For example, holding the Alt (Option) key down while clicking might make a plain, level-zero Spikey, and holding down the Control key might make a smaller or bigger Spikey.
Or maybe you can think of some ways to use key presses to control the program (such as by turning the Brownian motion on and off). You would likely need some help to set up a key listener.