Z-Man
|
 |
«
Posted
2011-07-01 08:28:59 » |
|
I know that both of these have been posted about and I apologize if I shouldn't post this but I'm just a bit confused. Recently I posted on a Java Forums topic about things you disliked about Java, I mentioned the Java2D bug that causes stuttering and someone said there was no Java2D bug. I am pretty positive I read about a Java2D bug here. I posted how I drew and they said drawing with a Canvas is bad (I believe ra4king suggested this to me?). So I guess my question is who should I believe >_< I'm all confused now. Is there a Java2D bug that causes slight stuttering? Is drawing on a Canvas better or worse then extending paintComponent() in a JComponent?
|
|
|
|
|
pitbuller
|
 |
«
Reply #1 - Posted
2011-07-01 09:48:25 » |
|
Both those have some stuttering. Slick2d don't have and have similar api. If that's not the option maybe try with pulp core?
|
|
|
|
|
philfrei
|
 |
«
Reply #2 - Posted
2011-07-01 10:28:31 » |
|
I don't know how you define stuttering, or what you are trying to do exactly. Java 2D has worked fine for me and works well for basic click and drag animation and simple sprite animation (smoke, twinkling stars) that I am doing in Hexara. And it manages this despite a high use of cpu for the sound effects. The Full-Screen Exclusive Mode API is designed for more demanding graphics. A lot of the folks here use it and champion it and I have no reason to doubt either them or the documentation. If I felt I needed it for the immediate project, I wouldn't hesitate to dive in. You can read about it here: http://download.oracle.com/javase/tutorial/extra/fullscreen/index.htmlBut with either path, there are lots of ways to go wrong and write less than optimal code. Maybe that's why some of the frameworks are so popular, as they both simplify away a many low-level complexities as well as greatly speed up development. If you still have the stuttering problem, I suspect there are issues with the coding, not the API. At least for me, 98% of the time I start to suspect there's a bug in the system it turns out to be a mistake or misunderstanding on my part. But maybe you are programming at a superior level than I am. This would not be too difficult.
|
"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
|
|
|
Games published by our own members! Check 'em out!
|
|
Cero
|
 |
«
Reply #3 - Posted
2011-07-01 15:13:58 » |
|
I assume you talk about screen-tearing:
basically it is desirable to get VSync, since then you can be certain it doesn't happen
if you use the opengl java2d pipeline for example its always vsynced if driver supports it same applies if you use some sort of opengl binding instead of java2d
now there are still cases in which you dont have vsync, most times in window mode in these cases you have to carefully write a gameloop that sleeps / yields appropriately. Hard to get right.
Slick seems to be able to do this by .setTargetFPS(int) which works even if vsync doesn't
|
|
|
|
ra4king
|
 |
«
Reply #4 - Posted
2011-07-01 18:37:07 » |
|
Whoever said drawing on Canvas is bad is either a troll or thinks he knows something that everyone else doesn't. And the only major Java2D bug I'm aware of is the V-Sync not available in windowed mode problem.
|
|
|
|
Z-Man
|
 |
«
Reply #5 - Posted
2011-07-01 19:32:46 » |
|
Ok, thanks for answering everyone. The stuttering is really small and it sounds like it might be screen tearing, but I certainly don't rule out my programming since it's not even close to perfect. The stutter isn't terrible but it is noticeable. I've been looking in the Slick2D API and have yet to find a way to use it with a Canvas, is this impossible? Now that I think about it I should probably use GUI components that are packaged with Slick2D or find a tutorial on Slick2D or something. @philfrei Trust me I am not on a higher level by any means. It is very likely it is my coding, but I made a really simple game loop, and had really simple drawing just to test if it really is my programming. I still got stuttering.  Also by stuttering I mean, if I have a cube moving across the screen it's movement will be broken slightly (kind of like it's not moving for a tiny amount of time) and then it will keep going. @ra4king The poster who suggested using paintComponent() in a JComponent gave this reason: Yeah, you're making it way more complicated than it should be. I would expect to see flickering if you're doing that, because you're fighting over what's being drawn- what you're drawing, and what the Component is drawing (which is probably nothing). Instead of any of that, simply override paintComponent (why are you using AWT instead of Swing?) and do all your drawing in there. EDIT: Out of curiosity, does anyone know why there isn't a JCanvas?
|
|
|
|
|
ra4king
|
 |
«
Reply #6 - Posted
2011-07-02 03:52:39 » |
|
How did you make your game loop? Slick2D uses OpenGL, while Canvas uses Java2D, two completely different things. Swing uses AWT. AWT is a windowing system, Swing is a GUI library that uses AWT, aka Graphics2D, to draw the widgets.  However, since passive rendering (aka calling redraw() and waiting for another thread to call paint()) is not recommended for games, Swing is not suitable for games. And there is no point for JCanvas since JComponent is already there.
|
|
|
|
Z-Man
|
 |
