Как исправить мерцание динамических движущихся изображений над JPanel, поверх другого предварительно окрашенного JPanel? - PullRequest
0 голосов
/ 24 марта 2019

Я сделал 2 JPanels , Panel и BackGround, в JFrame.Я динамически рисую панель через 10 мс (используя таймер), но BackGround окрашивается только один раз в начале игры.Группа отвечает за показ истребителей (космических кораблей), снарядов и инопланетян.BackGround отвечает за отображение фоновой сцены, которая не является динамической.Метод paintComponent (Graphics) действительно рисует истребители и снаряды, но мерцает при их обновлении.Может кто-то найти причину.

Это моя рамка:

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Frame extends JFrame {
    private static final long serialVersionUID = 1L;

    public static final int WIDTH = 1280;
    public static final int HEIGHT = 720;

    public static final int DELAY = 10;

    private Panel panel;
    private Background bg;

    public Frame() {

        panel = new Panel();
        bg = new Background();

        initComponents();
    }

    public void initComponents() {

        this.setSize(WIDTH, HEIGHT);

        this.add(bg);
        this.add(panel);

        this.setLocationRelativeTo(null);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_LEFT) panel.moveLeft();
                else if(e.getKeyCode() == KeyEvent.VK_RIGHT) panel.moveRight();
            }

        });

    }

    public static void main(String args[]) {

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Frame().setVisible(true);
            }
        });

    }

}

Это моя панель:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Panel extends JPanel implements ActionListener {
    private static final long serialVersionUID = 1L;

    public static final int DELAY = Frame.DELAY;

    private Timer timer;
    private BufferedImage fighter;

    int x, y;

    public Panel() {

        timer = new Timer(DELAY, this);
        try {
            fighter = ImageIO.read(this.getClass().getResource("fighter.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        initComponents();

        timer.start();
    }

    public void initComponents() {

        this.setSize(Frame.WIDTH, Frame.HEIGHT);
        this.setDoubleBuffered(true);
        this.setBackground(new Color(0, 0, 0, 0));

        x = 150;
        y = 200;

    }


    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;
        doDrawing(g2d);

    }



    private void doDrawing(Graphics2D g2d) {

        g2d.drawImage(fighter, x, y, null);

    }

    @Override
    public void actionPerformed(ActionEvent arg0) {

        this.repaint();
    }

    public void moveLeft() {
        x -= 10;
    }

    public void moveRight() {
        x += 10;
    }

}

Это фон:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;
import javax.swing.Timer;


public class Background extends JPanel implements ActionListener{
    private static final long serialVersionUID = 1L;

    private BufferedImage backGround;
    private Timer timer;
    public Background() {

        this.setSize(Frame.WIDTH, Frame.HEIGHT);
        this.setBackground(new Color(0, 0, 0, 0));

        timer = new Timer(Frame.DELAY, this);

        try {
            backGround = ImageIO.read(this.getClass().getResource("background.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        timer.start();

    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.drawImage(backGround, 0, 0, null);

    }

    @Override
    public void actionPerformed(ActionEvent e) {

        this.repaint();

    }

}

Я ожидаю, что спрайты не будут мерцать и не будут отставать (что не происходит после многих испытаний).

1 Ответ

1 голос
/ 24 марта 2019
  1. Не вызывать перерисовку в методе рисования
  2. Избавиться от класса Background и выполнить все рисование в one JPanel.Например:
  3. См. Пример ниже, а также дизайн MCVE
    • Все это можно скопировать / вставить в IDE и запустить
    • , используя изображения, доступные для всех онлайн,не на диске
  4. Я также удалил бы Таймер, который просто вызывает repaint(), и вместо этого либо
    • вызовите перерисовку из KeyListener
    • , либо используйтетаймер для выполнения действительного кода движения спрайта (с repaint()).Это было бы полезно, если вы хотите непрерывное движение

Пример MCVE:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;

public class Frame1 extends JFrame {
    // Image attribution:
    // By Adam Evans - M31, the Andromeda Galaxy (now with h-alpha)
    // Uploaded by NotFromUtrecht, CC BY 2.0,
    // https://commons.wikimedia.org/w/index.php?curid=12654493
    public static final String ANDROMEDA_IMAGE = "https://upload.wikimedia.org/wikipedia/commons/"
            + "thumb/9/98/Andromeda_Galaxy_%28with_h-alpha%29.jpg/"
            + "1280px-Andromeda_Galaxy_%28with_h-alpha%29.jpg";
    public static final String SPRITE_IMAGE = "https://upload.wikimedia.org/wikipedia/commons/"
            + "thumb/a/a1/Glossy_3d_blue_blue2.png/" + "120px-Glossy_3d_blue_blue2.png";

    private static final long serialVersionUID = 1L;
    public static final int WIDTH = 1280;
    public static final int HEIGHT = 720;
    public static final int DELAY = 10;
    private Panel1 panel;
    // private Background bg;

    public Frame1() {
        panel = new Panel1();
        // bg = new Background();
        initComponents();
    }

    public void initComponents() {
        this.setSize(WIDTH, HEIGHT);
        // this.add(bg);
        this.add(panel);
        this.setLocationRelativeTo(null);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_LEFT)
                    panel.moveLeft();
                else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
                    panel.moveRight();
            }
        });
    }

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Frame1().setVisible(true);
            }
        });
    }
}

class Panel1 extends JPanel implements ActionListener {
    private static final long serialVersionUID = 1L;
    public static final int DELAY = Frame1.DELAY;
    private Timer timer;
    private BufferedImage fighter;
    private BufferedImage background;
    int x, y;

    public Panel1() {
        timer = new Timer(DELAY, this);
        try {
            URL url = new URL(Frame1.SPRITE_IMAGE);
            // fighter = ImageIO.read(this.getClass().getResource("fighter.png"));
            fighter = ImageIO.read(url);

            url = new URL(Frame1.ANDROMEDA_IMAGE);
            background = ImageIO.read(url);

        } catch (IOException e) {
            e.printStackTrace();
        }
        initComponents();
        timer.start();
    }

    public void initComponents() {
        this.setSize(Frame1.WIDTH, Frame1.HEIGHT);
        this.setDoubleBuffered(true);
        this.setBackground(new Color(0, 0, 0, 0));
        x = 150;
        y = 200;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(background, 0, 0, this);
        g.drawImage(fighter, x, y, this);
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        this.repaint();
    }

    public void moveLeft() {
        x -= 10;
    }

    public void moveRight() {
        x += 10;
    }
}
...