java - 如何停止 java.awt.graphics 中的闪烁?

标签 java multithreading graphics awt

所以我开始学习 Java 并尝试使用 java.awt.graphics 创建一个基本的乒乓游戏。 完成后我发现它有很多闪烁,以至于游戏无法玩。 这是我的主类,名为“pong”(多么有创意的名字)。

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();
}

我真的很迷茫,非常感谢任何帮助。 谢谢。

最佳答案

So i started to learn Java

所以你的第一课是,Applet 已经死了 - 最好把时间花在其他地方,无论是使用 Swing 或 JavaFX 基于 Windows 的 UI。

Applet 不是双缓冲的,因此如果使用正确的话,Swing 和 JavaFX 都会出现闪烁。

我也不鼓励您以这种方式使用Thread,因为大多数 GUI 框架都不是线程安全的

我建议您查看:

作为基本起点

基于 Swing 的解决方案

因为我可以很快完成...

KeyListener 是一个糟糕的选择,它会困扰你,最好使用 Key Bindings API,它旨在克服其局限性

您必须阅读的内容...

作为一个整体的基本示例

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);
        }
    }

}

关于java - 如何停止 java.awt.graphics 中的闪烁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51352161/

相关文章:

java - 将消息放入集群队列

c# - 如何减少后台工作程序中使用匿名管道的程序的 CPU 使用率?

graphics - 标准化设备坐标

java - JTextPane 中未呈现 CSS 填充

java - 包含带有来自 servlet 的错误重定向的 jsp 页面

multithreading - 如果没有数据等待,从 mpsc::channel 获取数据而不锁定

ios - OS X 是否限制辅助线程的内存使用?

c# - 点在 3D 线上的投影

java - OpenGL:模型显示不正确。 (需要固定绘制距离吗?)

java - JSP简单密码加密解密