Conflux
Senior Newbie 
Java games rock!
|
 |
«
Posted
2003-11-18 10:03:26 » |
|
Hi folks! I was trying to create a small space-shooter (pong style) to get some experience with java 2D and realtime rendering. a jar containing a runnable version can be found at: http://www.hdm-stuttgart.de/~ml18/jumat/jumat.zipMy problem is, that the movement of the ships is still flickering although I am using double-buffering. Further implementations should be socket or RMI based multiplayer so I decided to run the game in a seperate thread (perhaps this could be useful later, but don't know exactly) But even if I remove the Thread and run the game in the main Thread (it gets up to 30000fps) the flickering still exists  Here's the main part of the code: The Frame containg a JPanel in the center: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
| public class GameWindow extends JFrame implements Runnable {
private ScenePanel pScene = new ScenePanel(this); BorderLayout borderLayout1 = new BorderLayout(); boolean running = true; boolean left = false; boolean right = false; boolean fire = false; boolean lock = false;
int screenwidth = 800; int screenheight = 600; int fps; int dir = 1; float frameduration; Ship player1 = new Ship("gfx/bat.gif", 368, 480, 300, 800, 100); Ship player2 = new Ship("gfx/cow.gif", 368, 40, 250, 850, 100);
public GameWindow() { this.setResizable(false); this.setTitle("Spacefight"); this.addKeyListener(new java.awt.event.KeyAdapter() { public void keyPressed(KeyEvent e) { this_keyPressed(e); } }); this.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(KeyEvent e) { this_keyReleased(e); } }); this.getContentPane().setLayout(borderLayout1); this.getContentPane().add(pScene, BorderLayout.CENTER); setSize(screenwidth, screenheight); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension size = getSize(); screenSize.height = screenSize.height/2; screenSize.width = screenSize.width/2; size.height = size.height/2; size.width = size.width/2; int y = screenSize.height - size.height; int x = screenSize.width - size.width; setLocation(x, y);
setVisible(true); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } void this_keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE) { if(!lock) { lock = true; fire = true; player1.shot.x = player1.posX+player1.w/2 - player1.shot.w/2; } } if (e.getKeyCode() == KeyEvent.VK_LEFT) { right = false; left = true; } if (e.getKeyCode() == KeyEvent.VK_RIGHT) { right = true; left = false; } } void this_keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_LEFT) { left = false; } if (e.getKeyCode() == KeyEvent.VK_RIGHT) { right = false; } }
public void run() { int count = 0; long fpsStartTime = System.currentTimeMillis(); long startTime;
synchronized (this) { while (running) { startTime = System.currentTimeMillis(); {try {this.wait(1);} catch (Exception e) {}} pScene.repaint(); count++; if (System.currentTimeMillis() > (fpsStartTime + 999)) { fps = count; count = 0; fpsStartTime = System.currentTimeMillis(); } frameduration = (System.currentTimeMillis() - startTime) / 1000.000f; if (dir==0) { if (player2.posX > 8) { player2.posX -= player2.movespeed * frameduration; } else { player2.posX = 8; dir = 1; } } if (dir==1) { if (player2.posX < screenwidth-player2.w-12) { player2.posX += player2.movespeed * frameduration; } else { player2.posX = screenwidth-player2.w-12; dir = 0; } } if (left) { if (player1.posX > 8) { player1.posX -= player1.movespeed * frameduration; } else { player1.posX = 8; } } if (right) { if (player1.posX < screenwidth-player1.w-12) { player1.posX += player1.movespeed * frameduration; } else { player1.posX = screenwidth-player1.w-12; } } if (fire) { player1.shot.y -= player1.firespeed * frameduration; if (player2.checkHit(player1.shot)) { player2.hitpoints -= player1.shot.dmg; player1.shot.y = player1.shot.initY; fire = false; lock = false; if (player2.hitpoints <= 0) { player2.hitpoints = 100; } } if (player1.shot.y <= 0) { player1.shot.y = player1.shot.initY; fire = false; lock = false; } } } } }
public void update(Graphics g) { paint(g); }
} |
The JPanel where the drawing takes place 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| class ScenePanel extends JPanel {
GameWindow gw; Image back = loadImage("gfx/stars0001.jpg"); private int bufferWidth; private int bufferHeight; private Image bufferImage; private Graphics bufferGraphics;
private MediaTracker mt;
ScenePanel(GameWindow gw) { this.gw = gw; }
public Image loadImage(String file) { Image img = Toolkit.getDefaultToolkit().getImage(file); mt = new MediaTracker(this); mt.addImage(img, 0); try { mt.waitForAll(); } catch (InterruptedException e) { e.printStackTrace(); } return img; }
public void update(Graphics g){ paint(g); }
public void paint(Graphics g){ if(bufferWidth!=getSize().width || bufferHeight!=getSize().height || bufferImage==null || bufferGraphics==null) resetBuffer(); if(bufferGraphics!=null){ bufferGraphics.clearRect(0,0,bufferWidth,bufferHeight); paintBuffer(bufferGraphics); g.drawImage(bufferImage,0,0,this); } }
private void resetBuffer(){ bufferWidth=getSize().width; bufferHeight=getSize().height; if(bufferGraphics!=null){ bufferGraphics.dispose(); bufferGraphics=null; } if(bufferImage!=null){ bufferImage.flush(); bufferImage=null; } System.gc(); bufferImage=createImage(bufferWidth,bufferHeight); bufferGraphics=bufferImage.getGraphics(); }
public void paintBuffer(Graphics g) { g.drawImage(back, 0, 0, this); g.drawImage(gw.player1.img, gw.player1.posX, gw.player1.posY, this); g.drawImage(gw.player2.img, gw.player2.posX, gw.player2.posY, this); g.setColor(Color.green); g.drawRect(gw.player2.posX, gw.player2.posY, gw.player2.w, gw.player2.h); g.drawRect(gw.player1.posX, gw.player1.posY, gw.player1.w, gw.player1.h); if (gw.fire) { g.drawImage(gw.player1.shot.img, gw.player1.shot.x, gw.player1.shot.y, this); } g.setColor(Color.red); g.fillRect(636,10,(int)(gw.player2.hitpoints*1.5),10); g.fillRect(636,553,(int)(gw.player1.hitpoints*1.5),10); g.setColor(Color.orange); g.drawString("FPS: " + gw.fps, 4, 16);
} } |
Would be really cool if someone could help me figure out where the flicker comes from 
|
|
|
|
|
kevglass
|
 |
