Roi Klevasky
Roi Klevasky

Reputation: 25

How to stop flickering in java.awt.graphics?

So i started to learn Java and tried to create a basic pong game using java.awt.graphics. After finishing it i saw that it was a lot of flickering to the point when the game was unplayable. This is my main class named "pong"(What a creative name).

package pong;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class pong extends Applet implements Runnable,KeyListener {
    public static void main(String[] args){}
    public final int W=700,L=500;
    p1 player1;
    p1 player2;
    ball b;
    Thread thread;
    public void init() {
        resize(W,L);
        this.addKeyListener(this);
        player2 = new p1(1);
        b = new ball();
        thread= new Thread(this);
        player1 = new p1(2);
        thread.start();
    }
    public void paint(Graphics g){
        g.setColor(Color.BLACK);
        g.fillRect(0,0,W,L);
        if(!(b.getX()<-10 || b.getX()>690)){
        player1.draw(g);
        b.draw(g);
        player2.draw(g);
        }else if(b.getX()<-10){
            g.setColor(Color.WHITE);
            g.drawString("Right Player Won!",350,250);
        }else{
            g.setColor(Color.WHITE);
            g.drawString("Left Player Won!",350,250);
        }
    }
    @Override
    public void update(Graphics g){
        paint(g);
    }
    public void run() {
        for(;;){
            player1.move();
            player2.move();
            b.move();
            colitionchecker(1);
            repaint();
            try {
                Thread.sleep(17);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void keyTyped(KeyEvent e) {
    }
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_UP)
            player1.setUp(true);
        else if (e.getKeyCode()==KeyEvent.VK_DOWN)
            player1.setDown(true);
        else if(e.getKeyCode()==KeyEvent.VK_W)
            player2.setUp(true);
        else if(e.getKeyCode()==KeyEvent.VK_S)
            player2.setDown(true);
    }
    public void keyReleased(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_UP)
            player1.setUp(false);
        else if (e.getKeyCode()==KeyEvent.VK_DOWN)
            player1.setDown(false);
        else if(e.getKeyCode()==KeyEvent.VK_W)
            player2.setUp(false);
        else if(e.getKeyCode()==KeyEvent.VK_S)
            player2.setDown(false);
    }
    public void colitionchecker(int num){
        if(num == 1){
            if(b.getX()<50 && b.getX()>20 && b.getY()>player2.getY() && 
b.getY()>=player2.getY()-80){
                b.xv=-b.xv;
            }
        else{
                if(b.getX()<700 && b.getX()>660 && b.getY()>=player1.getY() && b.getY()<=player1.getY()+80){
                    b.xv=-b.xv;
                }
            }
        }
    }
}
package pong;
import java.awt.*;
public class p1 implements paddle{
    final double GRAVITY = 0.94;
    double y=210,yv;
    boolean up,down;
    int player,x;
    public p1(int player){
        up=false; down=false;
        if(player==1)
            x=20;
        else
            x=660;
    }
    @Override
    public void draw(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(x, (int)y,20,80);
    }
    public void move() {
        if (up){
            yv -= 2;
        }else if (down){
            yv += 2;
        }else if (!down && !up){
            yv *= GRAVITY;
        }
        if(yv>=15)
            yv=5;
        else if(yv<=-5)
            yv=-5;
        y += yv;
        if(y<=0)
            y=0;
        else if(y>=420)
            y=420;
        }
    public void setUp(boolean up) {
        this.up = up;
    }
    public void setDown(boolean down) {
        this.down = down;
    }
    public int getY() {
        return (int)y;
    }
}

package pong;
import java.awt.*;
public class ball {
    double xv, yv, x, y;
    public ball(){
        x = 350;
        y = 250;
        xv = 2;
        yv = 1;
    }
    public int getY() {
        return (int)y;
    }
    public int getX() {
        return (int)x;
    }
    public void move(){
        x+=xv;
        y+=yv;
        if(y<10)
            yv=-yv;
        if(y>490)
            yv=-yv;
    }

    public void draw(Graphics g){
        g.setColor(Color.WHITE);
        g.fillOval((int)x-10,(int)y-10,20,20);
    }
}
package pong;
import java.awt.*;
public interface paddle {
    public void draw(Graphics g);
    public int getY();
    public void move();
}

I am really lost and any help will be much appreciated. Thanks.

Upvotes: 1

Views: 1138

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347194

So i started to learn Java

So your first lesson is, Applets are dead - better to spend your time else where, either using Swing or JavaFX windows based UIs.

Applet is not double buffered, hence the flicker, both Swing and JavaFX, if used correctly are.

I'd also discourage you from using a Thread in this way, as most GUI frameworks are not thread safe

