1

I was trying something in my cs lecture then suddenly i have experienced an interesting problem.

this is my main code,

public void run(){
    setSize(800, 600);

    for(int i=0; i<= 30; i++){
        elips el = new elips();
        el.setFilled(true);
        el.setColor(Color.RED);
        elipsler.add(el);
        add(el);
    }

    while(!stopthat){
        for(int i=0; i< elipsler.size() -1; i++){
            elipsler.get(i).cdRemove();

            println("asd");

            if(elipsler.get(i).canRemove == true){
                remove(elipsler.get(i));
                elipsler.remove(i);
                elips el = new elips();
                el.setFilled(true);

                add(el);
                elipsler.add(el);
            }
        }
    }
}

and that's my ellipse class.

public class elips extends GOval{
    static int x, y, w, h;
    int cd;
    public boolean canRemove = false;
    Random rand = new Random();

    public elips(){
        super(x, y, w, h);
        canRemove = false;
        cd = rand.nextInt(100);
        x = rand.nextInt(780) + 20;
        y = rand.nextInt(580) + 20;
        w = rand.nextInt(80) + 20;
        h = rand.nextInt(80) + 20;
    }

    public void cdRemove(){
        if(this.cd <= 0){
            this.canRemove = true;
        }else{
            this.cd--;
        }
    }
}

As you see, I am creating ellipses and giving them "remove cooldown" and after end of cooldown the ellipses destroy. The problem is if i remove println("asd") line, code does not work properly. That is, if i remove that line, the ellipses appear and disappear at the same time(cooldowns don't work).

so I wonder how "println" line can solve this problem?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
shanks
  • 342
  • 2
  • 4
  • 16
  • Just as a coding standard FYI, your class name should start with a capital letter. So instead of `public class elips` it should be `public class Elips` – Ascalonian Feb 18 '15 at 13:03
  • 'println' gives some delay and method cdRemove() manages to finish the job. – DmitryKanunnikoff Feb 18 '15 at 13:04
  • when i write "cd = rand.nextInt(10000)" instead of "cd = rand.nextInt(100)" it slows much more if there is println line. after i remove println line the cooldown system does not work. – shanks Feb 18 '15 at 13:20

2 Answers2

2

Counting down from 100 to 0 is done in virtually zero time and that is essentially what you are doing before removing the ellipse. The reason you see the ellipse when adding the println, is because it takes some small amount of time to print. A hundred times, and you got yourself a couple of milliseconds worth of ellipse.

What you want to do is replace the raw count down with an actual timer of some kind. Stopwatch would do the job. (Apparantely DateTime, which I previously suggested, is not that accurate when down to a few milliseconds) I was thinking in C# this whole time. In java, using System.currentTimeMillis() is the way to go.

ninja: I'll provide code later today if you need it

EDIT: Right now, you are essentially doing this:

add ellipse
for(int i = 0; i < 100; i++)
{
    // nothing happening in here, this entire loop takes zero time
}
remove ellipse

And with the println:

add ellipse
for(int i = 0; i < 100; i++)
{
    println("asd"); 
    // something happening in here, this entire loop takes a little bit of time
}
remove ellipse

This kind of cooldown-system is going to be a problem in more than one way:

  • The time it takes for each tick is gonna differ (sometimes greatly) depending on the computer it is run on
  • You are basically locking up your entire application. If you want to do something parallel to this, you are going to have to create a separate thread, or whatever you do will affect the time between each tick, thus changing the cooldown, while also be affected by the same cooldown as all your ellipses combined.
  • You are not actually measuring time.

So, here's an option that does measure time:

public class elips extends GOval{
    static int x, y, w, h;
    int cd;
    public boolean canRemove = false;
    Random rand = new Random();

    long timeStart;

    public elips(){
        super(x, y, w, h);
        canRemove = false;
        cd = rand.nextInt(100);
        x = rand.nextInt(780) + 20;
        y = rand.nextInt(580) + 20;
        w = rand.nextInt(80) + 20;
        h = rand.nextInt(80) + 20;

        timeStart = System.currentTimeMillis();
    }

    public void cdRemove(){
        if(System.currentTimeMillis() > timeStart + cd)
            this.canRemove = true;
    }
}

And:

public void run(){
    setSize(800, 600);

    for(int i=0; i<= 30; i++){
        elips el = new elips();
        el.setFilled(true);
        el.setColor(Color.RED);
        elipsler.add(el);
        add(el);
    }

    while(!stopthat){
        // now you can do stuff here that will not be delayed by the ellipse cooldowns
        // neither will it become part of the ellipse cooldowns 
        for(int i=0; i< elipsler.size() -1; i++){
            elipsler.get(i).cdRemove();


            if(elipsler.get(i).canRemove == true){
                remove(elipsler.get(i));
                elipsler.remove(i);
                elips el = new elips();
                el.setFilled(true);

                add(el);
                elipsler.add(el);
            }
        }
    }
}

This might be subject to a few changes, my proof read was a quick one.

EDIT 2: I was thinking in C# with the stopwatches and all, fixed that now.

Anton
  • 1,435
  • 2
  • 10
  • 21
  • when i write "cd = rand.nextInt(10000)" instead of "cd = rand.nextInt(100)" it slows much more if there is println line. after i remove println line the cooldown system does not work. – shanks Feb 18 '15 at 13:19
  • @shanks Yeah, I get that. When you remove the println, counting down is done at incredible speeds. I would not be surprised if you set the cd to Int32.MAX_VALUE and still don't get a printed ellipse. Your cooldown goes down to zero in no time unless something that takes time (println) happens with each tick. When you do have the println, and a cd of 10000, it's gonna take some time since you are printing something (which takes some small amount of time) 10000 times. – Anton Feb 18 '15 at 13:24
  • @shanks My point is that you cannot rely on the time it takes to go through a loop a set amount of times as your cooldown timer. You need something that _actually_ measures time. – Anton Feb 18 '15 at 13:26
  • i got your point thanks, but i always have done my cooldown systems like that, i have faced with a problem like this only in this one :( eventually, don't "this.cd--" happen in each tick? – shanks Feb 18 '15 at 13:52
  • @shanks I have edited my answer, it turned into a big one. I hope it makes sense. If not, ask on! – Anton Feb 18 '15 at 14:23
  • thank you so much now i got everything :) i was doing my cooldowns like this on libs like libgdx etc. so i guess their run method works like 60 fps in a second so they are slower than default java, is it correct? – shanks Feb 18 '15 at 14:47
  • Never acutally used libgdx, but yes I would assume there is a set timelapse between the updates if it worked for you then. This is very popular in more game-centric engines. If by slower you mean not updating as often, then yes, not necessarily slower in performance though. I'm glad I could help :) Please accept my answer by clicking the tick under the vote arrows so the question gets marked as answered. – Anton Feb 18 '15 at 16:57
0

println("asd"); is pretty expensive operation. Without it, the loop above completes in less than 10ms, way to fast for the human eye to notice.

With the println(), the loop takes much longer, allowing you to see what happens.

When doing animations, you need to synchronize your animation loop to a timer to make sure you don't get more than 60 frames per second because the human eye is too slow to see that fast.

A simple fix is to replace the println() with Thead.sleep(1000/50); to get 50 frames per second (roughly). If you want a smooth animation, you need to use Timer.scheduleAtFixedRate() to account for the time that your rendering commands take.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820