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

How to access one object from another

A common question that Greenfoot beginners ask is:

How can I access the variables (or methods) of one object/class from another one?

But of course usually it is phrased differently... sometimes beginners don't yet understand what "variables" or "objects" are. So the question might look more like this:

How can I update the score counter whenever an asteroid is destroyed by the rocket?

Image: Rocket shooting at an asteroid

Now, take a look at the Greenfoot scenario pictured above:

tut-access-p1 (right-click and open the link in a new window or tab).

This scenario is a simple game where you press the space bar to fire shots from a rocket at the asteroids that pass by overhead. There is a score counter, but it is currently not functional. Click on the "open scenario in Greenfoot" link to download a copy of the scenario to your computer, and start working on it.

In this example, there are several classes, including "Counter", "Rocket" and "Shot". The Counter has a method called "bumpCount()" which increases the score which the counter displays:

void bumpCount(int amount)
{ totalCount += amount; setImage(new GreenfootImage("" + totalCount)); }

If you don't understand that code, don't worry about it for now. The important thing to know is: if you call the bumpCount() method, it will increase the number which the counter displays by the amount you specify. (Try it out! Right-click the counter object in the world, choose the "bumpCount(int)" method, and specify a number).

Now, in the Shot class, we might have a method which is called (from the act() method) whenever an asteroid is hit:

void hitAnAsteroid()
{
    // What goes here????
    // We want to call the "bumpCount" method from the Counter class -
    // but how??!!
}

Open the editor for the Shot class (double-click the "Shot" class at the right).

Now the question is: how can I call the "bumpCount" method, which is in the Counter class, from the Shot class?

If we simply try to call bumpCount() in the normal way, we'll get an error when we try to compile:

void hitAnAsteroid()
{
    bumpCount();
}

Go on - try it. You see a compiler error saying something like:

Cannot find symbol - method bumpCount()

We get this error because the compiler only looks in thesame class - the Shot class - for the "bumpCount" method, but there is no bumpCount method in the Shot class! We need to somehow tell the compiler to look in the Counter class instead.

Before continuing, remove the "bumpCount()" method call from the hitAnAsteroid() method so that the code compiles cleanly again.

Solution: Store the reference in the world when creating the object

In this solution we'll store a reference to the counter in the world, then retrieve it from the shot when we need to.

Take a look at the Space constructor:

public Space()
{
    super(600, 400, 1);
    addObject(new Rocket(), 300, 200);  // add the rocket
    addObject(new Counter(), 5, 5);  // add the counter
}

We need to do two things: firstly, declare a field to store the reference to the Counter, and then assign that variable when the counter is created. Change the Space constructor so that it looks like this:

private Counter theCounter;

public Space()
{
    super(600, 400, 1);
    addObject(new Rocket(), 300, 200);
    theCounter = new Counter();
    addObject(theCounter, 5, 5);
}

Make sure your code compiles before you continue.

Notice that we added a declaration for a variable called "theCounter". This is an instance variable, meaning that we want the keep the value for as long as the world exists, and so it is declared outside the SpaceWorld constructor (but inside the SpaceWorld class).

Now, add a method to the Space class to retrieve the value of "theCounter" so it can be accessed by the rocket:

public Counter getCounter()
{
    return theCounter;
}

We can then access the world from the shot, and then call the getCounter method on the world to obtain a reference to the counter; finally, we can call the bumpCount method on the counter reference! The hitAnAsteroid method in the Shot class should then look like this:

void hitAnAsteroid()
{
    Space spaceWorld = (Space) getWorld();  // get a reference to the world
    Counter counter = spaceWorld.getCounter();  // get a reference to the counter
    counter.bumpCount(5);
}

Go ahead and make the same changes in your copy of the scenario. Make sure it compiles!

And that's it! We have a solution to the problem. When the shot needs to increment the counter, it asks the world for a reference to the counter, and then modifies the counter using that reference. Run your modified scenario and make sure it works correctly.

To see the completed solution, look at the source code here:

tut-access-p2