I'd recommend having a look at:

as a basic starting point

Swing based solution

Because I can do it quickly...

KeyListener is a poor choice which is going to haunt you, better to use the Key Bindings API, which has been designed to overcome its limitations

Things you're going to have to read up on...

And as an overall basic example

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private DefaultPaddle player1;
        private DefaultPaddle player2;
        private Ball b;

        public TestPane() {
            setBackground(Color.BLACK);

            player1 = new DefaultPaddle(1);
            player2 = new DefaultPaddle(2);
            b = new Ball();

            addKeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "Player1.up.pressed", new UpAction(player1, true));
            addKeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "Player1.up.released", new UpAction(player1, false));
            addKeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "Player1.down.pressed", new DownAction(player1, true));
            addKeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "Player1.down.released", new DownAction(player1, false));

            addKeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Player2.up.pressed", new UpAction(player2, true));
            addKeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Player2.up.released", new UpAction(player2, false));
            addKeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Player2.down.pressed", new DownAction(player2, true));
            addKeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Player2.down.released", new DownAction(player2, false));

            Timer timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    player1.move();
                    player2.move();
                    b.move();
//                  colitionchecker(1);
                    repaint();
                }
            });
            timer.start();
        }

        protected void addKeyBinding(KeyStroke ks, String name, Action action) {
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(ks, name);
            am.put(name, action);
        }

        public void colitionchecker(int num) {
            if (num == 1) {
                if (b.getX() < 50 && b.getX() > 20 && b.getY() > player2.getY()
                                && b.getY() >= player2.getY() - 80) {
                    b.xv = -b.xv;
                } else {
                    if (b.getX() < 700 && b.getX() > 660 && b.getY() >= player1.getY() && b.getY() <= player1.getY() + 80) {
                        b.xv = -b.xv;
                    }
                }
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(700, 500);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.BLACK);
//          if (!(b.getX() < -10 || b.getX() > 690)) {
            player1.draw(g);
            b.draw(g);
            player2.draw(g);
//          } else if (b.getX() < -10) {
//              g.setColor(Color.WHITE);
//              g.drawString("Right Player Won!", 350, 250);
//          } else {
//              g.setColor(Color.WHITE);
//              g.drawString("Left Player Won!", 350, 250);
//          }
            g2d.dispose();
        }

    }

    public class UpAction extends AbstractAction {

        private DefaultPaddle paddle;
        private boolean pressed;

        public UpAction(DefaultPaddle paddle, boolean pressed) {
            this.paddle = paddle;
            this.pressed = pressed;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Up " + pressed);
            paddle.setUp(pressed);
        }

    }

    public class DownAction extends AbstractAction {

        private DefaultPaddle paddle;
        private boolean pressed;

        public DownAction(DefaultPaddle paddle, boolean pressed) {
            this.paddle = paddle;
            this.pressed = pressed;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            paddle.setDown(pressed);
        }

    }

    public interface Paddle {

        public void draw(Graphics g);

        public int getY();

        public void move();
    }

    public class DefaultPaddle implements Paddle {

        final double GRAVITY = 0.94;
        double y = 210, yv;
        boolean up, down;
        int player, x;

        public DefaultPaddle(int player) {
            up = false;
            down = false;
            if (player == 1) {
                x = 20;
            } else {
                x = 660;
            }
        }

        @Override
        public void draw(Graphics g) {
            g.setColor(Color.WHITE);
            g.fillRect(x, (int) y, 20, 80);
        }

        public void move() {
            if (up) {
                yv -= 1;
            } else if (down) {
                yv += 1;
            } else if (!down && !up) {
                yv *= GRAVITY;
            }
            if (yv >= 15) {
                yv = 5;
            } else if (yv <= -5) {
                yv = -5;
            }
            y += yv;
            if (y <= 0) {
                y = 0;
            } else if (y >= 420) {
                y = 420;
            }
        }

        public void setUp(boolean up) {
            this.up = up;
        }

        public void setDown(boolean down) {
            this.down = down;
        }

        public int getY() {
            return (int) y;
        }
    }

    public class Ball {

        double xv, yv, x, y;

        public Ball() {
            x = 350;
            y = 250;
            xv = 2;
            yv = 1;
        }

        public int getY() {
            return (int) y;
        }

        public int getX() {
            return (int) x;
        }

        public void move() {
            x += xv;
            y += yv;
            if (y < 10) {
                yv = -yv;
            }
            if (y > 490) {
                yv = -yv;
            }
        }

        public void draw(Graphics g) {
            g.setColor(Color.WHITE);
            g.fillOval((int) x - 10, (int) y - 10, 20, 20);
        }
    }

}

Upvotes: 2

Related Questions