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

2014/1/12

How to to change a boolean of an actor from the world?

Super_Hippo Super_Hippo

2014/1/12

#
Hello, it is me again, I am having trouble with changing a boolean of an actor from the world in which the actor was added. For example, I set the world 'Level1.class'. This world adds the objects in the world.
1
2
3
4
5
6
Elefant ele1 = new Elefant( getEle1a(), getEle1b() );
addObject(ele1, getEle1x(), getEle1y() );
Elefant ele2 = new Elefant( getEle2a(), getEle2b() );
addObject(ele2, getEle2x(), getEle2y() );
Elefant ele3 = new Elefant( getEle3a(), getEle3b() );
addObject(ele3, getEle3x(), getEle3y() );
It also has the boolean 'started':
1
public static boolean started = false;
Now I want to have a method to change the boolean 'started' of the actors. This 'started' is not the same as the one in the world class. This is in the constructor of the class 'KI', which is the superclass of Elefant. Actually it is the superclass of the superclass, but I do not think that this matters.
1
public boolean started = false;
I want to change the boolean 'started' of the actors to true, when the boolean 'started' in the world class was set to true. My first try was like this:
1
2
3
4
5
6
7
8
9
public void act()
{
    if (started)
    {
        ele1.started = true;
        ele2.started = true;
        ele3.started = true;
    }
}
But if I try to compile, it says "cannot find symbol - variable ele1". I thought that ele1 was defined earlier when I created the object ele1 from the class Elefant and would now refer to this object. But this is apparently not the case. This was my second try:
1
2
3
4
5
6
7
8
9
10
public void act()
{
    if (started)
    {
        for (int i = 0; i<gegner-1; i++) //'gegner' is an int. It is the number of enemies which are added in this level.
        {
            getObjects(KI.class).get(i).started = true;
        }
    }
}
But now, I get the error 'cannot find symbol - variable started'. What am I doing wrong? The variable 'started' is public in the KI.class as I said. What is the reason why the compiler is not able to find it? How can I change the boolean of the actors from the world class? By the way, I did the second way exacty the same with only taking the subclass Eelefant instead of the superclass KI and using the number of them instead of 'gegner'. Of course I put the variable from the KI constructor to Elefant, too. I wanted to see, if that caused the problem, but I did not.
Gevater_Tod4711 Gevater_Tod4711

2014/1/12

