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

2020/8/13

Executing a static method every frame

RcCookie RcCookie

2020/8/13

#
I have coded a Time class that calculates some useful data like the fps and the duration of the last frame. The problem is that it has to be updated each frame. Of course I can have the time class extend from the Actor class and add it to a world, but I don’t want to do so. In fact, I would like to have everything in the time class be static, and now the only thing that has to be done is to call „Time.update()“ exactly once per frame (not more!). The only way I could imagine that working is if the Time class can extend from an internal greenfoot class and overrides a static method that is already being called once per frame. I just need to know that class if there is one.
danpost danpost

2020/8/13

#
RcCookie wrote...
I have coded a Time class ... it has to be updated each frame.
Where do you create this timer?
RcCookie RcCookie

2020/8/13

#
I’m not sure what you mean. The timer class (at the moment) extends the Actor class, but that is not necessary for it to function. It basically is a independent script
danpost danpost

2020/8/13

#
RcCookie wrote...
I’m not sure what you mean. The timer class (at the moment) extends the Actor class, but that is not necessary for it to function. It basically is a independent script
You should have something like:
Timer timer = new Timer();
What class will you find "new Timer()" and what type of class is it?
RcCookie RcCookie

2020/8/13

#
So this is the timer class:
package packages.tools;

public class Time extends greenfoot.Actor{
    public static final double MAX_DELTA_TIME = 0.08;
    long lastMillis;
    double deltaTime;
    public double timeScale = 1;
    long frameIndex = 0;

    double timeSinceFpsUpdate = 0;
    int frameNum;
    int frameCount;
    int stableFps;
    
    public Time(){
        setImage(new greenfoot.GreenfootImage(1, 1));
    }
    public void act(){
        long currentMillis = System.currentTimeMillis();
        deltaTime = (currentMillis - lastMillis) / 1000.0;
        lastMillis = currentMillis;
        deltaTime %= 1;


        timeSinceFpsUpdate += deltaTime;
        frameNum++;
        frameCount += fps();
        if(timeSinceFpsUpdate >= 1){
            timeSinceFpsUpdate %= 1;
            stableFps = (int)(frameCount / (double)frameNum);
            frameNum = frameCount = 0;
        }
        frameIndex++;
    }
    
    /**
     * Fraction of time since the last frame
     */
    public double deltaTime(){
        if(deltaTime < MAX_DELTA_TIME) return deltaTime * timeScale;
        return MAX_DELTA_TIME * timeScale;
    }

    public void setTimeScale(double scale){
        timeScale = scale;
    }
    
    /**
     * Updated once per frame
     */
    public int fps(){
        if(deltaTime == 0) return 2000;
        return (int)(1 / deltaTime);
    }
    
    /**
     * Updated once per second
     */
    public int stableFps(){
        return stableFps;
    }
    
    public long frameIndex(){
        return frameIndex;
    }
    
    public void resetFrameIndex(){
        frameIndex = 0;
    }
}
At the moment whenever I want to use the time class, I initiate it in that class, for example in a fps display. But what I want is that you don't have to do that, somewhat like this:
package packages.tools;

public class Time extends /*some class that has a static method that is executed once per frame*/{
    public static final double MAX_DELTA_TIME = 0.08;
    static long lastMillis;
    static double deltaTime;
    public static double timeScale = 1;
    static long frameIndex = 0;

    static double timeSinceFpsUpdate = 0;
    static int frameNum;
    static int frameCount;
    static int stableFps;
    
    //not needed
    /*public Time(){
        setImage(new greenfoot.GreenfootImage(1, 1));
    }*/

    @Override // the method in the super class that is executed once per frame
    public static void update(){
        long currentMillis = System.currentTimeMillis();
        deltaTime = (currentMillis - lastMillis) / 1000.0;
        lastMillis = currentMillis;
        deltaTime %= 1;


        timeSinceFpsUpdate += deltaTime;
        frameNum++;
        frameCount += fps();
        if(timeSinceFpsUpdate >= 1){
            timeSinceFpsUpdate %= 1;
            stableFps = (int)(frameCount / (double)frameNum);
            frameNum = frameCount = 0;
        }
        frameIndex++;
    }
    
    /**
     * Fraction of time since the last frame
     */
    public static double deltaTime(){
        if(deltaTime < MAX_DELTA_TIME) return deltaTime * timeScale;
        return MAX_DELTA_TIME * timeScale;
    }

    public static void setTimeScale(double scale){
        timeScale = scale;
    }
    
    /**
     * Updated once per frame
     */
    public static int fps(){
        if(deltaTime == 0) return 2000;
        return (int)(1 / deltaTime);
    }
    
    /**
     * Updated once per second
     */
    public static int stableFps(){
        return stableFps;
    }
    
    public static long frameIndex(){
        return frameIndex;
    }
    
    public static void resetFrameIndex(){
        frameIndex = 0;
    }
}
The update method then had to be called exactly once per frame for the time to work.
danpost danpost

2020/8/13

#
RcCookie wrote...
/*some class that has a static method that is executed once per frame*/
I cannot think of any. With no extension, you can just use:
Time.update();
without having to create any object. You can execute any other method in the class in like manner (because they are all static).
RcCookie RcCookie

2020/8/13

#
I know, but how do I know that it's not been executed this frame already? If I will at some point create a more complex world basis, I might let it do that stuff because I know every of my words extends from it and will in fact run that code, but then I might as well create an instace of time.
danpost danpost

2020/8/13

#
RcCookie wrote...
I know, but how do I know that it's not been executed this frame already? If I will at some point create a more complex world basis, I might let it do that stuff because I know every of my words extends from it and will in fact run that code, but then I might as well create an instace of time.
If you only call it once from your World subclass' act method, it will only execute once per frame.
You need to login to post a reply.