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

2013/4/21

Accessing methods in other objects??

1
2
allekalle allekalle

2013/4/21

#
Hi! I have made a "TextBox" actor class to show up different texts. When I do this in the background (world class) constructor: TextBox turnBox = new TextBox("Turn: X"); addObject(turnBox, 197, 20); turnBox.makeImage("test"); The text box shows up fine with the right text, but when I try this from another object: turnBox.makeImage("textTest"); it doesn't work ("cannot find symbol - variable turnBox"). Why is this? The object is there. Do I have to make the compiler "see it" somehow in the object calling it?
Gevater_Tod4711 Gevater_Tod4711

2013/4/21

#
The object turnBox is declared in the world class. And only there (or maybe in subclasses) it's visible. If you want to create a new object and execute the method makeImage it it should work like this:
1
TextBox turnBox = new TextBox("Turn: X"); getWorld().addObject(turnBox, 197, 20); turnBox.makeImage("test");
But if you try to acces the object in the world you have to do it like this:
1
2
3
4
5
6
7
8
9
//in the world class:
private TextBox turnBox;
 
//in the constructor you have to initialise this object;
//almost like you did before with the exception that you have to use turnBox = ... instead of TextBox turnbox = ...;
 
public TextBox getTurnBox() {
    return turnBox;
}
1
2
3
4
//in your object from wicht you want to execute the method:
 
((WorldName) getWorld()).getTurnBox().makeImage("textTest");
//instead of WorldName you have to use the classname of your world.
allekalle allekalle

2013/4/21

#
I think I got it working using your information. But I don' t really understand it very well to be quite honest. Would it be easier if I made a special subclass z right under actor define some methods there? For some reason I thought it was practical to create objects in the world class constructor since it is run automatically on start-up. Maybe it's more practical to create the objects in the subclass z directly under Actor, create the further objects there (when only that object is created from the world class) and then Would it be possible to access methods from parallel objects (objects of classes on the same level under e.g. Actor)? I tried the intermediate sub-actor now, and got a number of other strange compiler errors. After a some changes again, I got exceptions when running it instead. Is there an easy way to write this code? Thanks! Karl
Gevater_Tod4711 Gevater_Tod4711

2013/4/21

#
To initialise object in the world is the easyest and also best possibility I think. If you declare them in a sublcass of actor every actor knows this objects but I'm not even shure if this can work (if you get a stackOverflowError be shure it'll not work). So to create objects in the world is the best way for adding your actors at the beginning of the game. If you need the references to some actors and you don't want to declare methods for each and every object you also can use the methods getObjects or getObjectsAt ... of the world class because all objects are saved in the class World and so you can reach them. To see how you can do this you should do this Greenfoot tutorial.
danpost danpost

2013/4/21

#
No. Making a special subclass z right under actor will only confuse things. Sub-classes should be objects of their super-class type with more specific characteristics and behaviours. For example, a sub-class of actor called 'Bicycle' can have sub-classes such as 'MountainBike', 'TourBike', and 'StreetBike'. They are all part of the 'Bicycle' family, just different 'species', you might say. And yes, it is practical to create objects in the world class constructor (or a method it calls -- usually called 'prepare'). Yes. It is certainly possible to access values and methods across classes; and it matters not whether it is Actor to Actor, Actor to World, or World to Actor (or even World to World). You just need an instance of that class to run the methods on. There are various ways to do this and it would depent on what you were trying to do at the time. Line 3 in the code above:
1
((WorldName) getWorld()).getTurnBox().makeImage("textTest");
'getWorld' returns a World object; however, because 'getTurnBox' in not part of the World class API, we need to specify that it is of type 'WorldName' so the compiler will look in your sub-class of world for that method. That is why the type casting of '(WorldName)' is placed in front of it and parenthesis are placed around them. Now, 'getTurnBox' has a retun type of 'TurnBox', which is the class where 'makeImage' is located, so we do not need to further type cast it.
allekalle allekalle

2013/4/21

#
OK, I got a stackoverflow error message (whatever that means). I guess I see how to do it now. If I understand things right, you always need to get the reference to the world since the object was (and should be) created there. (I just think it would have been easier if the compiler would understand direct object references like object.method() from anywhere). Just another question: this is a solution very specific for Greenfoot. What would the normal java solution be, if you work in Netbeans, for example. Would you create the objects in the Main method in the Main class and use a method corresponding to getWorld()? I guess games also need a method that keeps things running, like "run" in Greenfoot? Thanks for the answers!
Gevater_Tod4711 Gevater_Tod4711

2013/4/21

#
The principle is always the same. You need a reference to the object if you want to execute it's methods or get it's objects. This is almost the same that the getWorld() method does. The getWorld method returns the reference to the world the actor is in. If you don't use Greenfoot you most times start with the method public void main(String args). This method is executed at the beginning of the execution. There you need to declare the first objects and connect them to each other. Therefor you can use the constructor of objects or object methods:
1
2
3
4
5
6
7
8
9
10
11
private ObjectB objectB;
 
//using the constructor;
public ObjectA(ObjectB objectB) {
    this.objectB = objectB;
}
 
//or methods;
public void setObjectB(ObjectB objectB) {
    this.objectB = objectB;
}
To execute any methods you first need a main method. If you want to execute your programm again and again you most times use an infiniteloop in the main method:
1
2
3
4
5
public void main(String[] args) {
    while (true) {
        //the code you want to execute;
    }
}
This will make your programm "run".
allekalle allekalle