#
Your first try didn't work because the variables ele1, ele2, ... were just used in the method that added the objects to the world. Because it says: 'Elefant ele1 = ...' the variables ele1, ... are not known outside this method. To make the variables visible in the whole class you need to declare them global:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class YourWorld extends World {
    //here you add the global variablese:
    private Elefant ele1;
    private Elefant ele2;
    //...
 
    //now you change the method to add them to the world like this:
    public void addThemToTheWorld() {
        ele1 = new Elefant( getEle1a(), getEle1b() ); 
        addObject(ele1, getEle1x(), getEle1y() ); 
        ele2 = new Elefant( getEle2a(), getEle2b() ); 
        addObject(ele2, getEle2x(), getEle2y() ); 
        ele3 = new Elefant( getEle3a(), getEle3b() ); 
        addObject(ele3, getEle3x(), getEle3y() ); 
    }
}
I think your second try didn't work because the objects of your list were known as actors and not as KI or Elefant. Unfortunately the Greenfoot API only says that the method returns a java.util.List and not the type of the generic parameter so I'm not quite shure if this is the problem. But I think the method getObjects returns a list of actors and in the class Actor the field started is not known. So you need to cast the objects you get from the list to KI or to Elefant to change the value of the variable started:
1
2
3
4
5
6
7
8
public void act() { 
    if (started) { 
        List<KI> objects = getObjects(KI.class);
        for (int i = 0; i < objects.size(); i++) { 
            ((KI) objects.get(i)).started = true;
        
    
}
Another way for doing this would be to use the variable started from the world class in your actor classes. Because it's declared public static you could easily check the value of this field like this:
1
2
3
4
//in your actor class (or any other class):
if (YourWorldsName.started) {
    //the variable started in the world is true;
}
Super_Hippo Super_Hippo

2014/1/12

#
Both ways are working perfectly! I will stick with the second one, because I can just add that to a new level without much work. Thank you very much! What you did at the end was also my first idea, but the problem is, that I would need to get the boolean 'started' of the world in which the actor is in and for that I would need another switch which I have to modify for every new level. There are already enough of them. Well, probably there is enough way again, but I already have a solution now. :) Okay, I think I found another way. I could save the boolean in one world and when I start a new level, this boolean will be set to false again. Then the KI can check whether this boolean is true or false. That would be even easier. Maybe it will work.
danpost danpost

2014/1/12

#
You could superclass your Level1, Level2, etc. with a Level world and put the static field there as well as level changing methods, initial world construction code, etc.
Super_Hippo Super_Hippo

2014/1/12

#
I tried having worlds as superclasses a quite long time ago, but it seems like I was not able to do that. I could create the walls from there, the other things are different in each level. Probably it is possible somehow (with lists and so on) that I just have to place the amount of the enemies in the level and it does everything else automatically. But I have no idea how. This would be too complicated for me, I think. At the moment, I have to adjust many things for every new level. Mainly because I want the enemies to spawn on a free field and not too close to the player. That is much code for every enemy and the woodblocks.
danpost danpost

2014/1/12

#
I think the main idea is to put Level1 at the same level as all the other levels and have a way to initialize everything before Level1 begins. I have an example of this somewhere. I will search for it and report back when I find it.
danpost danpost

2014/1/12

#
OK, I uploaded a sample of what I was talking about. Download my ControlWorld Demo and see how the ControlWorld class is used with the Level sub-classes
Super_Hippo Super_Hippo

2014/1/12

#
This is really interesting. I think, I finally understood the meaning of 'super' which refers to the superclass instead of just being the form for 'create world'. (Although I don't know how I would refer to the superclass of the superclass without referring to a method of the superclass which itself refers to its superclass. Well, not interesting.) To come back to my scenario, I am not sure how I could make use of your example or how it would simplify my code. Of course, the greatest thing would be, that I only have to type in the amount of different enemies into the constructor of the level and it would do the rest. But for that I would need lists and I have no idea how to use them. Then I would have one complicated world and all other would be very easy. But, as I said, I am probably not skilled enough to do that. What I maybe could do is to put the code of the walls inside this superclass constructor and call it from every level which is created, because the walls are always the same. But that would not remove much code, because this creation is quite simple. The wood is depending on the enemies position, which has to be initialized every time a level starts. And this initialization is a quite large code which I have to adjust for every enemy that is placed. If you would play to level 13, at latest then you would notice how much work this is. (Do not play before the next update. Savings will be deleted due to other scoring.) And after this initialization, I have to check for the wood (which is divided into four parts) that it will not be placed over an actor. (While writing this, I could also place it and remove it if it is over an actor then, this could reduce the code a bit.) The game does not only exist of the levels anymore, it has a menu. It will be a bit more extensive in the next update. Yes, I still update it, although it looks like no one cares about it. The update is almost ready. At the moment, I change the code of every level to shrink my code a bit. And with a bit I mean over 100 lines each. Good, that I only have 13 levels yet. If I can only use it to actually just change the active world, then this does not really help me, I think. The only effort is then, that I have all subclasses separated from the Menu worlds. This would improve the lucidity a bit, but that is probably too much work to change everything again to get this improvement. I don't know if this was only to the first question in this tread. If yes, then you can ignore like everything above. I have the reference in the first world now and everything changes or gets the boolean. It works fine. By the way, you said, that you initialize everything before it starts. In your scenario, every room still initializes for example the portals when the world is created and not in the beginning. As you said it, I thought that every world would be initialized and they would only be set active later. All in all, I could misunderstood you some-/everywhere.
danpost danpost

2014/1/12

#
Super_Hippo wrote...
Although I don't know how I would refer to the superclass of the superclass without referring to a method of the superclass which itself refers to its superclass.
What?!? I think I know what you are trying to say -- why would you want to do that? Please, give an example of what you would be trying to do that you would need to do this.
danpost danpost

2014/1/13

#
'super' just means that it is higher than (in the chain of classes that extends to the lower one. The Object class extends everything. The World and Actor classes extends Object. The world and actor classes you create extend them. Your Elefant class is an extension of the Actor class. All Elefant objects created are therefore also an Actor class object and an Object class object. If your Elefant class extended the Animal class, which in turn extended the Actor class, then it is also an Animal class object. I created the ControlWorld class so that I did not have to do the initial setup (before running the actual levels in one of those level classes. Also, it is a place where you can put methods and state fields that are common to all levels (so you do not have to re-write (or copy/paste) the methods and fields into every level. The levels just inherit those methods and state fields.
Super_Hippo Super_Hippo

2014/1/13

#
danpost wrote...
What?!? I think I know what you are trying to say -- why would you want to do that? Please, give an example of what you would be trying to do that you would need to do this.
I was only thinking, not very serious. That's why I put the next sentence there. If you use super, do you get one level higher in this chain or do you come to the highest one? It is like Object->Actor->KI->Boden->Elefant. So if the elephant uses super, he comes to the Boden.class (every AI which walks on the ground). If it wants to use something from the KI class, he would have to use super-duper...^^ That brings me to the idea to write dozens of initializations into this superclass, so I have a bit less work for a new level.
danpost danpost

2014/1/13

#
In your example: Object>Actor>KI>Boden>Elefant All your methods and state fields (public and protected) in the KI class are inherited by the Elefant class. If you want to use something in the KI class from the Elefant class, you do not have to do anything except...use it. It is Just like you subclassing Animal with Crab and using the Actor class method 'getX'. For classes that require initialization, like the World class, each subclass has a 'super' call as the first line in its constructor. One calls the one in its superclass; it calls the one above it, etc. Until the World class constructor is called, where the foundation of the world is built. You can add 'super' calls to your Elefant class constructor which calls the Boden constructor; and then one in your Boden constructor to call the KI constructor. By not adding a constructor in the Elefant class, your Elefant will begin construction with the first class above it that has a constructor. Hope this clears some things up (and I express myself propely).
Super_Hippo Super_Hippo

2014/1/13

#
Yes, it did and probably that is the reason why I never used super in an Actor class.
danpost danpost

2014/1/13

#
Super_Hippo wrote...
If you use super, do you get one level higher in this chain or do you come to the highest one?
I think I touched on the answer to this in my last post. But to be direct, 'super' calls the constructor of the class that the class extends. 'this' can also be used to call a different constructor within the same class. For example:
1
2
3
4
5
6
7
8
9
public MyWorld()
{
    this(600, 400); // calls the constructor below
}
 
public MyWorld(int wide, int high)
{
    super(wide, high, 1); // calls the constructor of the class this class extends
}
Now, you can use 'new MyWorld()' to create a world whose dimension are defaulted to (600, 400) or you can use 'new MyWorld(int, int)' to create one of any specified size. Either way, the cellsize will be one. In fact, if MyWorld extended the World class, then line 8 would probably be calling a constructor that looked like this:
1
2
3
4
public World(int width, int height, int cellsize)
{
    this(width, height, cellsize, true);
}
which calls a different constructor in the same class, setting the default value of 'true' to the bounded state of the new World object.
You need to login to post a reply.