/*************************************************************************** * Wolf: That bad guy that chases after and eats sheep. ***************************************************************************/ class Wolf { /*************************************************************************** * Variables ***************************************************************************/ // Possible states private static final int STATE_WAITING = 0; private static final int STATE_DARTING = 1; private static final int STATE_HERDING = 2; // Info about icon private PImage m_img; private float m_scale; // Location and movement private int m_x, m_y, m_direction; private float m_speed; private int m_timeDarting; private int m_timeStopped; private int m_currentState; private static final int MAX_TIME_STOPPED = 50; private static final int MAX_TIME_DARTING = 20; // List of all the sheep and other stuff private ArrayList m_sheepList; private Dog m_dog; private int m_runAwayCornerX, m_runAwayCornerY; /*************************************************************************** * Constructor ***************************************************************************/ public Wolf(String imgLoc, float scale, int x, int y, ArrayList sheepList, Dog dog) { // Load and save the image m_img = loadImage(imgLoc); m_scale = scale; // Starting position m_x = x; m_y = y; m_direction = 0; m_speed = 0; m_timeDarting = 0; m_timeStopped = 0; // List of all the sheep m_sheepList = sheepList; m_dog = dog; m_currentState = STATE_WAITING; m_dog.wolfArrived(this); for (int s=0; s < m_sheepList.size(); s++) { ((Sheep)(m_sheepList.get(s))).wolfArrived(this); } m_runAwayCornerX = m_runAwayCornerY = 0; if (m_dog.isCircling()) { startHerding(); } } /*************************************************************************** * Getters/setters ***************************************************************************/ public void setSpeed(float s) { m_speed = s; } //public void setDirection(int d) { m_direction = d; } public int getW() { return (int)(m_img.width * m_scale); } public int getH() { return (int)(m_img.height * m_scale); } public void setLocation(int x, int y) { m_x = x; m_y = y; } /*************************************************************************** * Drawing function ***************************************************************************/ public void draw() { imageMode(CORNER); image(m_img, m_x, m_y, (m_img.width*m_scale), (m_img.height*m_scale)); } /*************************************************************************** * Check the state of the wolf and move it accordingly. ***************************************************************************/ public void move() { if (m_currentState == STATE_WAITING) { m_timeStopped++; if (m_timeStopped > MAX_TIME_STOPPED) { m_currentState = STATE_DARTING; m_timeDarting = 0; orientToSheep(); } } if (m_currentState == STATE_DARTING) { moveDart(); m_timeDarting++; if (m_timeDarting > MAX_TIME_DARTING) { m_currentState = STATE_WAITING; m_timeStopped = 0; } } if (m_currentState == STATE_HERDING) { moveHerding(); } checkSheepCollisions(); } /*************************************************************************** * Dart ***************************************************************************/ private void moveDart() { float changeInX = m_speed * cos(radians(m_direction)); float changeInY = m_speed * sin(radians(m_direction)); if (!checkBoundaries((int)changeInX, (int)changeInY)) { m_x += (int)changeInX; m_y += (int)changeInY; } } /*************************************************************************** * Run away from the herd into a corner ***************************************************************************/ private void moveHerding() { if (dist(m_x, m_y, m_runAwayCornerX, m_runAwayCornerY) < 5) { return; } m_direction = (int)(degrees(atan2(m_runAwayCornerY - m_y, m_runAwayCornerX - m_x))); float changeInX = m_speed * 2 * cos(radians(m_direction)); float changeInY = m_speed * 2 * sin(radians(m_direction)); if (!checkBoundaries((int)changeInX, (int)changeInY)) { m_x += (int)changeInX; m_y += (int)changeInY; } } /*************************************************************************** * Orient towards a sheep ***************************************************************************/ private void orientToSheep() { if (m_sheepList.size() > 0) { Sheep s; do { // Pick a random sheep s = (Sheep)m_sheepList.get((int)random(1,m_sheepList.size())-1); // Figure out the angle towards it m_direction = s.getAngle(m_x, m_y); } while (s.isDeadOrDying() || s.isDoneOrGettingDone()); } } /*************************************************************************** * Orient to corner ***************************************************************************/ private void orientToCorner() { int w = (int)(m_img.width * m_scale); int h = (int)(m_img.height * m_scale); int finalX, finalY; float d[] = new float[4]; d[0] = d[1] = d[2] = d[3] = -1; int x[] = new int[4]; int y[] = new int[4]; if (!m_dog.withinCirclingRadius(sheepBoundaryX1, sheepBoundaryY1) && !m_dog.crossingCirclingRadius(m_x, m_y, sheepBoundaryX1, sheepBoundaryY1)) { finalX = x[0] = sheepBoundaryX1; finalY = y[0] = sheepBoundaryY1; d[0] = dist(m_x, m_y, finalX, finalY); } if (!m_dog.withinCirclingRadius(sheepBoundaryX2-w, sheepBoundaryY1) && !m_dog.crossingCirclingRadius(m_x, m_y, sheepBoundaryX2-w, sheepBoundaryY1)) { finalX = x[1] = sheepBoundaryX2-w; finalY = y[1] = sheepBoundaryY1; d[1] = dist(m_x, m_y, finalX, finalY); } if (!m_dog.withinCirclingRadius(sheepBoundaryX1, sheepBoundaryY2-h) && !m_dog.crossingCirclingRadius(m_x, m_y, sheepBoundaryX1, sheepBoundaryY2-h)) { finalX = x[2] = sheepBoundaryX1; finalY = y[2] = sheepBoundaryY2-h; d[2] = dist(m_x, m_y, finalX, finalY); } if (!m_dog.withinCirclingRadius(sheepBoundaryX2-w, sheepBoundaryY2-h) && !m_dog.crossingCirclingRadius(m_x, m_y, sheepBoundaryX2-w, sheepBoundaryY2-h)) { finalX = x[3] = sheepBoundaryX2-w; finalY = y[3] = sheepBoundaryY2-h; d[3] = dist(m_x, m_y, finalX, finalY); } float minD = d[0]; int minIdx = 0; for (int i=1; i < 4; i++) { if (minD > d[i]) { minD = d[i]; minIdx = i; } } m_runAwayCornerX = x[minIdx]; m_runAwayCornerY = y[minIdx]; m_direction = (int)(degrees(atan2(m_runAwayCornerY-m_y, m_runAwayCornerX-m_x))); } /*************************************************************************** * Check the boundaries, and adjust the direction accordingly ***************************************************************************/ private boolean checkBoundaries(int dx, int dy) { boolean hitBoundary = false; // Left boundary if (m_x + dx < sheepBoundaryX1) { //m_x = sheepBoundaryX1; hitBoundary = true; } // Right boundary if (m_x + dx + m_scale*m_img.width > sheepBoundaryX2) { //m_x = sheepBoundaryX2 - (int)(m_scale*m_img.width); hitBoundary = true; } // Top boundary if (m_y + dy < sheepBoundaryY1) { //m_y = sheepBoundaryY1; hitBoundary = true; } // Bottom boundary if (m_y + dy + m_scale*m_img.height > sheepBoundaryY2) { //m_y = sheepBoundaryY2 - (int)(m_scale*m_img.height); hitBoundary = true; } return hitBoundary; } /*************************************************************************** * Check whether we are touching a sheep (unless we are in escape mode) ***************************************************************************/ public void checkSheepCollisions() { if (m_currentState != STATE_HERDING) { int w = (int)(m_img.width * m_scale); int h = (int)(m_img.height * m_scale); for (int s=0; s < m_sheepList.size(); s++) { Sheep sheep = (Sheep)(m_sheepList.get(s)); if (!sheep.isDeadOrDying() && !sheep.isDoneOrGettingDone()) { if (sheep.collides(m_x, m_x+w, m_y, m_y+h)) { killSheep(sheep); } } } } } /*************************************************************************** * Does the wolf collide with the given sheep? ***************************************************************************/ public boolean collides(Sheep s) { return s.collides(m_x, m_x+getW(), m_y, m_y+getH()); } /*************************************************************************** * The wolf collided with a sheep - eat it! :D ***************************************************************************/ public void killSheep(Sheep sheep) { // Get the sheep to go into kill mode sheep.die(); } /*************************************************************************** * Does the wolf collide with a given set of boundaries? ***************************************************************************/ public boolean collides(int x1, int x2, int y1, int y2) { // int x1Me = m_x; // int x2Me = m_x + (int)(m_img.width * m_scale); // // int y1Me = m_y; // int y2Me = m_y + (int)(m_img.height * m_scale); // // if ((x1Me >= x1 && x1Me <= x2 && y1Me >= y1 && y1Me <= y2) || // (x2Me >= x1 && x2Me <= x2 && y2Me >= y1 && y2Me <= y2)) // { // return true; // } // else // { // return false; // } int xMe = m_x + (int)(0.5 * m_img.width * m_scale); int yMe = m_y + (int)(0.5 * m_img.height * m_scale); return (xMe > x1 && xMe < x2 && yMe > y1 && yMe < y2); } /*************************************************************************** * Get the angle from the location to the wolf ***************************************************************************/ public int getAngleTo(int x, int y) { float rads = atan2(m_y - y, m_x - x); return (int)(degrees(rads)); } /*************************************************************************** * Get the angle to the location from the wolf ***************************************************************************/ public int getAngleFromCenter(int x, int y) { int xWolf = (int)(m_x + m_img.width/2); int yWolf = (int)(m_y + m_img.height/2); float rads = atan2(y - yWolf, x - xWolf); return (int)(degrees(rads)); } /*************************************************************************** * Get the distance to the location from the wolf ***************************************************************************/ public int getDistanceFromCenter(int x, int y) { int xWolf = (int)(m_x + m_img.width/2); int yWolf = (int)(m_y + m_img.height/2); return (int)dist(x,y,xWolf,yWolf); } /*************************************************************************** * Start or stop herding behaviour ***************************************************************************/ public void startHerding() { m_currentState = STATE_HERDING; orientToCorner(); } public void stopHerding() { m_currentState = STATE_DARTING; m_timeDarting = 0; orientToSheep(); } }// end class Wolf