Problems with vsync and TimerTask

I am new to Java game programming, but I’ve done a bit of Allegro, so I thought it could be fun trying a bit of Java ;D

I decided to make a small program with a sliding ball to get vsync in order…

Here is the code:

import java.applet.;
import java.awt.
;
import java.awt.geom.;
import java.awt.image.
;
import java.awt.image.BufferStrategy;
import java.awt.Graphics2D.;
import java.util.
;

public class PlayingField extends Applet{

public void init() {
setLayout(new BorderLayout());
add(new PField());
}
}

class PField extends Canvas {
PaintTimer pt;
Timer t;
int x;
BufferedImage bi;
Graphics2D big;
Rectangle area;
BufferStrategy strategy;
boolean firstTime = true;
boolean increasing = true;

public PField() {
x = 0;
pt = new PaintTimer();
t = new Timer();
t.scheduleAtFixedRate(pt,200,10);
}

public void paint(Graphics g) {
update(g);
}

public void update(Graphics g) {
if(firstTime) {
Dimension d = getSize();
area = new Rectangle(d);
bi = (BufferedImage)createImage(d.width,d.height);
big = bi.createGraphics();
createBufferStrategy(3);
strategy = getBufferStrategy();
firstTime = false;
}
Graphics2D g2d = (Graphics2D)strategy.getDrawGraphics();
g2d.setColor(Color.white);
g2d.clearRect(0,0,area.width,area.height);
g2d.setColor(Color.red);
g2d.fill(new Ellipse2D.Double(x,50,32,32));

strategy.show();
g2d.dispose();

}

class PaintTimer extends TimerTask {
public void run() {
if(x+32>=area.width && increasing==true)
increasing = false;
if(x<=0 && increasing==false)
increasing = true;

  if(increasing)
    x = x + 2;
  else
    x = x - 2;
  repaint();
}

}
}

Here vsync seems to be ok, however the speed is not constant. Why is that, is there any timing method which is more constant than TimerTask?

I have tried to remove Graphics g from update, which I should be able to as update don’t use g at all. But that really messes up things. The vsync goes completely, so as well as speed problems I also get flickering!

Why is that?

Could anybody pls enlighten me 8)

Dont use timertask for anything, it is an incomplete API.

One day, maybe, Sun will finish writing it. It is somewhat incredible that it’s even included in the standard libraries, since it’s clearly not production ready. I guess enough Sun customers were desperate enough for “anything, even if it’s poor”.

It’s the most basic feature of an OOP language (although that’s not to say it’s obvious how this works until you already know ;D). If you “remove” that parameter then you are making a completely different method. All the method calls in the system which invoke:

yourthing.update( some-graphics-or-other );

will, for fairly obvious reasons, NOT get “secretly redirected” to some phantom method of yours which has no argument.

Lots of scripting languages hide this, and some “alternative” language designs exist where the parameters are considered unimportant, so that update( graphics ) could actually invoke a method that is just update() - but these are very off-the-wall; they are fine, but you have to adopt significantly different approaches to how you think about programming (in many people’s opinion, better approaches - but they have yet to unseat the mainstream ones that do not work that way).

Re: the update(g) stuff, you need to find a good tutorial on OOP - start with the Sun free ones (google for sun java tutorial) if you’ve not already done them.

PS: I’ve made the same mistake three times in my life that I remember, and I didn’t have any excuse of ignorance - I knew perfectly well what was going on, I was just being stupid :). So I can remember how easy it is to interpret the language in the way that you did.

[quote]But that really messes up things. The vsync goes completely, so as well as speed problems I also get flickering!
[/quote]
This is because you are no longer overriding the existing (“default”) method “update( Graphics g)”. This is another of the most fundamental “features” of OOP: when you write a class with “extends ANOTHERCLASS” you automatically inherit all the other class’s methods. And, in turn, inherit any that it had inherited from the class it extended (if it had an “extends” clause at the top).

If you look in the javadocs / API docs for Applet, and follow the tree diagram up, you’ll eventually find a class that has the update( graphics g ) method in it - when you wrote your own one, you disabled that method. When you changed the parameters, you re-enabled the default version.