«
Reply #7 - Posted
2011-07-02 06:08:55 » |
|
The game loop is this: [CODE] long start = System.nanoTime();
while(running) { updateGame(); paintGame();
while((System.nanoTime() - start) < period) try { Thread.sleep(1); }catch(Exception e) {}
start = System.nanoTime(); } System.exit(0); [/CODE]
Yup, so I'll have to learn Slick2D or just deal with the tearing/stuttering.
|
|
|
|
|
|
|
Riven
|
 |
«
Reply #9 - Posted
2011-07-02 18:38:47 » |
|
The game loop is this: [CODE] long start = System.nanoTime();
while(running) { updateGame(); paintGame();
while((System.nanoTime() - start) < period) try { Thread.sleep(1); }catch(Exception e) {}
start = System.nanoTime(); } System.exit(0); [/CODE]
Yup, so I'll have to learn Slick2D or just deal with the tearing/stuttering.
You're leaking time. Line 15 should be:
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Z-Man
|
 |
«
Reply #10 - Posted
2011-07-02 21:17:28 » |
|
@ra4king Nope I'm not noticing any tearing/stuttering or lag. It runs at a constant 59fps and looks good.
@Riven Oh. Thanks that seems to help.
I have it running at 60-61fps now and the cube moves 5px every update. At first it starts out fine no tearing/stuttering then after a little while it starts to tear/stutter. Could this be because my game loop has no way of catching up? Like skipping frames or something? My game loop is exactly the same as above, except for the change Riven pointed out on line 15.
|
|
|
|
|
Mickelukas
|
 |
«
Reply #11 - Posted
2011-07-02 21:30:30 » |
|
Are you moving it exactly 5 pixels each time? If not then floats could help with making the animation smoother.
If that's not it then it could be garbage collection, care to post the code?
Mike
|
|
|
|
Z-Man
|
 |
