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

2018/8/26

Problem to access variable from world

R4ylot R4ylot

2018/8/26

#
I am currently working on a game where I want to have a timer for the remaining time. The actual variable for the timer is in the world "MyWorld", so the timer should only display the remaining time. When I compiled my game there was no error, but when I tried to start it I've got the following error: java.lang.NullPointerException at Timer.<init>(Timer.java:14) at Level0.prepare(Level0.java:38) at Level0.<init>(Level0.java:20) This is the code of MyWorld:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
/**
 * Write a description of class MyWorld here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class MyWorld extends World
{
    long time = 50;
    long absoluteTime = 160;
    GreenfootSound music = new GreenfootSound("571236_Load.mp3");
    /**
     * Constructor for objects of class MyWorld.
     * 
     */
    public MyWorld(Player player, int xPos, int yPos)
    {    
        super(896, 448, 1); 
        this.addObject(player,xPos,yPos);
        Greenfoot.setSpeed(62);
        if (time <= 0) {
            music.stop();
        }
    }
    
    public void act()
    {
        time--;
        Greenfoot.delay(380);
    }

    public void started()
    {
        music.play(); 
    }
    
    public void stopped()
    {
        music.pause();
    }
    
    public long getTime()
    {
        return time;
    }
}
And this of the Actor Timer:
import greenfoot.*;
import java.awt.Color;
import java.util.List;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Timer here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Timer extends Actor
{
    MyWorld myworld = (MyWorld) getWorld();
    long timer = myworld.time;
    public Timer() 
    {
        GreenfootImage img = new GreenfootImage("Time remaining: " +timer, 35, Color.white, new Color(0, 0, 0, 0));
        setImage(img);
    }

    /**
     * Act - do whatever the Timer wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        // Add your action code here.
        GreenfootImage img = new GreenfootImage("Time remaining: " +timer, 35, Color.white, new Color(0, 0, 0, 0));
        setImage(img);
    }    
}
Can anybody help me, please?
Super_Hippo Super_Hippo

2018/8/26

#
Code outside of methods and the code in the constructor of the Timer class are executed when the Timer isn't in any world. So 'getWorld' returns null and you can't call methods on 'null'. Second thing is that your 'timer' variable is not a copy of the 'time' variable, it only copies its value once and will never change.
private long timer;

protected void addedToWorld(World w)
{
    updateImage();
}

public void updateImage()
{
    setImage(new GreenfootImage("Time remaining: " + ((MyWorld) getWorld()).getTime(), 35, Color.WHITE, new Color(0, 0, 0, 0));
}
Using 'Greenfoot.delay' pauses the whole scenario, I am not sure if that is what you want.
R4ylot R4ylot

2018/8/26

#
Okay, thanks for your help, the error is now gone. However, the timer is now stuck at 50. Also, because you mentioned that Greenfoot.delay would pause the scenario: I've discovered this problem earlier and because of that, I decided to put the code for the timer in MyWorld. It won't pause the game there because the worlds where all the actors are in extend of MyWorld. But is there any way to create a timer without Greenfoot.delay?
Super_Hippo Super_Hippo

2018/8/26

#
It stucks at 50 because the 'updateImage' method isn't called from any act method yet. So whenever the value changed, call that method. Yes, simply remove the 'delay'. You can use higher values and don't change the displayed value all the time. For example:
private final int APS = 60;
private int time = 50*APS;

public void act()
{
    if (--time%APS==0) timer.updateImage(); //if timer is the reference to the Timer object in your world
}

public int getTime()
{
    return time/APS;
}
R4ylot R4ylot

2018/8/26

#
Now it doesn't recognize the method updateImage from the timer
Super_Hippo Super_Hippo

2018/8/26

#
Show what you tried.
R4ylot R4ylot

2018/8/26

#
So, at first, I moved the code for the timer in the player class because now it's easier to change time if the player makes a mistake or reaches the goal. These are only the parts of the code that have to do with the time, so it's clearer
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
/**
 * Write a description of class Player here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Player extends Actor
{
public final int APS = 60;
    public int time = 50*APS;
    int absoluteTime = 160*APS;
    Actor timer = getWorld().getObjects(Timer.class).get(0);
/**
     * Act - do whatever the Player wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
time--;
        absoluteTime--;
        if (--time%APS==0) {
            timer.updateImage();
        }//Here's the error
    }
public int getTime()
    {
        return time/APS;
    }
}
I've also tried to move the if-part in line 22 in the timer class, but then it didn't recognized the variables "time" and "APS".
Super_Hippo Super_Hippo

2018/8/26

#
Again, don't use 'getWorld' outside methods. This can't work. You could add the Timer from the Player class.
protected void addedToWorld(World w)
{
    timer = new Timer();
    w.addObject(timer, 100, 100);
}
You probably won't need the 'getTime' method like this. You could pass the time to the Timer object directly:
timer.updateImage(time/APS);
public void updateImage(int time)
{
    setImage(new GreenfootImage("Time remaining: " + time, 35, Color.WHITE, new Color(0, 0, 0, 0));
}
R4ylot R4ylot

2018/8/26

#
Ok, I made the Timer now a subclass of Player. But when I try to add "timer.updateImage(time/APS);" to the player act, it says "cannot find symbol - variable timer"
Super_Hippo Super_Hippo

2018/8/26

#
A Timer is not a Player, so the Timer class shouldn't be a subclass of the Player class.
danpost danpost

2018/8/26

#
As a game timer, the timer variable should be in your world class. The variable can be either of Timer type (with an int field in the Timer class) or of int type (using the showText method or having also an Actor field for the generic actor that displays the remaining time). Please refer to my Value Display Tutorial for details.
R4ylot R4ylot

2018/8/27

#
I tried now different solutions and I think I solved my problem now. Thank you for helping.
You need to login to post a reply.