import uwcse.graphics.*;
import java.awt.Point;
import java.util.*;
import java.awt.Color;
/**
* representation and display of a caterpillar
*/
public class Caterpillar implements CaterpillarConstants
{
// The body of a caterpillar is made of Points stored
// in an ArrayList
private ArrayList body = new ArrayList();
// Store the graphical elements of the caterpillar body
// Useful to erase the body of the caterpillar on the screen
private ArrayList bodyUnits = new ArrayList();
// The window the caterpillar belongs to
private GWindow window;
// Direction of motion of the caterpillar (NORTH initially)
private int dir = NORTH;
// Length of a unit of the body of the caterpillar
// MUST be equal to the distance covered by the caterpillar
// at every step of the animation.
private final int bodyUnitLength=STEP;
// Width of a unit of the body of the caterpillar
private final int bodyUnitWidth=CATERPILLAR_WIDTH;
/**
* Construct a caterpillar
*/
public Caterpillar(GWindow window)
{
// Initialize the graphics window for this Caterpillar
this.window = window;
// Create the caterpillar (10 points)
// First point
Point p = new Point(5,WINDOW_HEIGHT/2);
body.add(p);
// Other points
for(int i=0; i<9; i++)
{
Point q = new Point(p);
q.x = p.x + bodyUnitLength;
body.add(q);
p=q;
}
// Show the caterpillar
draw();
}
/**
* Draw the caterpillar in the graphics window
*/
private void draw()
{
// Connect with Rectangles the points of the body
Point p=(Point)body.get(0);
for(int i=1; i
* If the new direction is illegal, select a
* legal direction of motion and move in that direction.
*/
public void move(int newDir)
{
// Is the move illegal?
boolean isMoveNotOK;
// newDir might not be legal
// Before trying a random direction, try first
// the current direction of motion (if not newDir)
boolean isFirstTry = true;
// move the caterpillar in direction newDir
do{
// new position of the head
Point head = new Point((Point)body.get(body.size()-1));
switch(newDir)
{
case NORTH:
head.y-=STEP;
break;
case SOUTH:
head.y+=STEP;
break;
case EAST:
head.x+=STEP;
break;
case WEST:
head.x-=STEP;
break;
}
// Is the new position in the window?
if (isPointInTheWindow(head))
{
isMoveNotOK=false;
// Update the position of the caterpillar
body.remove(0);
body.add(head);
}
else
{
isMoveNotOK=true;
// Select another direction
// Try the current direction first
if (newDir!=dir && isFirstTry)
{
newDir = dir;
isFirstTry = false;
}
else // random direction
newDir = (int)(Math.random()*4+1);
}
}while(isMoveNotOK);
// Update the current direction of motion
dir = newDir;
// Show the new location of the caterpillar
moveCaterpillarOnScreen();
}
/**
* Move the caterpillar on the screen
*/
private void moveCaterpillarOnScreen()
{
// Erase the body unit at the tail
window.remove((Shape)bodyUnits.get(0));
bodyUnits.remove(0);
// Add a new body unit at the head
Point q = (Point)body.get(body.size()-1);
Point p = (Point)body.get(body.size()-2);
addBodyUnit(p,q,bodyUnits.size());
// show it
window.doRepaint();
}
/**
* Add a body unit to the caterpillar. The body unit
* connects Point p and Point q.
* Insert this body unit at position index in bodyUnits.
* e.g. 0 to insert at the tail and bodyUnits.size() to insert
* at the head.
*/
private void addBodyUnit(Point p, Point q, int index)
{
// Connect p and q with a rectangle.
// To allow for a smooth look of the caterpillar, p and q
// are not on the edges of the Rectangle
// Upper left corner of the rectangle
int x = Math.min(q.x,p.x)-bodyUnitWidth/2;
int y = Math.min(q.y,p.y)-bodyUnitWidth/2;
// Width and height of the rectangle (vertical or horizontal rectangle?)
int width = ((q.y==p.y)?(bodyUnitLength+bodyUnitWidth):bodyUnitWidth);
int height = ((q.x==p.x)?(bodyUnitLength+bodyUnitWidth):bodyUnitWidth);
// Create the rectangle and place it in the window
Rectangle r = new Rectangle(x,y,width,height,Color.red,true);
window.add(r);
// keep track of that rectangle (we will erase it at some point)
bodyUnits.add(index,r);
}
/**
* Is Point p in the window?
*/
private boolean isPointInTheWindow(Point p)
{
return (p.x>=0 && p.x<=WINDOW_WIDTH &&
p.y>=0 && p.y<=WINDOW_HEIGHT );
}
}