THIS IS THE BIRD CLASS
import greenfoot.*; // (World, Actor, GreenfootImage, and Greenfoot)
import java.util.*;
/**
* A boid is an object that is part of a flock.
* The boid follows a few simple rules that gives emergent behaviour when lots of boids are placed in the world.
*
* @author Poul Henriksen
* @version 2.0
*/
public class Boid extends SmoothActor
{
/** Distance the wall-force will start working from. */
private final static int WALL_DIST = 50;
/** The size of wall force when it is at max. */
private final static int WALL_FORCE = 200;
/** Maximum speed of the boid. */
private final static int MAX_SPEED = 30;
/** Minimum speed of the boid. */
private final static int MIN_SPEED = 25;
/** The speed is divided by this. */
private final static int SPEED_DIVIDER = 15;
/** Distance from which repulsion from other objects start working.*/
private final static int REPULSE_DIST = 40;
/** Distance from which alignment with other boids start working. */
private final static int ALIGN_DIST = 150;
/** Distance from which attraction to other boids start working. */
private final static int ATTRACT_DIST = 150;
/**
* Creates a new boid with minimum speed in a random direction.
*/
public Boid()
{
setMaximumSpeed(MAX_SPEED);
setMinimumSpeed(MIN_SPEED);
setSpeedDivider(SPEED_DIVIDER);
Vector vel = new Vector();
vel.setDirection((Math.random())*360);
vel.setLength(MIN_SPEED);
setVelocity(vel);
}
/**
* Flock!
*/
public void act()
{
acc();
super.act();
}
/**
* Calculate accelaration by appling the boid rules
*/
private void acc() {
Vector acc = new Vector(0,0);
acc.add(getFlockAttraction(ATTRACT_DIST).divide(7.5));
acc.add(getFlockRepulsion(REPULSE_DIST).multiply(1));
acc.add(getFlockAlignment(ALIGN_DIST).divide(8));
acc.add(getWallForce());
setAccelaration(acc);
}
/**
* Get the size of the wall force on this boid. Will make the boid avoid the world boundaries.
*/
public Vector getWallForce() {
Vector location = getLocation();
//Special border repulse rules:
Vector wallForce = new Vector(0,0);
if(location.getX() <= WALL_DIST) {
double distFactor = (WALL_DIST - location.getX()) / WALL_DIST;
wallForce.add(new Vector(WALL_FORCE * distFactor, 0));
}
if( (getWorld().getWidth() - location.getX()) <= WALL_DIST) {
double distFactor = (WALL_DIST - (getWorld().getWidth() - location.getX())) / WALL_DIST;
wallForce.subtract(new Vector(WALL_FORCE * distFactor, 0));
}
if(location.getY() <= WALL_DIST) {
double distFactor = (WALL_DIST - location.getY()) / WALL_DIST;
wallForce.add(new Vector(0, WALL_FORCE * distFactor));
}
if(getWorld().getHeight() - location.getY() <= WALL_DIST) {
double distFactor = (WALL_DIST - (getWorld().getHeight() - location.getY())) / WALL_DIST;
wallForce.subtract(new Vector(0, WALL_FORCE * distFactor));
}
return wallForce;
}
/**
* Get the other objects that are within the given distance.
*/
private List getNeighbours(int distance, Class cls) {
return getObjectsInRange(distance, cls);
}
/**
* Get the center of all the boids within the given distance.
* That is, the average of all the positions of the other boids.
*/
public Vector getCentreOfMass(int distance) {
List neighbours = getNeighbours(distance, Boid.class);
//add me
neighbours.add(this);
Vector centre = new Vector();
for(Object o : neighbours) {
Boid b = (Boid) o;
centre.add(b.getLocation());
}
return centre.divide(neighbours.size());
}
/**
* Get the attraction from the other boids within the given distance.
*/
public Vector getFlockAttraction(int distance) {
Vector com = getCentreOfMass(distance);
//distance to the centre of mass
Vector distCom = getCentreOfMass(distance).subtract(getLocation());
return distCom;
}
/**
* Get the repulsion from the other boids within the given distance.
*/
public Vector getFlockRepulsion(int distance) {
Vector repulse = new Vector();
List neighbours = getNeighbours(distance, SmoothActor.class);
for(Object o : neighbours) {
SmoothActor other = (SmoothActor) o;
//dist to other actor
Vector dist = getLocation().subtract(other.getLocation());
if(dist.getLength() > distance) {
// Make sure we are looking at the logical distance.
continue;
}
repulse.add(dist.setLength(distance - dist.getLength()));
}
return repulse;
}
/**
* Get the average velocity of all boids within the given distance.
*/
private Vector getAverageVelocity(int distance) {
List neighbours = getNeighbours(distance, Boid.class);
//add me
neighbours.add(this);
Vector avg = new Vector();
for(Object o : neighbours) {
Boid b = (Boid) o;
avg.add(b.getVelocity());
}
return avg.divide(neighbours.size());
}
/**
* Get the relative direction this boid should be facing to match the average direction of the flock.
*/
private Vector getFlockAlignment(int distance) {
Vector avgVel = getAverageVelocity(distance);
avgVel.subtract(getVelocity());
return avgVel;
}
public void hit()
{
((Sky)getWorld()).countScore();
if (((Sky)getWorld()).counter.getValue() > 50*1/4)
{
((Sky)getWorld()).countScore();
((Sky)getWorld()).gameOver();
}
getWorld().removeObject(this);
}
}
WORLD CLASS
import greenfoot.*; // (World, Actor, GreenfootImage, and Greenfoot)
import java.awt.Color;
import java.util.List;
/**
* A world for the boids.
*
* @author Poul Henriksen
* @version 2.0
*/
public class Sky extends World
{
/**
* Constructor for objects of class Sky.
*
*/
Counter counter = new Counter("Birds:");
public Counter scoreCounter;
public Sky()
{
super(800, 600, 1);
getBackground().setColor(new Color(220,220,100));
getBackground().fill();
/**
* Add the birds and trees to the world;
*/
populateTrees(100);
populateBoids(50);
/**
* Make a hunter and add it to the world
*/
Hunter myHunter = new Hunter();
addObject(myHunter, getWidth()/2 ,getHeight()/2);
/**
* Make a predator and add it to the world
*/
Predator myPredator = new Predator();
addObject(myPredator, Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
addObject(counter, 780, 590);
}
/**
* DO NOT EDIT
* Method to add the birds to the world
*/
public void populateBoids(int number)
{
for(int i=0; i < number; i++) {
int x = (int) (Math.random() * getWidth());
int y = (int) (Math.random() * getHeight());
Boid b = new Boid();
addObject(b, x, y);
}
}
/**
* DO NOT EDIT
* Method to add the trees to the world
*/
public void populateTrees(int number)
{
// Size of block in pixels
int blockSize = 70;
// Trees per block
int treesPrBlock = 10;
// How close together trees in a block are. Higher number, the closer they are.
int blockCoherence = 1;
for(int block = 0; block < number / treesPrBlock; block++) {
int x = Greenfoot.getRandomNumber(getWidth()/blockSize) * blockSize;
int y = Greenfoot.getRandomNumber(getHeight()/blockSize) * blockSize;
for(int t = 0; t < treesPrBlock; t++) {
int dx = Greenfoot.getRandomNumber(blockSize/blockCoherence);
int dy = Greenfoot.getRandomNumber(blockSize/blockCoherence);
Tree b = new Tree();
addObject(b, x + dx, y + dy);
}
}
}
public Counter getCounter()
{
return counter;
}
public void countScore()
{
counter.add(1);
}
public void gameOver()
{
Scoreboard board = new Scoreboard(counter.getValue());
addObject(new Scoreboard(9), getWidth()/2, getHeight()/2);
}
COUNTER CLASS
import greenfoot.*;
/**
* Write a description of class Counter here.
*
* @author (your name)
* @version (a version number or a date)
*/
import java.awt.Color;
public class Counter extends Actor
{
/**
* Act - do whatever the Counter wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
private static final Color textColor=new Color (0,0,0);
private int value = 0;
private int target = 0;
private String text;
private int stringLength;
int score = 0;
public Counter()
{
this("");
}
public Counter(String prefix)
{
text = prefix;
stringLength = (text.length() + 2)*10;
setImage(new GreenfootImage(stringLength, 16));
GreenfootImage image = getImage();
image.setColor(textColor);
updateImage();
}
public void act()
{
if(value < target)
{
value++;
updateImage();
}
else if (value > target)
{
value--;
updateImage();
}
endGame();
}
public void add (int score)
{
target += score;
}
public int getValue()
{
return value;
}
private void updateImage()
{
GreenfootImage image = getImage();
image.clear();
image.drawString(text + value, 1, 12);
}
public void endGame()
{
if (target==13)
{
((Sky)getWorld()).gameOver();
}
}
SCOREBOARD CLASS
import greenfoot.*;
import java.awt.Color;
import java.awt.Font;
import java.util.Calendar;
/**
* Write a description of class Scoreboard here.
*
* @author (your name)
* @version (a version number or a date)
*/
public class Scoreboard extends Actor
{
/**
* Act - do whatever the Scoreboard wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
public static final float FONT_SIZE = 48.0f;
public static final int WIDTH = 400;
public static final int HEIGHT = 300;
public void act()
{
// Add your action code here.
}
public Scoreboard()
{
this(100);
}
public Scoreboard(int score)
{
makeImage("Game Over", "Score: ", score);
}
private void makeImage(String title, String prefix, int score)
{
GreenfootImage image = new GreenfootImage(WIDTH,HEIGHT);
image.setColor(new Color(255,255,255, 128));
image.fillRect(0,0, WIDTH, HEIGHT);
image.setColor(new Color(0,0,0, 128));
image.fillRect(5,5, WIDTH-10, HEIGHT-10);
Font font = image.getFont();
font = font.deriveFont(FONT_SIZE);
image.setFont(font);
image.setColor(Color.WHITE);
image.drawString(prefix + score, 60, 200);
setImage(image);
}
}
HUNTER CLASS
import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
/**
* Write a description of class Shooter here.
*
* @author (your name)
* @version (a version number or a date)
*/
public class Hunter extends Animal
{
private GreenfootImage shooter = new GreenfootImage("fudd.png");
private int reloadDelayCount;
private static final int gunReloadTime = 5;
/**
* Our hunter needs to check and see if any keys have been pressed and then
* increment the reload delay count by 1
*/
public void act()
{
checkWorldEdge();
checkForTree();
checkKeys();
reloadDelayCount++;
move();
if(Greenfoot.isKeyDown("space"))
{
getWorld().addObject(new bullet(getRotation()), getX(), getY());
}
}
public Hunter()
{
reloadDelayCount = 0;
}
/**
* Check to see if we are at the world's edge, if so turn 180 degrees
*/
private void checkWorldEdge()
{
if(atWorldEdge())
{
turn(180);
}
}
/**
* Check to see if we are facing a tree, if so turn 180 degrees
*/
private void checkForTree()
{
if(canSee(Tree.class))
{
turn(180);
}
}
/**
* Check whether there are any key pressed and react to them.
*/
private void checkKeys()
{
if (Greenfoot.isKeyDown("up"))
{
move(5);
}
if (Greenfoot.isKeyDown("down"))
{
move(-5);
}
if (Greenfoot.isKeyDown("left"))
{
turn(-7);
}
if (Greenfoot.isKeyDown("right"))
{
turn(7);
}
if (Greenfoot.isKeyDown("space"))
{
fire();
}
}
private void fire()
{
if(reloadDelayCount >= gunReloadTime)
{
bullet bullet = new bullet ();
getWorld().addObject (bullet, getX(), getY());
bullet.move ();
reloadDelayCount = 0;
}
}
}
