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

2018/3/6

Trouble making actor appear and disappear dynamically

Justins9269 Justins9269

2018/3/6

#
Hey y'all. I am having a lot of trouble making an actor appear only when my main actor is touching an interactable object. I will leave u the code I think is relevant here together with the try I have made in order to make this work. Some help would be greatly appreciated. This code right here is inside my main actor class, "Lucas":
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void touching_interactable_object()
    {
        Actor z = new Interact_Button();
        spawn_Interact_Button(z);
        if (isTouching(interactable_objects.class))
        {
             
            z.getImage().setTransparency(100);
        }
        else
        {
            z.getImage().setTransparency(0);
        }
     
    }
This code is for spawning the Actor at the bottom left of the screen:
1
2
3
4
public void spawn_Interact_Button(Actor z)
   {
       getWorld().addObject(z, 30, 450);
   }
Super_Hippo Super_Hippo

2018/3/6

#
What you are doing: Whenever the touching_interactable_object method is executed, you add a new Interact_Button into the world which is transparent or not. If this happens every act cycle, you will add a lot of those buttons in the world... What you probably want to do: Add one single Interact_Button to your world at the beginning which starts invisible. Whenever Lucas touches an interactable_objects object, you make this Interact_Button visible (not creating a new one). How to do that: Create the Interact_Button when your world is created. Save a reference to it and add it to the world. When Lucas touches an interactable_objects object, call a method on your world which uses the reference to change the transparency of the Interact_Button object's image.
CubeGamer6 CubeGamer6

2018/3/6

#
You are getting the image of the z object, changing it, but never actually setting it again. You need to first get the image, then set the transparency, then set the image to the new one The rest of the code is fine btw
Justins9269 Justins9269

2018/3/6

#
CubeGamer6 wrote...
You are getting the image of the z object, changing it, but never actually setting it again. You need to first get the image, then set the transparency, then set the image to the new one The rest of the code is fine btw
Thanks for the answer! I tried doing it this way, but still no results:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void touching_interactable_object()
    {
        Actor z = new Interact_Button();
        spawn_Interact_Button(z);
        GreenfootImage image = z.getImage();
        if (isTouching(interactable_objects.class))
        {
          image.setTransparency(100);
          z.setImage(image);
        }
        else
        {
          image.setTransparency(0);
          z.setImage(image);
        }
      
    }
Super_Hippo wrote...
What you are doing: Whenever the touching_interactable_object method is executed, you add a new Interact_Button into the world which is transparent or not. If this happens every act cycle, you will add a lot of those buttons in the world... What you probably want to do: Add one single Interact_Button to your world at the beginning which starts invisible. Whenever Lucas touches an interactable_objects object, you make this Interact_Button visible (not creating a new one). How to do that: Create the Interact_Button when your world is created. Save a reference to it and add it to the world. When Lucas touches an interactable_objects object, call a method on your world which uses the reference to change the transparency of the Interact_Button object's image.
Might be a bit of a stupid question but I'm not quite sure how to do the referencing of the object between the world and the Lucas class :(
danpost danpost

2018/3/6

#
Justins9269 wrote...
I'm not quite sure how to do the referencing of the object between the world and the Lucas class
Actually, it is not really necessary to reference it. But still, you should not create and add an Interact_Button every single act cycle. Your project will start lagging after just a few seconds. Also, interaction between a newly added actor and another may not even be established as collision is computed between act cycles. Like Hippo suggested, add one Interact_Button into the world from your world constructor (or prepare method). As far as having the transparency of the actor change, it may be easier to have the object itself do that instead of Lucas. All it would take is the following line in the act method of the 'interactable_objects' class (or 'Interact_Button' class):
1
setTransparency(isTouching(Lucas.class) ? 100 : 0);
Justins9269 Justins9269

2018/3/6

