For many years I often have wondered, what the Swing equivalence
of a classic tight game loop might be. What I am thinking of is:
as fast as possible, repeat this:
if there is user input pending, then handle it
update the state to the next generation and redraw it
end repeat
(redraws might be omitted when know to be invisble due to a
limited screen refresh rate, this is the meaning of
�possiblyRepaint�, below.)
Now I have heard that often 1 ms timer events are recommended
with the idea that Swing will coalesc multiple timer events into
a single one and that they have lower priority than user inputs.
(Theoretically, there also is the possibility that 1 ms is to
slow, so that the program might become idle.)
Recently, I had another idea of:
public class NextGeneration implements java.lang.Runnable
{ public void run()
{ calculateNextGeneration();
possiblyRepaint();
invokeLater( this ); }}
. I am hoping that the recursion via �invokeLater( this )�
will effectively give me a loop (but not eat stack, since
it's not a real recursion) and at the same time user input
events IIRC have a higher priority than invokeLater events,
so that they will still be handled. What do you think about
such an �invokeLater� loop?
|
|
0
|
|
|
|
Reply
|
ram (2829)
|
6/4/2012 12:31:06 PM |
|
On 6/4/12 5:31 AM, Stefan Ram wrote:
> For many years I often have wondered, what the Swing equivalence
> of a classic tight game loop might be. What I am thinking of is:
>
> as fast as possible, repeat this:
> if there is user input pending, then handle it
> update the state to the next generation and redraw it
> end repeat
>
> (redraws might be omitted when know to be invisble due to a
> limited screen refresh rate, this is the meaning of
> �possiblyRepaint�, below.)
>
> Now I have heard that often 1 ms timer events are recommended
> with the idea that Swing will coalesc multiple timer events into
> a single one and that they have lower priority than user inputs.
> (Theoretically, there also is the possibility that 1 ms is to
> slow, so that the program might become idle.)
>
> Recently, I had another idea of:
>
> public class NextGeneration implements java.lang.Runnable
> { public void run()
> { calculateNextGeneration();
> possiblyRepaint();
> invokeLater( this ); }}
>
> . I am hoping that the recursion via �invokeLater( this )�
> will effectively give me a loop (but not eat stack, since
> it's not a real recursion) and at the same time user input
> events IIRC have a higher priority than invokeLater events,
> so that they will still be handled. What do you think about
> such an �invokeLater� loop?
>
>
AWT (not swing) has a method called "Exclusive Mode" which can bypass
the event-queue and you actively render your game. AFAIK it's the only
way you can access full screen mode, but I don't think full-screen was
required.
A quick search for java exclusive mode brought me to this link:
<http://docs.oracle.com/javase/tutorial/extra/fullscreen/index.html>
HTH,
Daniel.
|
|
0
|
|
|
|
Reply
|
newsgroup.nospam (532)
|
6/4/2012 2:34:12 PM
|
|
In article <tight-game-loop-20120604142027@ram.dialup.fu-berlin.de>,
ram@zedat.fu-berlin.de (Stefan Ram) wrote:
> For many years I often have wondered, what the Swing equivalence of
> a classic tight game loop might be. What I am thinking of is:
>
> as fast as possible, repeat this:
> if there is user input pending, then handle it
> update the state to the next generation and redraw it
> end repeat
>
> (redraws might be omitted when know to be invisble due to a
> limited screen refresh rate, this is the meaning of
> »possiblyRepaint«, below.)
>
> Now I have heard that often 1 ms timer events are recommended
> with the idea that Swing will coalesc multiple timer events into
> a single one and that they have lower priority than user inputs.
> (Theoretically, there also is the possibility that 1 ms is to
> slow, so that the program might become idle.)
The available resolution varies by platform:
<http://mindprod.com/jgloss/time.html#ACCURACY>
> Recently, I had another idea of:
>
> public class NextGeneration implements java.lang.Runnable
> { public void run()
> { calculateNextGeneration();
> possiblyRepaint();
> invokeLater( this ); }}
>
> I am hoping that the recursion via »invokeLater( this )«
> will effectively give me a loop (but not eat stack, since
> it's not a real recursion) and at the same time user input
> events IIRC have a higher priority than invokeLater events,
> so that they will still be handled. What do you think about
> such an »invokeLater« loop?
This reminds of an example adduced by Knute Johnson:
<https://groups.google.com/d/msg/comp.lang.java.gui/aBy_DZFvg2M/-T9aWOwBM-QJ>
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>
|
|
0
|
|
|
|
Reply
|
nospam59 (9800)
|
6/4/2012 3:01:26 PM
|
|
John B. Matthews wrote:
> This reminds of an example adduced by Knute Johnson:
>
> <https://groups.google.com/d/msg/comp.lang.java.gui/aBy_DZFvg2M/-T9aWOwBM-QJ>
Ten points for using the word "adduced".
There are some EDT violations in the cited code's 'main()' routine.
--
Lew
|
|
0
|
|
|
|
Reply
|
lewbloch (1312)
|
6/4/2012 11:39:54 PM
|
|
On 6/4/2012 4:39 PM, Lew wrote:
> John B. Matthews wrote:
>> This reminds of an example adduced by Knute Johnson:
>>
>> <https://groups.google.com/d/msg/comp.lang.java.gui/aBy_DZFvg2M/-T9aWOwBM-QJ>
>
> Ten points for using the word "adduced".
>
> There are some EDT violations in the cited code's 'main()' routine.
>
Here's the updated code with that fixed.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.lang.reflect.*;
import javax.swing.*;
public class test3 extends JPanel implements Runnable {
volatile BufferedImage bi;
volatile long then;
long now,time;
final Thread thread;
double angle,rate;
int n;
public test3() {
super(false);
setPreferredSize(new Dimension(400,300));
thread = new Thread(this);
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent ce) {
GraphicsConfiguration gc = getGraphicsConfiguration();
bi = gc.createCompatibleImage(getWidth(),getHeight());
}
});
}
public void start() {
then = System.nanoTime();
thread.start();
}
public void stop() {
thread.interrupt();
}
public void run() {
try {
long now = 0;
long then = System.nanoTime();
while (true) {
render();
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
paintImmediately(getBounds());
}
});
} catch (InvocationTargetException ite) {
System.out.println(ite);
}
/*
while (now < then + 10000000)
now = System.nanoTime();
then = now;
*/
}
} catch (InterruptedException ie) {
System.out.println(ie);
}
}
public void render() {
int w = getWidth();
int h = getHeight();
Graphics2D g = bi.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0,0,w,h);
if (++n % 100 == 0) {
now = System.nanoTime();
time = now - then;
then = now;
rate = 100000000000.0 / time;
}
g.setColor(Color.RED);
g.drawString(String.format("%5.1f",rate),10,12);
angle += 0.001;
g.rotate(angle,w/2,h/2);
g.setColor(Color.BLUE);
g.fillRect(w/2 - 100,h/2 - 100,200,200);
g.dispose();
}
public void paintComponent(Graphics g) {
g.drawImage(bi,0,0,null);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
final test3 t3 = new test3();
final JFrame f = new JFrame();
f.addWindowListener(new WindowAdapter() {
public void windowOpened(WindowEvent we) {
t3.start();
}
public void windowClosing(WindowEvent we) {
t3.stop();
f.dispose();
}
});
f.add(t3,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
});
}
}
|
|
0
|
|
|
|
Reply
|
nospam8071 (917)
|
6/6/2012 4:51:11 AM
|
|
Knute Johnson wrote:
> Lew wrote:
>> John B. Matthews wrote:
>>> This reminds of an example adduced by Knute Johnson:
>>>
>>> <https://groups.google.com/d/msg/comp.lang.java.gui/aBy_DZFvg2M/-T9aWOwBM-QJ>
>>
>> Ten points for using the word "adduced".
>>
>> There are some EDT violations in the cited code's 'main()' routine.
>>
>
> Here's the updated code with that fixed.
>
> import java.awt.*;
> import java.awt.event.*;
> import java.awt.geom.*;
> import java.awt.image.*;
> import java.lang.reflect.*;
> import javax.swing.*;
>
> public class test3 extends JPanel implements Runnable {
> volatile BufferedImage bi;
> volatile long then;
I am curious what motivated the choice of 'volatile'.
In my own case I will sometimes speculatively use 'volatile' to mark fields
not essential to state despite that the class does not implement
'Serializable'. While this violates the rigid rule prohibiting superfluity, I
aver that the marker aids reasoning about the state in such cases.
This doesn't seem to be that.
--
Lew
Honi soit qui mal y pense.
http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
|
|
0
|
|
|
|
Reply
|
noone7 (3512)
|
6/7/2012 6:58:37 AM
|
|
On 06/05/2012 09:51 PM, Knute Johnson wrote:
> public void run() {
> try {
> long now = 0;
> long then = System.nanoTime();
>
> while (true) {
> render();
> try {
> EventQueue.invokeAndWait(new Runnable() {
> public void run() {
> paintImmediately(getBounds());
> }
> });
> } catch (InvocationTargetException ite) {
> System.out.println(ite);
> }
>
> /*
> while (now < then + 10000000)
> now = System.nanoTime();
> then = now;
> */
> }
> } catch (InterruptedException ie) {
> System.out.println(ie);
> }
> }
>
How about this formulation?
@Override
public void run() {
for (boolean active = true; active; ) {
try {
render();
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
paintImmediately(getBounds());
}
});
} catch (InvocationTargetException ite) {
System.out.println(ite);
}
/*
for (long pause = System.nanoTime() + 10000000L;
System.nanoTime() < pause;
) {
}
*/
} catch (InterruptedException ie) {
System.out.println(ie);
active = false;
}
}
}
I base this on vague, hence possibly superstitiously encoded memories of
Goetz's (et al.) _Java Concurrency in Practice_ and other sources.
He goes to some length to re-educate about 'InterruptedException'. I may have
got it wrong, but I seem to recall something about setting a loop condition
rather than leaping out pell-mell, and a tickle about a rethrow of the
interruption but that might be for specialized circumstances. Like when the
interruptee isn't the end of the line for handling that interrupt as it is here.
I read a book. I'm not an authority.
I loathe 'System.out' for logging. OTOH, in this case the point of the program
arguably is the exception output, so it's legit, right?
--
Lew
Honi soit qui mal y pense.
http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
|
|
0
|
|
|
|
Reply
|
noone7 (3512)
|
6/7/2012 7:36:06 AM
|
|
On 6/6/12 11:58 PM, Lew wrote:
> Knute Johnson wrote:
>> Lew wrote:
>>> John B. Matthews wrote:
>>>> This reminds of an example adduced by Knute Johnson:
>>>>
>>>> <https://groups.google.com/d/msg/comp.lang.java.gui/aBy_DZFvg2M/-T9aWOwBM-QJ>
>>>>
>>>
>>> Ten points for using the word "adduced".
>>>
>>> There are some EDT violations in the cited code's 'main()' routine.
>>>
>>
>> Here's the updated code with that fixed.
>>
>> import java.awt.*;
>> import java.awt.event.*;
>> import java.awt.geom.*;
>> import java.awt.image.*;
>> import java.lang.reflect.*;
>> import javax.swing.*;
>>
>> public class test3 extends JPanel implements Runnable {
>> volatile BufferedImage bi;
>> volatile long then;
>
> I am curious what motivated the choice of 'volatile'.
>
> In my own case I will sometimes speculatively use 'volatile' to mark
> fields not essential to state despite that the class does not implement
> 'Serializable'. While this violates the rigid rule prohibiting
> superfluity, I aver that the marker aids reasoning about the state in
> such cases.
>
> This doesn't seem to be that.
>
Volatile has nothing to do with Serializable. Perhaps you're having a
moment of confusing volatile with transient? Volatile is necessary when
you want to force a happens-before relationship to reads/writes to a
field. It also guarantees the you won't have a situation where writes
aren't flushed to main memory before the next attempted read.
In other words, it is one safe way to publish a value across threads.
|
|
0
|
|
|
|
Reply
|
newsgroup.nospam (532)
|
6/7/2012 4:20:55 PM
|
|
Daniel Pitts wrote:
> On 6/6/12 11:58 PM, Lew wrote:
> > I am curious what motivated the choice of 'volatile'.
> >
> > In my own case I will sometimes speculatively use 'volatile' to mark
> > fields not essential to state despite that the class does not implement
> > 'Serializable'. While this violates the rigid rule prohibiting
> > superfluity, I aver that the marker aids reasoning about the state in
> > such cases.
> >
> > This doesn't seem to be that.
> >
> Volatile has nothing to do with Serializable. Perhaps you're having a
> moment of confusing volatile with transient? Volatile is necessary when
> you want to force a happens-before relationship to reads/writes to a
> field. It also guarantees the you won't have a situation where writes
> aren't flushed to main memory before the next attempted read.
>
> In other words, it is one safe way to publish a value across threads.
Duhy. My foolishness.
--
Lew
|
|
0
|
|
|
|
Reply
|
lewbloch (1312)
|
6/8/2012 7:28:52 PM
|
|
|
8 Replies
69 Views
(page loaded in 0.12 seconds)
|