I have implemented a little Flappy Bird clone with swing. I'm pretty new to Java, especially in graphic programming, so I'm really glad if someone an give me a feedback to my Code and maybe to movement of the bird, because it's not really smooth.
The bird is represented as a red square and the pipes are green rectangles. On my GameBoard i have a moving Bufferedimage as background, so it looks like the bird is moving and pipes were randomily placed.
MainWindow:
public class MainWindow {
private GameBoard gameBoard = new GameBoard();
public MainWindow() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("FlappyBirds");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(GameBoard.screenWidth,GameBoard.screenHeight);
frame.add(gameBoard);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static void main(String[] args) {
new MainWindow();
}
}
GameBoard:
public class GameBoard extends JPanel implements KeyListener {
private boolean running = true;
private int pressedKey;
private BufferedImage backgroundImage;
private int backgroundImageCoordX = 0;
private Bird bird = new Bird(new Rectangle(50, 250, 50, 50));
private Pipe pipe = new Pipe(bird);
public static int screenWidth;
public static int screenHeight;
public GameBoard() {
try {
backgroundImage = ImageIO.read(getClass().getResourceAsStream("Ressources/background.png"));
} catch (IOException ex) { // read Image from Ressourcefolder
ex.printStackTrace();
}
screenWidth = backgroundImage.getWidth();
screenHeight = backgroundImage.getHeight();
addKeyListener(this);
setFocusable(true);
setPreferredSize(new Dimension(backgroundImage.getWidth(), backgroundImage.getHeight()));
GameLoop gameLoop = new GameLoop();
new Thread(gameLoop).start();
}
class GameLoop extends Thread { // Gameloopfor udpdating all with 60 FPS
private static final int FPS = 60;
private static final long maxLoopTime = 1000 / FPS;
@Override
public void run() {
long timestamp;
long oldTimestamp;
while (running == true) {
oldTimestamp = System.currentTimeMillis();
timestamp = System.currentTimeMillis();
updateGameObjects();
updateScreen();
if (timestamp - oldTimestamp <= maxLoopTime) {
try {
Thread.sleep(maxLoopTime - (timestamp - oldTimestamp));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void checkGameOver() { /* if bird touches pipes or border Gameloop stop running */
if (bird.getBirdShape().intersects(pipe.getPipeShapeUp())
|| bird.getBirdShape().intersects(pipe.getPipeShapeBottom())
|| bird.getBirdShape().intersects(pipe.getPipeShapeBottom2())
|| bird.getBirdShape().intersects(pipe.getPipeShapeUp2())|| (int) bird.getBirdShape().getY() <= 0
|| bird.getBirdShape().getY() + bird.getBirdShape().getHeight() >= backgroundImage.getHeight()) {
running = false;
}
}
public void updateGameObjects() { // moves all GameObjects
bird.move();
backgroundImageCoordX = backgroundImageCoordX - bird.getSpeed();
pipe.move();
if (bird.getJump() == true) {
bird.makeJump();
bird.setJump(false);
}
checkGameOver();
}
public void updateScreen() { // repaint Screen
super.repaint();
}
@Override
public void paintComponent(Graphics g) { /*moving background Image,
so it seems bird is moving, render bird and random Pipes*/
super.paintComponent(g);
int w = backgroundImage.getWidth();
g.drawImage(backgroundImage, backgroundImageCoordX % w, 0, this);
g.drawImage(backgroundImage, (backgroundImageCoordX % w) + backgroundImage.getWidth(), 0, this);
bird.renderBird(g);
pipe.renderPipe(g);
if (backgroundImageCoordX >= 0) { // draw new Image and append it to current
g.drawImage(backgroundImage, (backgroundImageCoordX % w) - backgroundImage.getWidth(), 0, this);
bird.renderBird(g);
pipe.renderPipe(g);
}
if (pipe.getPipeShapeUp2().getX() <= 0) { // create new Pipes
pipe = new Pipe(bird);
pipe.renderPipe(g);
}
}
@Override
public void keyPressed(KeyEvent e) { // jump bird
pressedKey = e.getKeyCode();
if (pressedKey == KeyEvent.VK_UP) {
bird.setJump(true);
}
}
@Override
public void keyReleased(KeyEvent arg0) {}
@Override
public void keyTyped(KeyEvent arg0) {}
}
Bird:
public class Bird {
private Rectangle birdShape;
private final int speed = 5;
private boolean jump = false;
public Bird(Rectangle birdShape) {
this.birdShape = birdShape;
}
public void move() {
birdShape.setLocation((int) birdShape.getX(), (int) birdShape.getY() + speed);
}
public void makeJump() { /* bird goes up per default it falling down*/
if (jump == true) {
birdShape.setLocation((int) birdShape.getX(), (int) birdShape.getY() - 75);
}
}
public int getSpeed() {
return this.speed;
}
public boolean getJump() {
return this.jump;
}
public void setJump(boolean jump) {
this.jump = jump;
}
public Rectangle getBirdShape() {
return this.birdShape;
}
public void renderBird(Graphics g) {
g.setColor(Color.RED);
g.fillRect((int) birdShape.getX(), (int) birdShape.getY(), (int) birdShape.getWidth(),
(int) birdShape.getHeight());
}
}
Pipe:
public class Pipe {
private Bird bird;
private Rectangle pipeShapeBottom;
private Rectangle pipeShapeUp;
private Rectangle pipeShapeBottom2;
private Rectangle pipeShapeUp2;
private final Random random = new Random();
private final int pipeWidth = 50;
public Pipe(Bird bird) { /* creates 2 random Pipes on the Screen, if two pipes are out of screen,create new 2 pipes*/
this.bird = bird;
int heightPipeUp = random.nextInt(120) + 100;
int heightPipeBottom = random.nextInt(175) + 125;
int randomX = random.nextInt(150) + 225;
pipeShapeBottom = new Rectangle(randomX, 0, pipeWidth, heightPipeBottom);
pipeShapeUp = new Rectangle(randomX, GameBoard.screenWidth - heightPipeUp, pipeWidth, heightPipeUp);
heightPipeUp = random.nextInt(200) + 100;
heightPipeBottom = random.nextInt(175) + 125;
int randomX2 = random.nextInt(250) + 150;
pipeShapeBottom2 = new Rectangle(randomX + randomX2, 0, pipeWidth, heightPipeBottom);
pipeShapeUp2 = new Rectangle(randomX + randomX2, GameBoard.screenWidth - heightPipeUp, pipeWidth, heightPipeUp);
}
public Rectangle getPipeShapeUp() {
return this.pipeShapeUp;
}
public Rectangle getPipeShapeBottom() {
return this.pipeShapeBottom;
}
public Rectangle getPipeShapeUp2() {
return this.pipeShapeUp2;
}
public Rectangle getPipeShapeBottom2() {
return this.pipeShapeBottom2;
}
public void renderPipe(Graphics g) {
g.setColor(Color.GREEN);
g.fillRect((int) pipeShapeUp.getX(), (int) pipeShapeUp.getY(), (int) pipeShapeUp.getWidth(),
(int) pipeShapeUp.getHeight());
g.fillRect((int) pipeShapeBottom.getX(), (int) pipeShapeBottom.getY(), (int) pipeShapeBottom.getWidth(),
(int) pipeShapeBottom.getHeight());
g.fillRect((int) pipeShapeUp2.getX(), (int) pipeShapeUp2.getY(), (int) pipeShapeUp2.getWidth(),
(int) pipeShapeUp2.getHeight());
g.fillRect((int) pipeShapeBottom2.getX(), (int) pipeShapeBottom2.getY(), (int) pipeShapeBottom2.getWidth(),
(int) pipeShapeBottom2.getHeight());
}
public void move() { // Pipes moves with same v as background v and bird
pipeShapeBottom.setLocation((int) pipeShapeBottom.getX() - bird.getSpeed(), (int) pipeShapeBottom.getY());
pipeShapeUp.setLocation((int) pipeShapeUp.getX() - bird.getSpeed(), (int) pipeShapeUp.getY());
pipeShapeBottom2.setLocation((int) pipeShapeBottom2.getX() - bird.getSpeed(), (int) pipeShapeBottom2.getY());
pipeShapeUp2.setLocation((int) pipeShapeUp2.getX() - bird.getSpeed(), (int) pipeShapeUp2.getY());
}
}
Any help would be appreciated.