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.zip
My 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:
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; // TEST: Player2 automove direction
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;
// Begin of Player2 automove
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;
}
}
// End of Player2 automove
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; // TEST: explosion will follow. GAME OVER
}
}
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
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