«
Reply #1 - Posted
2003-11-18 10:11:57 » |
|
It *might* be something to do with this: this.getContentPane().setLayout(borderLayout1); this.getContentPane().add(pScene, BorderLayout.CENTER);
Since the content pane that exists might be doing the clear for you... try doing this instead: 1
| this.setContentPane(pScene); |
Kev
|
|
|
|
kevglass
|
 |
«
Reply #2 - Posted
2003-11-18 10:25:36 » |
|
Having looked again, it *might* also be your in the running thread. I believe repaint() schedules a repain of the surface as soon as possible, so you don't actually guarantee that a rendering has taken place by the time its returned (this would explain the extraordinary frame rates). Calling repaint(0) where the 0 is the time allowed before the repaint actually happens has worked for me in the past, but there may be a more correct way of doing it. repaint(0) will indicate that the repaint must occur immediately. Kev
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Conflux
Senior Newbie 
Java games rock!
|
 |
«
Reply #3 - Posted
2003-11-18 12:03:28 » |
|
A big thanks so far, Kev  I'll try your proposals as soon as I'm getting eclipse running on this PC where I'm currently sitting 
|
|
|
|
|
Conflux
Senior Newbie 
Java games rock!
|
 |
«
Reply #4 - Posted
2003-11-18 15:42:25 » |
|
with "replay(0);" there's a slight improvement (couldn't say exactly because there is still flickering) the setContent did nothing to improve the performance.  any other ideas? 
|
|
|
|
|
kevglass
|
 |
«
Reply #5 - Posted
2003-11-18 15:57:39 » |
|
Finally on a machine where I can download and try, Aww, no source!  Interesting, I don't get any global flickering.. is it just the ships you're worried about? I get an effect around the ships, but I think its more to do with the screen updating out of sync with the game giving that shimmering around the ships... Kev
|
|
|
|
immudium
|
 |
«
Reply #6 - Posted
2003-11-18 16:16:19 » |
|
Hmmm, I ran it on my box and to me it actually doesn't look like it's flicker per se...more like it's skipping a few pixels every so often as it slides back and forth. It seems to me you need a way to interpolate the position of your spaceship so that when your framerate drops, your ship doesn't "hop" so much. Maybe this thread might help? http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=Tuning;action=display;num=1058296748And maybe a couple of other ideas if that's not it. Did you double check that your JFrame's double buffering didn't get turned of by checking isDoubleBuffered()? Also is pScene.repaint() trying to paint the entire window? You might already know this but you would get much better performance just repainting the square surrounding the spaceship if this is not already the case.
|
|
|
|
|
Jeff
|
 |
