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

2016/10/31

How to create composite Actors

MrBradley MrBradley

2016/10/31

#
I'm looking to build a container to hold multiple Actors. Has this been done before? An example would be to have an adventure hero with a health bar. Danpost - I fixed an error in your XWorld class - how do I get it to you?
danpost danpost

2016/10/31

#
MrBradley wrote...
I'm looking to build a container to hold multiple Actors. Has this been done before? An example would be to have an adventure hero with a health bar.
There are several ways to link a health bar to a character. The character can hold the health bar object in a field; or, you could make the health bar class an inner class of the character class (for two ways). For the second way, the health bar object can only be used for objects of that particular character class; but, the bar is more tightly linked to that character because the character is what must then create that bar object for itself.
Danpost - I fixed an error in your XWorld class - how do I get it to you?
You can just tell me what you changed here.
MrBradley MrBradley

2016/10/31

#
First, the XWorld errors: I believe the errors were introduced with some changes in Generics support in JDK and Greenfoot. Methods: getObjects( class ) and getObjectsAt( x, y, class ), when class is sent as a null argument ( as in methods getInstances(), getInstancesAt() and removeAllInstancesExcept() ) you will get the following compile time error: incompatible types: java.util.List<java.lang.Object> cannot be converted to java.util.List<greenfoot.Actor>. To correct this you must cast the null argument as follows: (Class<Actor>) null Example:
1
2
3
4
5
6
7
8
public List<Actor> getInstances(Class... classes)
    {
        if (classes.length == 0) return (List<Actor>) getObjects( null );  // error
        if (classes.length == 0) return (List<Actor>) getObjects( (Class<Actor>) null );   / corrected
        List<Actor> actors = new ArrayList<Actor>();
        for (int i=0; i<classes.length; i++) actors.addAll(getObjects(classes[i]));
        return actors;
    }
I hope this is clear and helpful. Thanks for all your examples and efforts supporting the Greenfoot community.
danpost danpost

2016/10/31

#
Thank you for the heads-up on the issues in my XWorld class due to the addition of generics in java. I will review, correct and update all scenarios using it. Thanks again.
MrBradley MrBradley

2016/10/31

#
Second, the Container Actor: We can implement various solutions for this, and I agree with your suggestions. But I'm more interested in a general solution to the problem that would avoid potential pitfalls that students might fall into. Abstractly I am thinking about a Swing Pane version of a Actor where visible components can be combined and manipulated as a single unit. Concretely the health bar would be offset from the adventure Actor; would be displayed and act when and where the adventurer is, as well as removed from the World at the same time the adventurer is. If there existed a Container Actor to allow for such composition, the basics of the implementation would already be in place. If not one would have to be designed well enough to allow students to use it easily and effectively while keeping them away from many of the pitfalls that could arise if they attempted it on their own. Currently, if one Actor object is embedded in another only the containing Actor can be placed in the World at design time. I haven't looked into all the updating and painting issues as well. I would be open to collaborating on a solution if you were interested.
danpost danpost

2016/10/31

#
I was thinking that if you had your character class, which I will call Player, and a generic Bar class that extends Actor, you could have this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import greenfoot.*;
 
public class Player extends Actor
{
    private Healthbar hb = new Healthbar();
     
    protected void addedToWorld(World world)
    {
        world.addObject(hb, 0, 0);
        hb.act();
    }
 
    private class Healthbar extends Bar
    {
        pubic Healthbar()
        {
            super(< parameters >); // add parameters to create a Bar object for player
        }
         
        public void act()
        {
            if (Player.this.getWorld() == null) getWorld().removeObject(this);
            else setLocation(Player.this.getX(), Player.this.getY()-30); // adjust position as needed
        }
    }
}
With this, the world only needs to create and add a Player object into the world and the Bar will automatically be added also; and the bar for that player will automatically remove itself when the player is removed from the world. The bar will also stay with the player as it move around the world.
MrBradley MrBradley

2016/10/31

#
Dan, I'm just on my way to class. Quick question: Do you know if an Actor's act() method gets called if it is not added to the World? If not, the Player's act() method must also call the Healthbar's act(). Now the question is: what else isn't getting done if the Healthbar is not added to the World?
danpost danpost

2016/10/31

#
MrBradley wrote...
o you know if an Actor's act() method gets called if it is not added to the World?
It does not get called by greenfoot during a normal act cycle unless it is not only in a world, but in the currently active world.
If not, the Player's act() method must also call the Healthbar's act().
Greenfoot will call the act method of the Healthbar object because it is in the active world. That it belongs to a Player object has nothing to do with the calling of its 'act'. I had the 'act' method of the Healthbar object execute when it was added to the world to properly position it (I could have just copied line 23 omitting 'else' for line 10). I hope I answered your question to your satisfaction.
danpost danpost

2016/10/31

#
MrBradley wrote...
Now the question is: what else isn't getting done if the Healthbar is not added to the World?
I am not sure what you mean. Please elaborate. "if the Healthbar is not added to the World"? With the code above, if a Player is added to the world, a Healthbar is also added for that player.
danpost danpost

2016/10/31

#
Apparently, the generics issue is of no consequence. At least one argument for classes must be supplied; so, 'classes.length' can never be zero. The line (my line 3, or your line 4, above) can simply be removed. To get all actors in the world, 'Actor.class' can be supplied as the one argument. I should probably go ahead and make note of that in the description of those methods; as well as the fact that some actors may be duplicated within the returned list if any Actor type subclass or superclass of a previously supplied class is given as an argument. Either that, or check the contents of the list for each actor before adding it.
MrBradley MrBradley

2016/11/1

#
Re: XWorld: You are correct about not needing the first line in the getInstances...() methods, but you may need to update the removeAllInstancesExcept() method. (Sorry I don't have the code in front of me). Re: Actor composition: Your example code works well enough. It's a bit more complicated syntactically than I wanted, but it will work as advertised. Thanks. If you ever decide to revisit the approach let me know.
Nosson1459 Nosson1459

2016/11/1

#
MrBradley wrote...
I'm looking to build a container to hold multiple Actors. Has this been done before? An example would be to have an adventure hero with a health bar.
u cud make it part of the heroes picture and a field in the hero will change the picture based on how healthy he is, so for example every 4 hits knocks down 1 of 6 bars changing the pic to only show 5 bars left, and so on
You need to login to post a reply.