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

2013/9/21

Add object to the world

oldmonk7 oldmonk7

2013/9/21

#
What is the best way in general to add objects to the world on the fly? this getWorld() method only on the objects that are currently in the world and if we dont want to add an object to the world but need to access the method of its class then it throws a null pointer exception. And if we add the object to the world to access getWorld() then we would need to add extra object, which I dont want to do. is there any alternative to get the world and add an object?
danpost danpost

2013/9/21

#
Really, the only issue is the with the object not placed in the world, there is no reference to the world unless you pass the world object or any actor object that is in that world to the method in question. Then you would not use 'getWorld()' but the reference given. For example, let us say you had a Timer class and create a timer object that you do not place in the world (in fact, if you never add any Timer objects into the world, you should probably drop the 'extends Actor' part of the class declaration statement). Now, you want that timer object you created to, let us say, call a method in your world class that ends the game playing time and shows a final score screen. Because the timer is not added to the world, it needs to be 'given' the world object. Let us say your world class is called 'PlayWorld' that the method is in. You would add an instance field to the Timer class to hold a PlayWorld object and add an argument to the Timer constructor to pass the PlayWorld object to it. The Timer class would look something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Timer
{
    private PlayWorld playWorld;
    private int timeLeft;
 
    public Timer(PlayWorld pw, int playTime)
    {
        playWorld = pw;
        timeLeft = playTime;
    }
 
    public void runTimer()
    {
        timeLeft--;
        if (timeLeft == 0) playWorld.endPlayTime();
    }
}
In your PlayWorld class code, you would do the following:
1
2
3
4
5
6
7
// add this instance field
private Timer playTimer;
// in PlayWorld constructor
playTimer = new Timer(this, 3000); // passing this world object with about a minute playtime
// in PlayWorld act method
playTimer.runTimer();
// then add the 'endPlayTime' method
danpost danpost

2013/9/21

#
A simpler approach is not to have a Timer class at all, but to set it up and process it in the world class code as follows:
1
2
3
4
5
6
7
8
9
10
11
12
// add these instance fields
int playTimer = 3000;
boolean playComplete;
// in act method
if (!playComplete && playTimeExpired()) endPlayTime();
// add method 'endPlayTime' (sets 'playComplete' to 'true')
// add the following method
private boolean playTimeExpired()
{
    playTimer--
    return playTimer == 0;
}
danpost danpost

2013/9/21

#
It would be best to show what code you are trying to get working. Then we can fix it right up.
oldmonk7 oldmonk7

2013/9/21

#
Hi Danpost I am getting this error even when I try to compile.
1
2
3
4
5
6
java.lang.IllegalStateException: Actor not in world. An attempt was made to use the actor's location while it is not in the world. Either it has not yet been inserted, or it has been removed.
    at greenfoot.Actor.failIfNotInWorld(Actor.java:663)
    at greenfoot.Actor.getOneIntersectingObject(Actor.java:912)
    at GumballMachine.<init>(GumballMachine.java:26)
    at GumballWorld.prepare(GumballWorld.java:30)
    at GumballWorld.<init>(GumballWorld.java:20)
GumballMachine
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
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class GumballMachine here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class GumballMachine extends Actor
{
 
    public GumballMachine()
    {
        GreenfootImage image = getImage() ;
        image.scale( 350, 400 ) ;
    }
 
    public void act()
    {
        checkCoinNear();
        if(Greenfoot.mouseClicked(this))
        {
            notifyInspector();
        }   
    }
     Actor coin = getOneIntersectingObject(Coin.class);
     Actor havecoin = new Message("Have Coin");
    public void checkCoinNear()
    {
        
        if (coin != null)
        {
             
            getWorld().removeObject(coin);
             
            getWorld().addObject(havecoin, 300, 300);
            Greenfoot.delay(50);
 
            
            Inspector coinstatus=new Inspector();
            coinstatus.gotCoin(true);
             
 
        }
    }
       public void notifyInspector()
       {
         
        getWorld().removeObject(havecoin);  
        Inspector ins=new Inspector();
        ins.inspectCoin((Coin)coin);
         
        }
    }