«
Reply #7 - Posted
2003-11-19 05:13:07 » |
|
Unless this is an applet game I'd strongly recommend dropping the repaint() approach in favor of an active rendering loop. As i think has already been pointed out 3000 calls to repaint doesn't necc equal 3000 frames as the system is free to coalesce repaint attempts.
|
|
|
|
Jeff
|
 |
«
Reply #8 - Posted
2003-11-19 05:16:36 » |
|
I also note that you are calling repaint on the entire panel.
It doesnt look like you've done anything to disable background clearing. If the background is getting cleared each frame that could give you a flicker. Disable the clear and just do dirty rectangle update.
OR as I said before go to active rendering and just flip frames. Thats the best solution as long as you dont need to run under Java 1.1
|
|
|
|
kevglass
|
 |
«
Reply #9 - Posted
2003-11-19 06:02:51 » |
|
Trying to remember from the "old days" but doesn't overriding update(Graphics g) prevent background clearing?
Kev
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Conflux
Senior Newbie 
Java games rock!
|
 |
«
Reply #10 - Posted
2003-11-19 09:03:26 » |
|
Unless this is an applet game I'd strongly recommend dropping the repaint() approach in favor of an active rendering loop. As i think has already been pointed out 3000 calls to repaint doesn't necc equal 3000 frames as the system is free to coalesce repaint attempts.
Please forgive me my lack of knowledge but what exactly is an active rendering loop?? I´'ll try the timing-loop algo posted in the other topic. It looks very suitable for me  Hope it works. thx so far...  I'll post my results here if sth important happens 
|
|
|
|
|
duncanIdaho
Junior Member  
invert mouse
|
 |
«
Reply #11 - Posted
2003-11-19 22:39:32 » |
|
kev: yes. Overriding update will remove the flicker associated with background clearing. 1 2 3 4
| public void update( Graphics g ) { paint( g );
} |
just learned that looking at javazoid's interpolation bug jar ;-)
|
|
|
|
|
|
|
kevglass
|
 |
«
Reply #13 - Posted
2003-11-24 06:17:09 » |
|
Where does your scroller code live now Jeff?
Kev
PS. Jeff, a God? Fear thee all.
|
|
|
|
immudium
|
 |
«
Reply #14 - Posted
2003-11-24 14:54:16 » |
|
Is this the latest and greatest scroller code by chance? https://misc-demos.dev.java.net/source/browse/misc-demos/I was just looking at it recently which is why I had it handly. By the way, thanks for the great example Jeff, it's helped me out quite a bit in learning some of this stuff.
|
|
|
|
|
Jeff
|
 |
«
Reply #15 - Posted
2003-11-25 22:12:02 » |
|
Yep, thats my demo. Cleaned up some by GhergisKahn so thank him too  JK
|
|
|
|
Conflux
Senior Newbie 
Java games rock!
|
 |
«
Reply #16 - Posted
2003-12-03 10:09:48 » |
|
ok, now  with the gage-timer it runs a lot smoother. thx a lot  btw. can I download the scoller example as a zip file somewhere?
|
|
|
|
|
Jeff
|
 |
«
Reply #17 - Posted
2003-12-03 23:38:42 » |
|
The link is at the bottom of the previous page.
|
|
|
|
nickdotjava
Junior Member  
I have fallen to the dark side. I'm using DX9
|
 |
«
Reply #18 - Posted
2003-12-06 07:52:56 » |
|
But even if I remove the Thread and run the game in the main Thread (it gets up to 30000fps) the flickering still exists  30000 fps? wow!
|
-Nick
"Oh ya, that's trivial. I should have it done in an hour."
|
|
|
Jeff
|
 |
«
Reply #19 - Posted
2003-12-07 03:09:45 » |
|
30000 fps? wow!
he wasn't getting 30000 fps. He was getting 30000 calls to repaint per sec, which as already explained has no direct correlation to frame rate.
|
|
|
|
Kommi
Junior Member  
All opinions will be lined up and shot!
|
 |
«
Reply #20 - Posted
2003-12-15 17:16:47 » |
|
hey Jeff I cant seem ti find a zipped file of your Scroller at the linked location. What package would I dl if I wanted the whole program?
|
Kommi
|
|
|
Jeff
|
 |
«
Reply #21 - Posted
2003-12-16 02:44:41 » |
|
Dunno if there is a Zip posted.
You can always go get WINCVS, its free, and grab a copy of the CVS workspace.
|
|
|
|
|