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; } }