#
danpost wrote...
Justins9269 wrote...
I'm not quite sure how to do the referencing of the object between the world and the Lucas class
Actually, it is not really necessary to reference it. But still, you should not create and add an Interact_Button every single act cycle. Your project will start lagging after just a few seconds. Also, interaction between a newly added actor and another may not even be established as collision is computed between act cycles. Like Hippo suggested, add one Interact_Button into the world from your world constructor (or prepare method). As far as having the transparency of the actor change, it may be easier to have the object itself do that instead of Lucas. All it would take is the following line in the act method of the 'interactable_objects' class (or 'Interact_Button' class):
1
setTransparency(isTouching(Lucas.class) ? 100 : 0);
I'm trying to make an actor(Interact Button) only appear when my main actor(Lucas) is touching an actor that he can interact with(interactable_objects).
Super_Hippo wrote...
What you are doing: Whenever the touching_interactable_object method is executed, you add a new Interact_Button into the world which is transparent or not. If this happens every act cycle, you will add a lot of those buttons in the world... What you probably want to do: Add one single Interact_Button to your world at the beginning which starts invisible. Whenever Lucas touches an interactable_objects object, you make this Interact_Button visible (not creating a new one). How to do that: Create the Interact_Button when your world is created. Save a reference to it and add it to the world. When Lucas touches an interactable_objects object, call a method on your world which uses the reference to change the transparency of the Interact_Button object's image.
I tried doing what you said, but I am not sure I have implemented it correctly. Some guidance would be of much help! This is the code for the World:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class Forest_1 here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class Forest_1 extends World
{
 
    /**
     * Constructor for objects of class Forest_1.
     *
     */
    public Forest_1()
    {   
        // Create a new world with 600x400 cells with a cell size of 1x1 pixels.
        super(640, 480, 1);
        prepare();
    }
    Interact_Button interact_button = new Interact_Button();
    Lucas lucas = new Lucas();
    private void prepare()
    {
        Lucas_tree_house lucas_tree_house = new Lucas_tree_house();
        addObject(lucas_tree_house,304,130);
        lucas_tree_house.setLocation(298,123);
        lucas_tree_house.setLocation(301,120);
        lucas_tree_house.setLocation(317,123);
        Forest_tree_1 forest_tree_1 = new Forest_tree_1();
        addObject(forest_tree_1,599,188);
        Forest_tree_1 forest_tree_12 = new Forest_tree_1();
        addObject(forest_tree_12,56,61);
        Forest_tree_1 forest_tree_13 = new Forest_tree_1();
        addObject(forest_tree_13,607,65);
        Forest_Rock_1 forest_rock_1 = new Forest_Rock_1();
        addObject(forest_rock_1,601,425);
        Forest_Rock_1 forest_rock_12 = new Forest_Rock_1();
        addObject(forest_rock_12,141,230);
        Forest_Rock_1 forest_rock_13 = new Forest_Rock_1();
        addObject(forest_rock_13,475,128);
        Forest_tree_1 forest_tree_14 = new Forest_tree_1();
        addObject(forest_tree_14,180,348);
        addObject(lucas,326,237);
        lucas.setLocation(320,231);
        lucas.setLocation(314,296);
        addObject(interact_button,46,436);
    }
     
    public Interact_Button getIB()
    {
        return interact_button;
    }
     
    public Lucas getLucas()
    {
        return lucas;
    }
}
Inside interactable_objects
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
27
28
29
30
31
32
33
34
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class interactable_objects here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class interactable_objects extends solid_object
{
    /**
     * Act - do whatever the interactable_objects wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    Interact_Button IB = ((Forest_1)getWorld()).getIB();
    Lucas lucas = ((Forest_1)getWorld()).getLucas();
     
    public void act()
    {
        if(isTouching(Lucas.class))
        {
        GreenfootImage IB_image = IB.getImage();
        IB_image.setTransparency(0);
        IB.setImage(IB_image);
    }
        else
        {
            GreenfootImage IB_image = IB.getImage();
        IB_image.setTransparency(100);
        IB.setImage(IB_image);
        }
         
    }   
}
I am getting 3 null pointer exceptions, not sure why :(
CubeGamer6 CubeGamer6

2018/3/6

#
The nullpointers are caused by the fact that the world is null when the class is trying to get it. in the act() of interactable_objects, put
1
2
3
4
5
if(getWorld() != null && getWorld().getClass() == Forest_1.class && IB == null && lucas == null) {
    Forest_1 w = (Forest_1).getWorld();
    IB = w.getIB();
    lucas = w.getLucas();
}
and replace lines15 and 16 with
1
2
Interact_Button IB = null;
Lucas lucas = null;
danpost danpost

2018/3/6

#
In the interactable_objects class, the fields declared on lines 15 and 16 are created and assigned their initial values at the time an interactable_objects object is created. This would be before it has a chance to be added into any world. Hence, 'getWorld()' returns a 'null' value and that is what 'lucas' and 'IB' are initially set to. This will then cause lines 22 and 28 to throw a 'NullPointerException' error. You do not need to get these references until you need them -- which you really do not at all. You can simply have this:
1
2
3
4
5
6
7
8
9
import greenfoot.*;
 
public class interactable_objects extends solid_object
{
    public void act()
    {
        getImage().setTransparency(isTouching(Lucas.class) ? 100 : 0);
    }
}
Any interactable_objects object that touches lucas will show itself -- and hide when not touching lucas.
Super_Hippo Super_Hippo

2018/3/6

#
danpost, yes that works if the Interact_Button is a subclass of interactable_objects. I thought it would not. So A is touching B and C's image should change. But I am not really sure anymore...
danpost danpost

2018/3/6

#
Super_Hippo wrote...
So A is touching B and C's image should change. But I am not really sure anymore...
One of the two, A or B, actually is C (which ever is the one created by the subclass).
Justins9269 Justins9269

2018/3/6

#
danpost wrote...
Super_Hippo wrote...
So A is touching B and C's image should change. But I am not really sure anymore...
One of the two, A or B, actually is C (which ever is the one created by the subclass).
Actually, the interact Button is a separate Actor, that does not inherit from anywhere. It is simply a picture that should be shown at the bottom left of the screen whenever Lucas is close to something he can interact with. As an example, Lucas walks and is close to a door, and the game creates this small thing on the bottom left side to tell the player that he can press a key to interact with the respective door.
danpost danpost

2018/3/6

#
Justins9269 wrote...
Actually, the interact Button is a separate Actor, that does not inherit from anywhere. It is simply a picture that should be shown at the bottom left of the screen whenever Lucas is close to something he can interact with.
Ahh, more info -- good. Might get somewhere now. It is not so straight-forward as to how to program this particular behavior. Maybe through the Lucas class is best since it is the common entity in the interactions. The button, however, should be a world thing -- and it looks like it already is there ... with a getter method. So far, so good. Now for the Lucas class. The following should be sufficient for the method:
1
2
3
4
5
6
public void touching_interactable_object()
{
    Forest_1 forest = (Forest_1)getWorld();
    if (isTouching(interactable_objects.class)) forest.getIB().getImage().setTransparency(100);
    else forest.getIB().getImage()setTransparency(0);
}
The interactable_objects class can be emptied:
1
public class interactable_objects extends solid_object {}
Justins9269 Justins9269

2018/3/7

#
danpost wrote...
Justins9269 wrote...
Actually, the interact Button is a separate Actor, that does not inherit from anywhere. It is simply a picture that should be shown at the bottom left of the screen whenever Lucas is close to something he can interact with.
Ahh, more info -- good. Might get somewhere now. It is not so straight-forward as to how to program this particular behavior. Maybe through the Lucas class is best since it is the common entity in the interactions. The button, however, should be a world thing -- and it looks like it already is there ... with a getter method. So far, so good. Now for the Lucas class. The following should be sufficient for the method:
1
2
3
4
5
6
public void touching_interactable_object()
{
    Forest_1 forest = (Forest_1)getWorld();
    if (isTouching(interactable_objects.class)) forest.getIB().getImage().setTransparency(100);
    else forest.getIB().getImage()setTransparency(0);
}
The interactable_objects class can be emptied:
1
public class interactable_objects extends solid_object {}
Finally getting there!! Seems to work fine for this specific world, finally. But it feels a little bit hardcoded. Considering I would want this to work for say, about 20 worlds, it is going to be a pain to do this for all... Not sure if there could be any way to do that. Anyway, thank you very much for your very helpful answers!
danpost danpost

2018/3/7

#
You could make all your worlds extend a single subclass of World and put the method there so Lucas can find it easily from any world.
You need to login to post a reply.