Applet Flickers even after using using Double Buffering

荒凉一梦 提交于 2020-02-05 04:27:10

问题


I am trying to make a 2 player Pong Applet where the user controls the paddle using mouse.

I have used the concept of Double Buffering, but the Applet still flickers !!! What is the mistake I am committing ?

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.Timer;
import javax.swing.JApplet;

public class Pong extends JApplet implements Runnable, MouseMotionListener {
    Ball ball;
    Paddle left_paddle;
    Paddle right_paddle;
    Image image;
    Graphics DoubleBuffered;

    @Override
    public void init() {
        setSize(800, 600);
        addMouseMotionListener(this);
        setFocusable(true);
        requestFocusInWindow();        
    }

    @Override
    public void start() {
        left_paddle = new Paddle(5, 200, this);
        right_paddle = new Paddle(this.getWidth() - 30, this.getHeight() / 2, this);
        ball = new Ball(100, 100, left_paddle, right_paddle);
        Thread thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {
        while (true) {
            ball.update(this);
            repaint();
            try {
                Thread.sleep(17); //Frame rate of approx 60 FPS
            } catch (InterruptedException ex) {

            }
        }
    }

    @Override
    public void stop() {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void update(Graphics g) {
        if (image == null) {
            image = createImage(this.getWidth(), this.getHeight());
            DoubleBuffered = image.getGraphics();
        }
        DoubleBuffered.setColor(getBackground());
        DoubleBuffered.fillRect(0, 0, this.getWidth(), this.getHeight());

        DoubleBuffered.setColor(getForeground());
        paint (DoubleBuffered);

        DoubleBuffered.drawImage(image, 0, 0, this);
    }

    @Override
    public void paint(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
        ball.paint(g);
        left_paddle.paint(g);
        right_paddle.paint(g);
        g.setColor(Color.BLACK);
        g.drawLine(this.getWidth()/2, 0, this.getWidth()/2, this.getHeight());
    }

    @Override
    public void mouseDragged(MouseEvent e) {
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        int y = e.getY();
        int x = e.getX();
        if (x < this.getWidth()/2) { //Control the left paddle
            if (y < 0) {
                y = 0;
            } else if (y + left_paddle.getHeight() >= this.getHeight()) {
                y = this.getHeight() - left_paddle.getHeight();
            }
            left_paddle.mouse(y);
        }
        else {
            if (y < 0) {
                y = 0;
            } else if (y + right_paddle.getHeight() >= this.getHeight()) {
                y = this.getHeight() - right_paddle.getHeight();
            }
            right_paddle.mouse(y);
        }
    }
}

class Ball {
    private int x;
    private int y;
    private float dx=4;
    private float dy=5;
    private int radius = 10;
    private Paddle left, right;

    Ball(int x, int y, Paddle x1, Paddle y1) {
        this.x = x;
        this.y = y;
        left = x1;
        right = y1;
    }

    public void reset ()
    {
        this.x = 400;
        this.y = 200;
    }

    public void update(Pong ref)
    {
        if (x+dx < left.getX()+left.getWidth()+radius && y+dy+radius >= left.getY() && y+dy+radius <= left.getY()+left.getHeight()) {
            x = left.getX()+left.getWidth()+radius;
            dx *= (-1);
            // checks the left paddle collision
        }
        else if (x+dx+radius >= right.getX() && y+dy+radius >= right.getY() && y+dy+radius <= right.getY()+right.getHeight() ) {
            x = right.getX() - radius;
            dx *= (-1);
            //checks the right paddle collision
        }
        //if ball touches the boundary reset it at middle point
        else if (x+dx+radius >= ref.getWidth()) {
            reset();
        }
        else if (x + dx < radius) {
            reset();
        }
        else {
            x += dx;
        }

        if (y+dy +radius > ref.getHeight()) {
            y = ref.getHeight() - radius - 1;
            dy *= (-1);
        }
        else if (y + dy < radius) {
            y = radius;
            dy *= (-1);
        }
        else {
            y += dy;
        }
    }

    public void paint (Graphics g)
    {
        g.setColor(Color.RED);
        g.fillOval(x-radius, y-radius, 2*radius, 2*radius);
    }

}

class Paddle {

    private int x;
    private int y;
    private int width = 25;
    private int height = 150;
    private Timer timer;

    public Paddle(int x, int y, Pong ref) {
        this.x = x;
        this.y = y;
    }

    public int getHeight() {
        return height;
    }

    public int getWidth() {
        return width;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public void paint (Graphics g)
    {
        g.setColor(Color.BLUE);
        g.fillRect(x, y, width, height);
    }

    //mouse lookup
    void mouse(int y_final)
    {
        y = y_final;
    }
}

回答1:


Generally speaking, you should avoid overriding the paint and update methods of top level containers like JApplet.

You must remember to call super.update, passing it the graphics context which you have created. You must also remember to call super.paint. There is a lot of important functionality going in here that you don't want to skip over.

You should also be disposing of any graphics you create, as they tend to hog memory ;)

But, seen as you're using Swing components anyway, you should create yourself a custom component (from something like JPanel) and use it's paintComponent method.

The main reason for this is, Swing components are double buffered by default...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.Timer;
import javax.swing.JApplet;
import javax.swing.JPanel;

public class Pong extends JApplet {

    private GamePane gamePane;

    @Override
    public void init() {
        setSize(800, 600);
        gamePane = new GamePane();
        setLayout(new BorderLayout());
        add(gamePane);
    }

    @Override
    public void start() {
        gamePane.start();
    }

    @Override
    public void stop() {
    }

    @Override
    public void destroy() {
    }

    public class GamePane extends JPanel implements MouseMotionListener {

        Ball ball;
        Paddle left_paddle;
        Paddle right_paddle;

        public GamePane() {
            setBackground(Color.WHITE);
            addMouseMotionListener(this);
            setFocusable(true);
            requestFocusInWindow();
        }

        public void start() {
            left_paddle = new Paddle(5, 200);
            right_paddle = new Paddle(this.getWidth() - 30, this.getHeight() / 2);
            ball = new Ball(100, 100, left_paddle, right_paddle);
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    ball.update(GamePane.this);
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.

            ball.paint(g);
            left_paddle.paint(g);
            right_paddle.paint(g);
            g.setColor(Color.BLACK);
            g.drawLine(this.getWidth() / 2, 0, this.getWidth() / 2, this.getHeight());

        }

        @Override
        public void mouseDragged(MouseEvent e) {
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            int y = e.getY();
            int x = e.getX();
            if (x < this.getWidth() / 2) { //Control the left paddle
                if (y < 0) {
                    y = 0;
                } else if (y + left_paddle.getHeight() >= this.getHeight()) {
                    y = this.getHeight() - left_paddle.getHeight();
                }
                left_paddle.mouse(y);
            } else {
                if (y < 0) {
                    y = 0;
                } else if (y + right_paddle.getHeight() >= this.getHeight()) {
                    y = this.getHeight() - right_paddle.getHeight();
                }
                right_paddle.mouse(y);
            }
        }
    }

    class Ball {

        private int x;
        private int y;
        private float dx = 4;
        private float dy = 5;
        private int radius = 10;
        private Paddle left, right;

        Ball(int x, int y, Paddle x1, Paddle y1) {
            this.x = x;
            this.y = y;
            left = x1;
            right = y1;
        }

        public void reset() {
            this.x = 400;
            this.y = 200;
        }

        public void update(GamePane ref) {
            if (x + dx < left.getX() + left.getWidth() + radius && y + dy + radius >= left.getY() && y + dy + radius <= left.getY() + left.getHeight()) {
                x = left.getX() + left.getWidth() + radius;
                dx *= (-1);
                // checks the left paddle collision
            } else if (x + dx + radius >= right.getX() && y + dy + radius >= right.getY() && y + dy + radius <= right.getY() + right.getHeight()) {
                x = right.getX() - radius;
                dx *= (-1);
                //checks the right paddle collision
            } //if ball touches the boundary reset it at middle point
            else if (x + dx + radius >= ref.getWidth()) {
                reset();
            } else if (x + dx < radius) {
                reset();
            } else {
                x += dx;
            }

            if (y + dy + radius > ref.getHeight()) {
                y = ref.getHeight() - radius - 1;
                dy *= (-1);
            } else if (y + dy < radius) {
                y = radius;
                dy *= (-1);
            } else {
                y += dy;
            }
        }

        public void paint(Graphics g) {
            g.setColor(Color.RED);
            g.fillOval(x - radius, y - radius, 2 * radius, 2 * radius);
        }
    }

    public class Paddle {

        private int x;
        private int y;
        private int width = 25;
        private int height = 150;
        private Timer timer;

        public Paddle(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int getHeight() {
            return height;
        }

        public int getWidth() {
            return width;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public void paint(Graphics g) {
            g.setColor(Color.BLUE);
            g.fillRect(x, y, width, height);
        }

        //mouse lookup
        void mouse(int y_final) {
            y = y_final;
        }
    }
}


来源:https://stackoverflow.com/questions/15264373/applet-flickers-even-after-using-using-double-buffering

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!