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

Posted

技术标签:

【中文标题】如何在 java.awt.graphics 中停止闪烁?【英文标题】:How to stop flickering in java.awt.graphics? 【发布时间】:2018-12-23 10:20:29 【问题描述】:

所以我开始学习 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();

我真的很迷茫,任何帮助都将不胜感激。 谢谢。

【问题讨论】:

“所以我开始学习 Java” - 所以你的第一课是,Applet 已经死了 - 最好把时间花在其他地方,使用基于 Swing 或 JavaFX windows 的 UI . Applet 不是双缓冲的,因此如果使用正确,Swing 和 JavaFX 都会出现闪烁。我也不鼓励您以这种方式使用Thread,因为大多数 GUI 框架都不是线程安全的 另见Are Java applets worth learning? 忘记小程序、AWT 和 Swing。用于图形JavaFX 库。 【参考方案1】:

于是我开始学习Java

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

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

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

我建议你看看:

Creating a GUI With JFC/Swing Getting Started with JavaFX

作为基本出发点

基于 Swing 的解决方案

因为我可以很快做到……

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

您必须阅读的内容...

2D Graphics How to Use Key Bindings How to Use Swing Timers

作为一个整体的基本示例

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.awt.graphics 中停止闪烁?的主要内容,如果未能解决你的问题,请参考以下文章

内部剪辑与Java图形

Java中的抽象类是如何实例化的?

JAVAWEB项目怎么实现验证码

java生成图片验证码实现

java实现验证码登录

java 图片如何让白色变透明