The default version just does:

  • paint a grey background
  • invoke paint( Graphics g )

the flickering is because it is, by default, wiping the screen to grey every frame.

;D

Thx alot.
How stupid of me. Of course I am making more polymorphisme!!!

I didn’t know that update was an excisting method, I thought I was declaring a new method, which paint was calling. This is the first time I play around with graphics in Java, up until now I’ve only used Java for networking and data manipulation…

I have done more C/C++ work. I just want to learn more Java, so that my code will be portable.

What a shame that TimerTask isn’t complete, how do I make scheduling then. Can it really be correct to use busy waiting checking the internal clock when to move the ball!

That really sounds like CPU misusage.

Is there a method in applet or canvas, which get called on a regular basis, so that it could be used to check the clock instead of a busy waiting loop?

Just call Thread.yield() inside the loop and you’ll be fine.

Excellent just the thing I was looking for ;D

That was much the same as what I thought when I made the same mistake a long time ago.

The sad thing is that it’s actually possible that that could have been what was happening (have a look at the Reflection section of the docs sometime…lets you query what methods a class/object/etc has, and then invoke them in a type-safe manner etc).

But without using reflection (which you don’t normally do without special reason to - it’s much slower than direct code, because it compiles to much less efficient code (since it contains compilaiton references that cant be resolved until runtime - although in theory it needn’t be as slow as it is in current implementtions)) your assumption is not possible - there is no physical way that the invoker could do what you assumed.

Ok I have had a look at my small ball program, and I have rewamped it, so that it is using a separate thread.

Here is the code:

import java.applet.;
import java.awt.
;
import java.awt.geom.;
import java.awt.image.
;
import java.awt.image.BufferStrategy;
import java.awt.Graphics2D.*;
import java.util.Date;

public class PlayingField extends Applet implements Runnable{
PField pf;
Thread t;

public void init() {
setLayout(new BorderLayout());
pf = new PField();
add(pf);
}

public void start() {
t = new Thread(this);
t.start();
}

public void stop() {
pf.stop();
t = null;
}

public void destroy() {
pf.setVisible(false);
this.setVisible(false);
}

public void run() {
pf.initialise();
pf.machine();
}

}

class PField extends Canvas {
int x=0;
final static int FPS = 100;

long newTime;
long deltaTime;

Rectangle area;
BufferStrategy strategy;
Graphics2D g2d;
boolean firstTime = true;
volatile boolean done = true;
boolean increasing = true;

/**public PField() {
date = new Date();
}*/

public void initialise() {
setBackground(Color.black);
Dimension d = getSize();
area = new Rectangle(d);
createBufferStrategy(3);
strategy = getBufferStrategy();
firstTime = false;
done = false;
}

public void stop() {
done = true;
firstTime = true;
}

public void machine() {

while (!done) {
  newTime = System.currentTimeMillis();

  if (x + 32 >= area.width && increasing == true)
    increasing = false;
  if (x <= 0 && increasing == false)
    increasing = true;

  if (increasing)
    x = x + 4;
  else
    x = x - 2;

  g2d = (Graphics2D)strategy.getDrawGraphics();
  g2d.setColor(Color.black);
  g2d.clearRect(0, 0, area.width, area.height);
  g2d.setColor(Color.red);
  g2d.fill(new Ellipse2D.Double(x, 50, 32, 32));
  
  strategy.show();
  g2d.dispose();

  deltaTime = System.currentTimeMillis() - newTime;

  while (deltaTime<(1000/FPS)){
    try {
      Thread.sleep((1000/FPS)-deltaTime);
    } catch (Exception e) {
      e.printStackTrace();
    }
    deltaTime = System.currentTimeMillis()-newTime;
  }
}

}
}

Well, this time it is MUCH more smooth, however the are still occasional jumps in the animation!

Could this be caused because I am running it inside an applet? Or is it just me doing something stupid again :-/

I’ve made an application without an extra thread, and it was also laggy, however I changed the Thread.sleep loop to:

Thread.sleep((1000/FPS)-deltaTime / 2);

and this helped tremendously, it is now acceptable for me to go on with the actual game…

Thx for the help ;D