Java-Gaming.org    
Featured games (78)
games approved by the League of Dukes
Games in Showcase (429)
Games in Android Showcase (89)
games submitted by our members
Games in WIP (467)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  JComponent vs Canvas and Java2D  (Read 4744 times)
0 Members and 1 Guest are viewing this topic.
Offline 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?
Offline 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?
Offline 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.html

But 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. Cranky

"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!
Legends of Yore - The Casual Retro Roguelike
Offline 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

Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« 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.

Offline 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.  Emo 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:
Quote
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?
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« 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. Wink
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.

Offline 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.
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #8 - Posted 2011-07-02 07:46:39 »

Try this game http://ra4king.is-a-geek.net/games/JDoodleJump
Do you see any screen tearing? Does it slow down/lag/stutter at any time?

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 614
Projects: 4
Exp: 16 years


Hand over your head.


« 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:
1  
   start += period;

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline 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.
Offline Mike

JGO Ninja


Medals: 69
Projects: 1
Exp: 5 years


Java guru wanabee


« 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

My current game, Minecraft meets Farmville and goes online Smiley
State of Fortune | Discussion thread @ JGO
Offline 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]
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« 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(); //Thread.sleep(1) more CPU-friendly but worse performance
}


Notice how I account for the time taken during update() and render() so that I don't sleep the entire period but (period-frameTime).

Offline 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(); // Used to calculate the actual FPS

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);
Offline 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)
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 614
Projects: 4
Exp: 16 years


Hand over your head.


« 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(); // Used to calculate the actual FPS

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.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline 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.
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« 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?

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (81 views)
2014-04-15 18:08:23

BurntPizza (73 views)
2014-04-15 03:46:01

UprightPath (84 views)
2014-04-14 17:39:50

UprightPath (67 views)
2014-04-14 17:35:47

Porlus (84 views)
2014-04-14 15:48:38

tom_mai78101 (107 views)
2014-04-10 04:04:31

BurntPizza (167 views)
2014-04-08 23:06:04

tom_mai78101 (263 views)
2014-04-05 13:34:39

trollwarrior1 (214 views)
2014-04-04 12:06:45

CJLetsGame (223 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!