2013/4/21

#
Thanks! I will try it out. Karl
allekalle allekalle

2013/4/23

#
Hi again! Sorry, I didn't understand the this.objectB = objectB; statement. What does it do? By the way, I have a feeling that I could do with some fundamental Java theory here about the object to object communication. Can anyone recommend a Java or general OO book (passage) or internet site that would explain the thinking behind all this? Thanks! Karl
davmac davmac

2013/4/23

#
If I understand things right, you always need to get the reference to the world since the object was (and should be) created there.
It has nothing to do with where the object was created; it's necessary because the world contains a reference to the object you want to manipulate. You're not correctly understanding what an object is (versus a reference). An object doesn't have a name. Only references to objects have names - these are 'variables' and they have scope, that is, they are not universal - they are restricted to either the same class or the same method, depending on where you declare them. So, going back to your original question:
The text box shows up fine with the right text, but when I try this from another object: turnBox.makeImage("textTest"); it doesn't work ("cannot find symbol - variable turnBox"). Why is this? The object is there. Do I have to make the compiler "see it" somehow in the object calling it?
The object is there, but it doesn't have a name, and there's no universal "turnBox" variable holding a reference to it. If you want to access it from another object, you either need to pass the reference to that object (via a method call or by storing a reference directly in a variable inside that object), or you need to store the reference somewhere that the other object can access, or provide an accessor method. This is what Gevater_tod Gevater_Tod4711's first post talks about.
Just another question: this is a solution very specific for Greenfoot. What would the normal java solution be, if you work in Netbeans, for example. Would you create the objects in the Main method in the Main class and use a method corresponding to getWorld()? I guess games also need a method that keeps things running, like "run" in Greenfoot?
Greenfoot is ultimately just Java, though when you write a scenario in Greenfoot you aren't writing all the code yourself - you're using some of the code that Greenfoot provides. A solution in another environment is likely going to be quite similar. Yes, games also need some sort of driver to keep things moving - a "run" method if you like.
allekalle allekalle

2013/4/23

#
" An object doesn't have a name. Only references to objects have names - these are 'variables' and they have scope" Thanks! That clears some things up! Next, I have to get used to how to write "getters" and "setters", I suppose (and how to access them). How about making the object references "static"? Thanks!
davmac davmac

2013/4/23

#
How about making the object references "static"?
You can declare variables to be static, if you like: static TextBox turnBox; ... Which means you can then access the variable from anywhere by prefixing it with "Classname.", eg if you declare it in a class called "MyWorld" then you can access it from another class as "MyWorld.turnBox". The 'static' means there is only one variable for the whole class, rather than one variable for each instance (object) of the class.
danpost danpost

2013/4/23

#
"static" references are okay for things you will keep for the entirety of your scenario or for immutable objects (objects that do not have any fields whose value(s) are variable ). Otherwise, you will have to worry about programmatically resetting those values or replacing those objects in your world constructor. 'Getters' and 'setters' are not difficult to work with. For any instance field in a class (I will call it 'field'), whether it be an int, boolean, String, Object, or whatever (I will call it 'Type' -- for any type) the methods will always take the same form:
1
2
3
4
5
6
7
8
9
10
// getter
public Type getField()
{
    return field;
}
// setter
public void setField(Type value)
{
    field = value;
}
Let us call the class these methods are in 'MethodClass'; it matters not whether it is a sub-class of World or Actor, the accessing of the methods is still the same. First, you need an Object reference of an instance of the 'MethodClass'. This can be from a value of an instance field or from one of the 'get' methods that returns an actor or world object, or from a list of actors returned from a 'get' method. Once you have the reference (let us call it 'methodObj'), you can access the methods with:
1
2
3
4
// to get
Type fieldValue = methodObj.getField();
// to set
methodObj.setField(fieldValue);
When using a built-in 'get' method (one from the Actor or World class API) to get a reference to the object, it will be of type 'Object' or 'Actor'. You will need to type cast those returns with 'MethodClass':
1
2
3
4
// an example from an Actor class
MethodClass methodObj = (MethodClass) getOneIntersectingObject(MethodClass.class);
//an example from the world class
MethodClass methodObj = ((MethodClass) getObjects(MethodClass.class).get(0));
The getting of the object and use of the method can be accomplished in one statement:
1
2
3
Type fieldValue = ((MethodClass) getOneIntersectingObject(MethodClass.class)).getField();
// or
((MethodClass) getObjects(MethodClass.class).get(0)).setValue(fieldValue);
If the field is in an instance of a World object and you need to set it from an actor class:
1
((MethodClass) getWorld()).setValue(fieldValue);
allekalle allekalle

2013/4/25

#
Thanks for the help, danpost! I'm sorry for the slow response, but I'm doing this on my free time (and when my family is sleeping, like). The methods "getOneIntersectingObject" and "getObjects" interest me. (As I understand it, we need methods like them to get a definition of the "methodObj" in the example above). These methods must use some interesting way of finding the objects. Can't we use the same way to get a more "direct" access? Thanks! Karl
danpost danpost

2013/4/25

#
What do you mean by 'more "direct" access? What do you want to accomplish?
There are more replies on the next page.
1
2