This site requires JavaScript, please enable it in your browser!
Greenfoot back
hubert14
hubert14 wrote ...

2015/6/16

Actor won't get added

hubert14 hubert14

2015/6/16

#
I am just starting out with Greenfoot so bear with me. I am working through the Greenfoot book. One of the programs in the book is a crab/worm/lobster scenario. I am trying to make the program work such that if there are no worms left in the world, the program will end, but I get a null pointer when I try to add a crab. Any help is awesome! My worm class is empty. Crab Class
import greenfoot.*;

/**
 * This class defines a crab. Crabs live on the beach.
 */
public class Crab extends Actor
{
    public int count = 0;
    public int wormCount = ((CrabWorld)getWorld()).getCount();
    public void act()
    {
        turnOnEdge();
        this.keyboardControl();
        this.lookForWorm();
        isOver();
    }
    
    public void lookForWorm()
    {
        if(isTouching(Worm.class))
        {
            removeTouching(Worm.class);
            count++;
        }
    }
    
    public int getCount()
    {
        return count;
    }
    
    public void randomTurn()
    {
        if(Greenfoot.getRandomNumber(100)<10)
        {
            turn(Greenfoot.getRandomNumber(90)-45);
        }
    }
    
    public void turnOnEdge()
    {
          if(isAtEdge())
        {
            turn(17);
        }
    }
    
    public void keyboardControl()
    {
        if(Greenfoot.isKeyDown("left"))
        {
            setRotation(180);
            move(5);
        }
        if(Greenfoot.isKeyDown("right"))
        {
            setRotation(0);
            move(5);
        }
        if(Greenfoot.isKeyDown("up"))
        {
            setRotation(270);
            move(5);
        }
        if(Greenfoot.isKeyDown("down"))
        {
            setRotation(90);
            move(5);
        }
    }
    
    public int isOver()
    {
        if(count == wormCount)
        {
            Greenfoot.stop();
        }
        return wormCount;
    }
}
CrabWorld
import greenfoot.*;  // (Actor, World, Greenfoot, GreenfootImage)

public class CrabWorld extends World
{
    public int count = 0;
    
    /**
     * Create the crab world (the beach). Our world has a size 
     * of 560x560 cells, where every cell is just 1 pixel.
     */
    public CrabWorld() 
    {
       super(560, 560, 1);
    }
    
    public int getCount()
    {
        for(Object worm : getObjects(Worm.class)) 
        {
            count++;
        }
        return count;
    }
}
miningmanna miningmanna

2015/6/16

#
try to initialize the wormCount in a constructor. The Crab class tries to get the world it is in even though its not even created yet.
danpost danpost

2015/6/16

#
miningmanna wrote...
try to initialize the wormCount in a constructor. The Crab class tries to get the world it is in even though its not even created yet.
With this:
public int wormCount = ((CrabWorld)getWorld()).getCount();
you are indeed trying to 'getWorld' before the actor is created, which, as stated by miningmanna, will not work ('getWorld' will return a 'null' value; so you cannot execute 'getCount' on it). However, it will still return a 'null' value even in the constructor of the class. The object must be created before it can be added into a world (the constructor is executed when 'new Crab()' is called; the crab is added to the world after that when 'addObject(new Crab(), x, y)' is processed). You could override the 'addedToWold(World)' method of the Actor class to set the value of 'wormCount' with that assignment in it. However, I feel you are going about what you are trying to do in a "backward" sense. Instead of complicating things by adding the limiting field 'wormCount', you could just check the number of worms remaining in the world. Since no worms will be in the world when the last one is eaten, you could just ask:
private void isOver()
{
    if (getWorld().getObjects(Worm.class).isEmpty())
    {
        Greenfoot.stop();
    }
}
I do not see why the value of 'wormCount', which I believe remains constant, needs to be returned from the method; or why the method needs to be 'public', since it is called from within the class. The 'getCount' method in your CrabWorld class essentially returns this:
return getObjects(Worm.class).size();
Since this value is easily obtainable, there is no need for the 'count' field or the 'getCount' method in your CrabWorld class. Use discretion when deciding whether a field is needed or not. The more fields you use, the more complicated the code and the more chance that a field may end up having a value that does not accurately portray the current state of the object. Using the current code as an example, the return line above will always return the correct value while the 'count' field must be properly maintained (its accuracy is dependent on how well you wrote your code to maintain it). Avoid writing methods that do basically the same thing as what one or two chained methods can already do. Use the documentation to your advantage. If you look at the 'getObjects' method in the World class documentation, you will see it returns a java.util.List object. If you look at the 'java.util.List' class documentation, you will see what methods can be executed on the returned List object ('size', isEmpty', etc.).
hubert14 hubert14

2015/6/16

#
Thank you, danpost! You're totally right, I did that in a terrible way haha. Wow. Thanks for your help guys!
You need to login to post a reply.