# teaching machines

## CS 145 Lecture 24 – Animation

November 5, 2016 by . Filed under cs145, fall 2016, lectures.

Dear students,

Write a method times with the following behavior:
• times('!', 3) yields "!!!"
• times('#', 6) yields "######"
• times('-', 13) yields "-------------"

We’ll use this method to generate a random spelunking workout.

After that, we’ll generate a few more images. This time we won’t use loops to march through every pixel. Instead we’ll loop through points on a line or timesteps in an animation! Let’s solve these problems:

• draw a line between two points
• bounce a ball
• rotate and scale a square

See you next class!

Sincerely,

P.S. It’s Haiku Friday!

They’re little windows
Shining past light, like Grandma’s
I wish pixels smelled

P.P.S. Here’s the code we wrote together…

#### RandomSpelunking.java

package lecture1104;

import java.util.Random;

public class RandomSpelunking {
public static void main(String[] args) {
Random generator = new Random();

int nLevels = getNumberOfLevels();
for (int i = 0; i < nLevels; ++i) {
System.out.println(times('-', generator.nextInt(7) + 4));
}

}

public static int getNumberOfLevels() {
System.out.println("Hey, we're callin' this method!");
return new Random().nextInt(20);
}

public static String times(char c, int n) {
String s = "";
for (int i = 0; i < n; ++i) {
s += c;
}
return s;
}
}


#### GifSequenceWriter.java

package lecture1104;

//  GifSequenceWriter.java

//
//  Created by Elliot Kroo on 2009-04-25.
//
// http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative
// Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.

import javax.imageio.*;
import javax.imageio.stream.*;
import java.awt.image.*;
import java.io.*;
import java.util.Iterator;

public class GifSequenceWriter {
protected ImageWriter gifWriter;
protected ImageWriteParam imageWriteParam;
protected ImageOutputStream outputStream;

/**
* Creates a new GifSequenceWriter
*
* @param outputStream
*          the ImageOutputStream to be written to
* @param imageType
*          one of the imageTypes specified in BufferedImage
* @param timeBetweenFramesMS
*          the time between frames in miliseconds
* @param loopContinuously
*          wether the gif should loop repeatedly
* @throws IIOException
*           if no gif ImageWriters are found
*
* @author Elliot Kroo (elliot[at]kroo[dot]net)
*/
public GifSequenceWriter(File outFile,
int timeBetweenFramesMS,
boolean loopContinuously) {
try {
// my method to create a writer
gifWriter = getWriter();
imageWriteParam = gifWriter.getDefaultWriteParam();
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);

graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("delayTime", Integer.toString(timeBetweenFramesMS / 10));
graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");

child.setAttribute("applicationID", "NETSCAPE");
child.setAttribute("authenticationCode", "2.0");

int loop = loopContinuously ? 0 : 1;

child.setUserObject(new byte[] { 0x1, (byte) (loop & 0xFF), (byte) ((loop >> 8) & 0xFF)
});
appEntensionsNode.appendChild(child);

outputStream = new FileImageOutputStream(outFile);
gifWriter.setOutput(outputStream);
gifWriter.prepareWriteSequence(null);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public void appendFrame(BufferedImage img) {
try {
} catch (IOException e) {
throw new RuntimeException(e);
}
}

/**
* Close this GifSequenceWriter object. This does not close the underlying
* stream, just finishes off the GIF.
*/
public void close() {
try {
gifWriter.endWriteSequence();
outputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

/**
* Returns the first available GIF ImageWriter using
* ImageIO.getImageWritersBySuffix("gif").
*
* @return a GIF ImageWriter object
* @throws IIOException
*           if no GIF image writers are returned
*/
private static ImageWriter getWriter() throws IIOException {
try {
Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("gif");
if (!iter.hasNext()) {
throw new IIOException("No GIF Image Writers Exist");
} else {
return iter.next();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}

/**
* Returns an existing child node, or creates and returns a new child node (if
* the requested node does not exist).
*
* @param rootNode
*          the <tt>IIOMetadataNode</tt> to search for the child node.
* @param nodeName
*          the name of the child node.
*
* @return the child node, if found or a new node created with the given name.
*/
String nodeName) {
int nNodes = rootNode.getLength();
for (int i = 0; i < nNodes; i++) {
if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) == 0) {
}
}
rootNode.appendChild(node);
return node;
}
}


#### Animation.java

package lecture1104;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;

public class Animation {
public static void main(String[] args) {
File outputFile = new File("/Users/johnch/Desktop/ball.gif");
GifSequenceWriter gif = new GifSequenceWriter(outputFile, 100, false);

BufferedImage image = new BufferedImage(512, 512, BufferedImage.TYPE_INT_RGB);

Graphics g = image.getGraphics();
double x = 0;
double y = 0;
double delta = 0.1;
double velocityY = 31;
double velocityX = 12;
double acceleration = 2 * 9.81;

for (double t = 0.0; t < 30; t += delta) {
g.setColor(Color.BLUE);
g.fillRect(0, 0, image.getWidth(), image.getHeight());

g.setColor(Color.YELLOW);
g.fillOval((int) x, (int) y, 100, 100);

if (y > 410) {
velocityY *= -0.9;
}

x += velocityX * delta;
y += velocityY * delta;

velocityY += acceleration;

gif.appendFrame(image);
}

gif.close();
}
}