import javax.swing.*; import java.awt.*; import java.awt.font.*; import java.awt.geom.*; import java.util.Observer; /** * Class that represents a Logo-style turtle. The turtle * starts off facing north. * A turtle can have a name, has a starting x and y position, * has a heading, has a width, has a height, has a visible * flag, has a body color, can have a shell color, and has a pen. * The turtle will not go beyond the model display or picture * boundaries. * * You can display this turtle in either a picture or in * a class that implements ModelDisplay. * * Copyright Georgia Institute of Technology 2004 * @author Barb Ericson ericson@cc.gatech.edu */ public class SimpleTurtle { ///////////////// fields //////////////////////// /** count of the number of turtles created */ private static int numTurtles = 0; /** array of colors to use for the turtles */ private static Color[] colorArray = { Color.green, Color.cyan, new Color(204,0,204), Color.gray}; /** who to notify about changes to this turtle */ private ModelDisplay modelDisplay = null; /** picture to draw this turtle on */ private Picture picture = null; /** width of turtle in pixels */ private int width = 15; /** height of turtle in pixels */ private int height = 18; /** current location in x (center) */ private int xPos = 0; /** current location in y (center) */ private int yPos = 0; /** heading angle */ private int heading = 0; // default is facing north /** pen to use for this turtle */ private Pen pen = new Pen(); /** color to draw the body in */ private Color bodyColor = null; /** color to draw the shell in */ private Color shellColor = null; /** color of information string */ private Color infoColor = Color.black; /** flag to say if this turtle is visible */ private boolean visible = true; /** flag to say if should show turtle info */ private boolean showInfo = false; /** the name of this turtle */ private String name = "No name"; ////////////////// constructors /////////////////// /** * Constructor that takes the x and y position for the * turtle * @param x the x pos * @param y the y pos */ public SimpleTurtle(int x, int y) { xPos = x; yPos = y; bodyColor = colorArray[numTurtles % colorArray.length]; setPenColor(bodyColor); numTurtles++; } /** * Constructor that takes the x and y position and the * model displayer * @param x the x pos * @param y the y pos * @param display the model display */ public SimpleTurtle(int x, int y, ModelDisplay display) { this(x,y); // invoke constructor that takes x and y modelDisplay = display; display.addModel(this); } /** * Constructor that takes a model display and adds * a turtle in the middle of it * @param display the model display */ public SimpleTurtle(ModelDisplay display) { // invoke constructor that takes x and y this((int) (display.getWidth() / 2), (int) (display.getHeight() / 2)); modelDisplay = display; display.addModel(this); } /** * Constructor that takes the x and y position and the * picture to draw on * @param x the x pos * @param y the y pos * @param picture the picture to draw on */ public SimpleTurtle(int x, int y, Picture picture) { this(x,y); // invoke constructor that takes x and y this.picture = picture; this.visible = false; // default is not to see the turtle } /** * Constructor that takes the * picture to draw on and will appear in the middle * @param picture the picture to draw on */ public SimpleTurtle(Picture picture) { // invoke constructor that takes x and y this((int) (picture.getWidth() / 2), (int) (picture.getHeight() / 2)); this.picture = picture; this.visible = false; // default is not to see the turtle } //////////////////// methods ///////////////////////// /** * Method to get value of show info * @return true if should show info, else false */ public boolean getShowInfo() { return showInfo; } /** * Method to show the turtle information string * @param value the value to set showInfo to */ public void setShowInfo(boolean value) { showInfo = value; } /** * Method to get the shell color * @return the shell color */ public Color getShellColor() { Color color = null; if (shellColor == null && bodyColor != null) color = bodyColor.darker(); else color = shellColor; return color; } /** * Method to set the shell color * @param color the color to use */ public void setShellColor(Color color) { shellColor = color; } /** * Method to get the body color * @return the body color */ public Color getBodyColor() { return bodyColor; } /** * Method to set the body color * @param color the color to use */ public void setBodyColor(Color color) { bodyColor = color;} /** * Method to set the color of the turtle. * This will set the body color * @param color the color to use */ public void setColor(Color color) { setBodyColor(color); } /** * Method to get the information color * @return the color of the information string */ public Color getInfoColor() { return infoColor; } /** * Method to set the information color * @param color the new color to use */ public void setInfoColor(Color color) { this.infoColor = color; } /** * Method to get the current x position * @return the x position (in pixels) */ public int getXPos() { return xPos; } /** * Method to get the current y position * @return the y position (in pixels) */ public int getYPos() { return yPos; } /** * Method to check if the pen is down * @return true if down else false */ public boolean isPenDown() { return pen.isPenDown(); } /** * Method to set the pen down boolean variable * @param value the value to set it to */ public void setPenDown(boolean value) { pen.setPenDown(value); } /** * Method to get the pen color * @return the pen color */ public Color getPenColor() { return pen.getColor(); } /** * Method to set the pen color * @param color the color for the pen ink */ public void setPenColor(Color color) { pen.setColor(color); } /** * Method to set the pen width * @param width the width to use in pixels */ public void setPenWidth(int width) { pen.setWidth(width); } /** * Method to get the pen width * @return the width of the pen in pixels */ public int getPenWidth() { return pen.getWidth(); } /** * Method to get the pen from the turtle * @return the pen used by this turtle */ public Pen getPen() { return pen; } /** * Method to get the picture, if there is one. * @return the picture that this turtle draws on or null **/ public Picture getPicture() {return this.picture;} /** * Method to set the pen for this turtle * @param pen the pen to use */ public void setPen(Pen pen) { this.pen = pen; } /** * Method to get the current heading * @return the heading in degrees */ public int getHeading() { return heading; } /** * Method to set the heading * @param heading the new heading to use */ public void setHeading(int heading) { this.heading = heading; } /** * Method to get the name of the turtle * @return the name of this turtle */ public String getName() { return name; } /** * Method to set the name of the turtle * @param name the new name to use */ public void setName(String name) { this.name = name; } /** * Method to get the value of the visible flag * @return true if visible else false */ public boolean isVisible() { return visible;} /** * Method to set the visible flag * @param value the value to set it to */ public void setVisible(boolean value) { // if the turtle wasn't visible and now is if (visible == false && value == true) { // update the display updateDisplay(); } // set the visibile flag to the passed value visible = value; } /** * Method to update the display of this turtle and * also check that the turtle is in the bounds */ public void updateDisplay() { // check not below zero if (xPos < 0) xPos = 0; if (yPos < 0) yPos = 0; // if picture if (picture != null) { Graphics g = picture.getGraphics(); paintComponent(g); if (xPos >= picture.getWidth()) xPos = picture.getWidth() - 1; if (yPos >= picture.getHeight()) yPos = picture.getHeight() - 1; } else if (modelDisplay != null) { modelDisplay.modelChanged(); if (xPos >= modelDisplay.getWidth()) xPos = modelDisplay.getWidth() - 1; if (yPos >= modelDisplay.getHeight()) yPos = modelDisplay.getHeight() - 1; } } /** * Method to move the turtle forward the given number of pixels * @param pixels the number of pixels to walk forward in the heading direction */ public void forward(int pixels) { int oldX = xPos; int oldY = yPos; // change the current position xPos = oldX + (int) (pixels * Math.sin(Math.toRadians(heading))); yPos = oldY + (int) (pixels * -Math.cos(Math.toRadians(heading))); // add a line from the old position to the new position to the pen pen.addLine(oldX,oldY,xPos,yPos); // update the display to show the new line updateDisplay(); } /** * Method to move to turtle to the given x and y location */ public void moveTo(int x, int y) { pen.addLine(xPos,yPos,x,y); xPos = x; yPos = y; updateDisplay(); } /** * Method to turn left */ public void turnLeft() { turn(-90); } /** * Method to turn right */ public void turnRight() { turn(90); } /** * Method to turn the turtle the passed degrees * use negative to turn left and pos to turn right * @param degrees the amount to turn in degrees */ public void turn(int degrees) { heading = (heading + degrees) % 360; updateDisplay(); } /** * Method to draw a passed picture at the current turtle * location and rotation * @param dropPicture the picture to drop */ public void drop(Picture dropPicture) { // only do this if drawing on a picture if (picture != null) { // get the 2d graphics object from the current picture Graphics2D g2 = (Graphics2D) picture.getGraphics(); // save the current tranform AffineTransform oldTransform = g2.getTransform(); // rotate to turtle heading and translate to xPos and yPos g2.rotate(Math.toRadians(heading),xPos,yPos); // draw the passed picture g2.drawImage(dropPicture.getImage(),xPos,yPos,null); // reset the tranformation matrix g2.setTransform(oldTransform); // draw the pen pen.paintComponent(g2); } } /** * Method to paint the turtle */ public void paintComponent(Graphics g) { // cast to 2d object Graphics2D g2 = (Graphics2D) g; // if the turtle is visible if (visible) { // save the current tranform AffineTransform oldTransform = g2.getTransform(); // rotate the turtle and translate to xPos and yPos g2.rotate(Math.toRadians(heading),xPos,yPos); // determine the half width and height of the shell int halfWidth = (int) (width/2); // of shell int halfHeight = (int) (height/2); // of shell int quarterWidth = (int) (width/4); // of shell int thirdHeight = (int) (height/3); // of shell int thirdWidth = (int) (width/3); // of shell // draw the body parts (head) g2.setColor(bodyColor); g2.fillOval(xPos - quarterWidth, yPos - halfHeight - (int) (height/3), halfWidth, thirdHeight); g2.fillOval(xPos - (2 * thirdWidth), yPos - thirdHeight, thirdWidth,thirdHeight); g2.fillOval(xPos - (int) (1.6 * thirdWidth), yPos + thirdHeight, thirdWidth,thirdHeight); g2.fillOval(xPos + (int) (1.3 * thirdWidth), yPos - thirdHeight, thirdWidth,thirdHeight); g2.fillOval(xPos + (int) (0.9 * thirdWidth), yPos + thirdHeight, thirdWidth,thirdHeight); // draw the shell g2.setColor(getShellColor()); g2.fillOval(xPos - halfWidth, yPos - halfHeight, width, height); // draw the info string if the flag is true if (showInfo) drawInfoString(g2); // reset the tranformation matrix g2.setTransform(oldTransform); } // draw the pen pen.paintComponent(g); } /** * Method to draw the information string * @param g the graphics context */ public void drawInfoString(Graphics g) { g.setColor(infoColor); g.drawString(this.toString(),xPos + (int) (width/2),yPos); } /** * Method to return a string with informaiton * about this turtle */ public String toString() { return name + " turtle at " + xPos + ", " + yPos + " heading " + heading + "."; } } // end of class