Inspector
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class Inspector here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class Inspector extends Alien
{
    /**
     * Act - do whatever the Inspector wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    private static boolean coinInside=false;
    //private static boolean isCrankTurned=false;
    public void act()
    {
        // Add your action code here.
        //pickAlien();
    }   
    /*void turnCrank()
    {
    isCrankTurned=true;
    }*/
     
    public void gotCoin(boolean status)
    {
     coinInside=status;
    }
    
     
     public void inspectCoin(Coin coin)
    {
        
        Inspector ins = new Inspector();
             
         
        if(coin.getClass().getName()=="Quarter")
        {
            Gumball gb = new Gumball();
            gb= ins.pickAlien();
            getWorld().addObject(gb,366, 392);
        }
        if(coin.getClass().getName()=="Penny")
        {
            Actor havecoin = new Message("Its a penny");
            getWorld().addObject(havecoin, 300, 300);
            Greenfoot.delay(40);
            getWorld().removeObject(havecoin);
 
        }
        if(coin.getClass().getName()=="FakeQuarter")
        {
            Actor havecoin = new Message("It is fake");
            getWorld().addObject(havecoin, 300, 300);
            Greenfoot.delay(40);
            getWorld().removeObject(havecoin);
             
        }
    }
     
     
    public Gumball pickAlien() 
    
        Gumball GB=new Gumball(); 
        int choice=Greenfoot.getRandomNumber(2); 
        if (choice == 0
        
            RandomPicker RP =new RandomPicker(); 
            GB = RP.pickRandom();
            return GB;
        
        else 
        
            GreenPicker GP =new GreenPicker(); 
            GB=GP.pickGreen();
            return GB;
        
         
         
    
 
}
danpost danpost

2013/9/21

#
Look at line 4 in your error message (it is the first line that does not start with 'greenfoot' and starts with the name of a class you created. The number at the end of that line is the line number that the error occurred in that method (line 26). Lines 26 and 27 are out of place (I believe they should be inside the following method block).
oldmonk7 oldmonk7

2013/9/21

#
if i put line 26 and 27 inside the method then my notifyInspector would not be able to access it, but I want to access the same coin object. please help!
oldmonk7 oldmonk7

2013/9/21

#
Also does the world.removeObject deallocates the object or it just removes it from the myworld??
danpost danpost

2013/9/21

#
oldmonk7 wrote...
Also does the world.removeObject deallocates the object or it just removes it from the myworld??
I oftentimes use the following:
1
2
3
4
5
6
7
8
9
// in an actor class
int x = getX(), y = getY(), w = getWorld();
w.removeObject(this);
w.addObject(this, x, y);
// or in a world class
Actor actor = [assigned some actor];
int x = actor.getX(), y = actor.getY();
removeObject(actor);
addObject(actor, x, y);
The reason I oftentimes use that code is to bring the actor on top of other actors. I works will as of now, but it is not something that is documented and should be relied on (future updates to the APIs could change that). In short, as long as you have a valid reference to the object (whether added to the world or not), it will not be de-allocated.
oldmonk7 wrote...
if i put line 26 and 27 inside the method then my notifyInspector would not be able to access it, but I want to access the same coin object. please help!
Actually, line 27 is not a problem; it is line 26 that is the issue here. You could just declare the field outside the method, but assign the values inside the method, As a sidenote: I believe that you are refactoring the code too much. A lot of code could be eliminated by grouping a few related actions together. First, it appears that the machine has only two possible things to do: wait for a coin and wait for a click (which should be on the text object or anywhere in general; but, not just on the gumball machine). My coding would be something like this (no Inspector class -- methods needed from there in the GumballMachine class):
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
// instance fields in GumballMachine
Coin coin = null;
Message haveCoin = new Message("Have Coin");
// gumball machine act
public void act()
{
    if (coin == null) checkForCoin();
    else if (haveCoin.getWorld() == null) inspectCoin();
}
// methods called by act
public void checkForCoin()
{
    coin = getOneIntersectingObject(Coin.class);
    if (coin != null)
    {
        getWorld().removeObject(coin);
        getWorld().addObject(haveCoin, 300, 300);
        Greenfoot.delay(50);
    }
}
 
public void inspectCoin()
{
    if (coin instanceof Quarter) pickAlien();
    else if (coin instanceof Penny) pennyFound();
    else if (coin instanceof FakeQuarter) fakeFound();
    coin = null;
}
// etc.
// Message class act should have this
if (Greenfoot.mouseClicked(this)) getWorld().removeObject(this);
You need to login to post a reply.