«
Reply #12 - Posted
2011-07-02 23:18:30 » |
|
@Mickelukas Yup, exactly 5px every update. Sure I can post the code, right now it's just moving a box. [CODE] public class MyCanvas extends Canvas implements Runnable { private int cWidth, cHeight; // Canvas width and height private Thread animator = null; // Animation thread private BufferStrategy strategy = null; private volatile boolean running; private int reqFPS; // Requested FPS private long period; // Period between updates private long fpsTime; // Used to calculate current FPS private int fps; // Current fps private int frames; // Number of frames drawn
private int x, y; // X, and Y cord. of th cube private final int cubeWidth = 25, cubeHeight = 25; private final int SPEED = 5; // Speed of the cube in pixels
public MyCanvas(int width, int height, int fps) { cWidth = width; cHeight = height; x = (cWidth - cubeWidth) / 2; y = (cHeight - cubeHeight) / 2; reqFPS = fps; period = Math.round(1000000000.0 / (double) reqFPS); fps = frames = 0; fpsTime = 0l; setBackground(Color.black); setPreferredSize(new Dimension(cWidth, cHeight)); setIgnoreRepaint(true); running = true; }
public void start() { createBufferStrategy(2); strategy = getBufferStrategy(); requestFocusInWindow(); if(animator == null) { animator = new Thread(this); animator.start(); } }
public void updateGame() { // Check time long curr = System.nanoTime(); if(curr - fpsTime >= 1000000000) { // Update FPS fps = frames; frames = 0; fpsTime = curr; }
// Update cube location x += SPEED; if(x > cWidth) x = 0 - cubeWidth; }
public void paintGame() { do { do { Graphics2D g = (Graphics2D) strategy.getDrawGraphics(); // Clear the screen g.setColor(getBackground()); g.fillRect(0, 0, cWidth, cHeight);
// Draw the cube g.setColor(Color.white); g.fillRect(x, y, cubeWidth, cubeHeight);
// Draw the FPS g.drawString("FPS: " + fps, 5, cHeight - 5);
g.dispose(); }while(strategy.contentsRestored());
strategy.show(); }while(strategy.contentsLost()); frames++; }
@Override public void run() { long start = fpsTime = System.nanoTime();
while(running) { updateGame(); paintGame();
while((System.nanoTime() - start) < period) try { Thread.sleep(1); }catch(Exception e) {} start += period; } System.exit(0); } }
/** * Creates a JFrame and adds an instance of MyCanvas to it. */ class MyCanvasTester { public static void main(String args[]) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
public static void createAndShowGUI() { JFrame frame = new JFrame("Canvas Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); MyCanvas canvas = (MyCanvas) frame.add(new MyCanvas(600, 600, 60)); frame.setFocusable(false); frame.setIgnoreRepaint(true); frame.pack(); frame.setVisible(true); canvas.start(); } } [/CODE]
|
|
|
|
|
ra4king
|
 |
«
Reply #13 - Posted
2011-07-03 06:29:27 » |
|
Well that's what I wanted to make sure. Here's my game loop: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| long lastTime = System.nanoTime();
while(isActive) { long now = System.nanoTime(); update(now-lastTime); lastTime = now; render(); long sleepTime = (ONE_SECOND/FPS)-(System.nanoTime()-lastTime); if(sleepTime <= 0) continue; long prevTime = System.nanoTime(); while(System.nanoTime()-prevTime < sleepTime) Thread.yield(); } |
Notice how I account for the time taken during update() and render() so that I don't sleep the entire period but (period-frameTime).
|
|
|
|
Z-Man
|
 |
«
Reply #14 - Posted
2011-07-03 07:25:44 » |
|
1
| long sleepTime = (ONE_SECOND/FPS)-(System.nanoTime()-lastTime); |
What's this line doing? ONE_SECOND is a second in nanoseconds right? Is FPS the FPS you want or the FPS you're getting? EDIT: Out of curiosity, would it be any more efficient to declare the variables used in the while loop outside of it so that they aren't being created for every iteration of the loop, or does it not make a difference. EDIT 2: Here is what I have so far. I was using Thread.sleep(1) but it was causing stuttering and I'm not getting that with Thread.yield(). I was also getting 59 fps with Thread.sleep(1) and I'm getting 60 fps (which is what I request) with Thread.yield(). I think my loop now does what you are talking about. Any improvements to make? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| long pre, prev, sleepTime; fpsTime = System.nanoTime(); while(running) { pre = System.nanoTime(); updateGame(); paintGame(); sleepTime = period - (System.nanoTime() - pre);
if(sleepTime < 0) continue; prev = System.nanoTime(); while(System.nanoTime() - prev < sleepTime) Thread.yield(); } System.exit(0); |
|
|
|
|
|
Roquen
|
 |
«
Reply #15 - Posted
2011-07-03 11:58:18 » |
|
Has anyone figured out if sleep(0) works properly across various modern OSes? (Yeah, yeah I could look it up, but I'm too lazy)
|
|
|
|
|
Riven
|
 |
«
Reply #16 - Posted
2011-07-03 14:59:12 » |
|
EDIT: Out of curiosity, would it be any more efficient to declare the variables used in the while loop outside of it so that they aren't being created for every iteration of the loop, or does it not make a difference. Variables are not 'created', they simply use space on the stack-frame. It's much faster than accessing instance fields, as they add a level of indirection. EDIT 2: Here is what I have so far. I was using Thread.sleep(1) but it was causing stuttering and I'm not getting that with Thread.yield(). I was also getting 59 fps with Thread.sleep(1) and I'm getting 60 fps (which is what I request) with Thread.yield(). I think my loop now does what you are talking about. Any improvements to make? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| long pre, prev, sleepTime; fpsTime = System.nanoTime(); while(running) { pre = System.nanoTime(); updateGame(); paintGame(); sleepTime = period - (System.nanoTime() - pre);
if(sleepTime < 0) continue; prev = System.nanoTime(); while(System.nanoTime() - prev < sleepTime) Thread.yield(); } System.exit(0); |
You're leaking time again. Just keep in mind that the only way you're ever allowed to 'bump time' is not by assigning 'now' but by adding a constant to the previous timestamp.
|
|
|
|
Z-Man
|
 |
«
Reply #17 - Posted
2011-07-03 18:57:36 » |
|
Ah I didn't know it worked like that, I guess I need to go back and read up on it. I think I fixed the leak though, instead of setting pre each time, I set it before the loop and then increment it by period. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| long pre = fpsTime = System.nanoTime();
while(running) { updateGame(); paintGame(); long sleepTime = period - (System.nanoTime() - pre); pre += period;
if(sleepTime < 0) continue; long prev = System.nanoTime(); while(System.nanoTime() - prev < sleepTime) Thread.yield(); } System.exit(0); |
EDIT: @Roquen My CPU usage starts at about 8% right now, when using the above loop with Thread.sleep(1) it goes to between 15 and 20 percent, using Thread.sleep(0) it goes up to around 50% which is about the same as Thread.yield(). I'm on Windows 7 64-bit Home Premium.
|
|
|
|
|
ra4king
|
 |
«
Reply #18 - Posted
2011-07-03 20:46:16 » |
|
1
| long sleepTime = (ONE_SECOND/FPS)-(System.nanoTime()-lastTime); |
What's this line doing? ONE_SECOND is a second in nanoseconds right? Is FPS the FPS you want or the FPS you're getting? ONE_SECOND = 1e9 And FPS is the number of frames I want per second. You're leaking time again. Just keep in mind that the only way you're ever allowed to 'bump time' is not by assigning 'now' but by adding a constant to the previous timestamp.
How is he leaking time?
|
|
|
|
|