In my game I have an actor called Demon who spawns every time a "blood moon" event occurs (which occurs about every 7-10 seconds or so). Upon spawning i attempted to code it so he would move towards the closest villager to eat it, and then retarget to the next closest and so on. However, for some reason when it spawns in it returns a NullPointerException.
Blood Demon Code:
World code (The part related to the Blood Moon event is in the last part of the spawn method):
Blood Moon Event Code:
import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.ArrayList;
/**
* The Ambulance subclass
*/
public class BloodDemon extends Vehicle
{
private ArrayList <Villager> villagers;
private Villager targetVillager;
public BloodDemon(VehicleSpawner origin){
super(origin); // call the superclass' constructor
GreenfootImage image = getImage();
image.scale(image.getWidth() - 200, image.getHeight() - 250);
setImage(image);
maxSpeed = 1.5 + ((Math.random() * 30)/5);
speed = maxSpeed;
yOffset = 0;
targetClosestVillager();
}
/**
* Act - do whatever the Ambulance wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
public void act()
{
if (targetVillager != null && targetVillager.getWorld() != null)
{
checkHitPedestrian();
moveTowardVillager();
}
else
{
moveRandomly();
}
/*drive();
checkHitPedestrian();
if (checkEdge()){
getWorld().removeObject(this);
}*/
}
private void targetClosestVillager ()
{
double closestTargetDistance = 0;
double distanceToActor;
int numVil;
// Get a list of all Villagers in the World, cast it to ArrayList
// for easy management
numVil = getWorld().getObjects(Villager.class).size();
// If any villagers are found
if (numVil > 50) // If lots of villagers are found, search small area
{
villagers = (ArrayList)getObjectsInRange(80, Villager.class);
}
else if (numVil > 20) // If less villagers are found, search wider radius
{
villagers= (ArrayList)getObjectsInRange(180, Villager.class);
}
else // If even fewer villagers are found, search the whole World
villagers = (ArrayList)getWorld().getObjects(Villager.class);
if (villagers.size() > 0)
{
// set the first one as my target
targetVillager = villagers.get(0);
// Use method to get distance to target. This will be used
// to check if any other targets are closer
closestTargetDistance = VehicleWorld.getDistance (this, targetVillager);
// Loop through the objects in the ArrayList to find the closest target
for (Villager o : villagers)
{
// Cast for use in generic method
//Actor a = (Actor) o;
// Measure distance from me
distanceToActor = VehicleWorld.getDistance(this, o);
// If I find a villager closer than my current target, I will change
// targets
if (distanceToActor < closestTargetDistance)
{
targetVillager = o;
closestTargetDistance = distanceToActor;
}
}
}
}
private void moveRandomly ()
{
if (Greenfoot.getRandomNumber (100) == 50)
{
turn (Greenfoot.getRandomNumber(360));
}
else
drive();
}
private void moveTowardVillager()
{
turnTowards(targetVillager.getX(), targetVillager.getY());
drive();
}
public boolean checkHitPedestrian () {
Pedestrian p = (Pedestrian)getOneObjectAtOffset((int)speed + getImage().getWidth()/2, 0, Pedestrian.class);
if (p != null){
getWorld().removeObject(p);
return true;
}
return false;
}
}
public class VehicleWorld extends World
{
private GreenfootImage background;
// Color Constants
public static Color GREY_BORDER = new Color (108, 108, 108);
public static Color GREY_STREET = new Color (88, 88, 88);
public static Color YELLOW_LINE = new Color (255, 216, 0);
public static Color GREEN_STREET = new Color (114, 135, 0);
public static Color BROWN_LINE = new Color (101, 67, 33);
public static Color BROWN_BORDER = new Color (101, 67, 33);
// Instance variables / Objects
private boolean twoWayTraffic, splitAtCenter;
private int laneHeight, laneCount, spaceBetweenLanes;
private int[] lanePositionsY;
private VehicleSpawner[] laneSpawners;
private GreenfootSound worldSound;
//Static Variables
private static boolean bloodMooning;
/**
* Constructor for objects of class MyWorld.
*
*/
public VehicleWorld()
{
// Create a new world with 600x400 cells with a cell size of 1x1 pixels.
super(800, 600, 1, false);
setPaintOrder (Villager.class, EvilWitch.class, GoodWitch.class, Acidmon.class, BloodDemon.class, Prowler.class);
bloodMooning = false;
worldSound = new GreenfootSound ("backgroundsound.wav");
// set up background
GreenfootImage background = new GreenfootImage("background.png");
background.scale(getWidth(), getHeight());
setBackground(background);
// Set critical variables
laneCount = 6;
laneHeight = 48;
spaceBetweenLanes = 6;
splitAtCenter = false;
twoWayTraffic = false;
setActOrder(Pedestrian.class);
// Init lane spawner objects
laneSpawners = new VehicleSpawner[laneCount];
// Prepare lanes method - draws the lanes
lanePositionsY = prepareLanes (this, background, laneSpawners, 222, laneHeight, laneCount, spaceBetweenLanes, twoWayTraffic, splitAtCenter);
}
public void act () {
spawn();
}
public void started()
{
worldSound.setVolume(80);
worldSound.play();
}
public boolean isGrabbed(final Villager villager)
{
for (final Grabber grabber : getObjects(Grabber.class)) {
if (villager.equals(grabber.getGrabbed())) {
return true;
}
}
return false;
}
public static float getDistance (Actor a, Actor b)
{
double distance;
double xLength = a.getX() - b.getX();
double yLength = a.getY() - b.getY();
distance = Math.sqrt(Math.pow(xLength, 2) + Math.pow(yLength, 2));
return (float)distance;
}
private void spawn () {
// Chance to spawn a vehicle
if (Greenfoot.getRandomNumber (60) == 0){
int lane = Greenfoot.getRandomNumber(laneCount);
if (!laneSpawners[lane].isTouchingVehicle()){
int vehicleType = Greenfoot.getRandomNumber(4);
if (vehicleType == 0){
addObject(new Acidmon(laneSpawners[lane]), 0, 0);
//} else if (vehicleType == 2){
//addObject(new BloodDemon(laneSpawners[lane]), 0, 0);
} else if (vehicleType == 1){
addObject(new Prowler(laneSpawners[lane]), 0, 0);
} else if (vehicleType == 2){
addObject(new RootedCorpse(laneSpawners[lane]), 0, 0);
}
}
}
// Chance to spawn a Pedestrian
if (Greenfoot.getRandomNumber (80) == 0){
int xSpawnLocation = Greenfoot.getRandomNumber (600) + 100; // random between 99 and 699, so not near edges
boolean spawnAtTop = true;//Greenfoot.getRandomNumber(2) == 0 ? true : false;
if (spawnAtTop){
addObject (new Villager (1), xSpawnLocation, 50);
} else {
addObject (new Villager (-1), xSpawnLocation, 550);
}
}
else if (Greenfoot.getRandomNumber (160) == 0){
int xSpawnLocation = Greenfoot.getRandomNumber (600) + 100; // random between 99 and 699, so not near edges
boolean spawnAtTop = true;//Greenfoot.getRandomNumber(2) == 0 ? true : false;
if (spawnAtTop){
addObject (new EvilWitch (1), xSpawnLocation, 50);
} else {
addObject (new EvilWitch (-1), xSpawnLocation, 550);
}
}
else if (Greenfoot.getRandomNumber (160) == 0){
int xSpawnLocation = Greenfoot.getRandomNumber (600) + 100; // random between 99 and 699, so not near edges
boolean spawnAtTop = true;//Greenfoot.getRandomNumber(2) == 0 ? true : false;
if (spawnAtTop){
addObject (new GoodWitch (1), xSpawnLocation, 50);
} else {
addObject (new GoodWitch (-1), xSpawnLocation, 550);
}
}
//Blood moon event
if (!bloodMooning && Greenfoot.getRandomNumber(200) == 0){
int lane = Greenfoot.getRandomNumber(laneCount);
addObject (new BloodMoon(240), 400, 300);
addObject(new BloodDemon(laneSpawners[lane]), 0, 0);
bloodMooning = true;
}
if (bloodMooning && getObjects(BloodMoon.class).size() == 0){
bloodMooning = false;
}
}
public static boolean isBloodMooning()
{
return bloodMooning;
}
/**
* Given a lane number (zero-indexed), return the y position
* in the centre of the lane. (doesn't factor offset, so
* watch your offset, i.e. with Bus).
*
* @param lane the lane number (zero-indexed)
* @return int the y position of the lane's center, or -1 if invalid
*/
public int getLaneY (int lane){
if (lane < lanePositionsY.length){
return lanePositionsY[lane];
}
return -1;
}
/**
* Given a y-position, return the lane number (zero-indexed).
* Note that the y-position must be valid, and you should
* include the offset in your calculations before calling this method.
* For example, if a Bus is in a lane at y=100, but is offset by -20,
* it is actually in the lane located at y=80, so you should send
* 80 to this method, not 100.
*
* @param y - the y position of the lane the Vehicle is in
* @return int the lane number, zero-indexed
*
*/
public int getLane (int y){
for (int i = 0; i < lanePositionsY.length; i++){
if (y == lanePositionsY[i]){
return i;
}
}
return -1;
}
}import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.ArrayList;
/**
* Write a description of class BloodMoon here.
*
* @author (your name)
* @version (a version number or a date)
*/
public class BloodMoon extends Effect
{
private int duration;
private GreenfootSound eventSound;
public BloodMoon (int duration){
this.duration = duration;
eventSound = new GreenfootSound ("BloodMoonSound.wav");
}
public void addedToWorld (World w){
image = drawBlood (w.getWidth(), w.getHeight(), 200);
setImage(image);
eventSound.setVolume(80);
eventSound.play();
ArrayList<Vehicle> vehicles = (ArrayList<Vehicle>) w.getObjects(Vehicle.class);
for (Vehicle v : vehicles){
v.speedUp();
}
}
/**
* Act - do whatever the Snowstorm wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
public void act()
{
if (duration == 0){
getWorld().removeObject(this);
} else if (duration <= 180){
fade (duration, 180);
}
duration--;
}
/**
* density should be 1-100. 100 will be almost completely white
*/
public static GreenfootImage drawBlood (int width, int height, int density){
Color[] swatch = new Color [64];
int red = 128;
int blue = 192;
for (int i = 0; i < swatch.length/2; i++){
swatch[i] = new Color (255, 0, 0);
}
for (int i = swatch.length/2; i < swatch.length; i++){
swatch[i] = new Color (255, 0, 0);
}
// The temporary image, my canvas for drawing
GreenfootImage temp = new GreenfootImage (width, height);
//temp.setColor (Color.BLACK);
//temp.fill();
// Run this loop one time per "density"
for (int i = 0; i < density; i++){
for (int j = 0; j < 150; j++){ // draw 100 circles
int randSize;
// Choose a random colour from my swatch, and set its tranparency randomly
int randColor = Greenfoot.getRandomNumber(swatch.length);;
int randTrans = Greenfoot.getRandomNumber(220) + 35; // around half transparent
temp.setColor (swatch[randColor]);
//setTransparency(randTrans);
// random locations for our dot
int randX = Greenfoot.getRandomNumber (width);
int randY = Greenfoot.getRandomNumber (height);
int tempVal = Greenfoot.getRandomNumber(250);
if (tempVal >= 1){
//randSize = 2;
temp.drawRect (randX, randY, 0, 0);
}else{
randSize = Greenfoot.getRandomNumber (2) + 2;
temp.fillOval (randX, randY, randSize, randSize);
}
// silly way to draw a dot..
}
}
return temp;
}
}