清除底层图像的图形部分 [英] Clear portion of graphics with underlying image

查看:240
本文介绍了清除底层图像的图形部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个游戏,其中玩家必须点击在屏幕上弹跳的图像。抓住的是屏幕在黑暗中,鼠标光标是一个手电筒,它点亮了一个小圆周围。

I'm making a 'game' of sorts where the player has to click on an image bouncing around the screen. The catch is that the screen is in darkness and the mouse cursor is a 'flashlight' which 'light up' a small circle around it.

我有一个 JFrame 在一个类中组成:

I have a JFrame in one class consisting of:

public class GameFrame {

public static void main(String[] args) throws IOException {

    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    JFrame jf = new JFrame("Flashlight Game");
    jf.setVisible(true);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jf.setSize(d);
    jf.setLocationRelativeTo(null);
    GamePanel gp = new GamePanel();
    jf.add(gp);
}

}

我有另一个类 extends JPanel 。以下是与我的问题相关的字段:

I have another class which extends JPanel. Here are its fields relevant to my problems:

private Point mouse; //location set by a MouseMotionListener
private BufferedImage myImage;
private int imageX;
private int imageY;
private int imageSpeedX;
private int imageSpeedY;

我的第一个问题在于手电筒。在我的 paint 方法中,我将图形背景颜色设置为面板背景颜色,并使用 clearRect 方法清除

My first problem lies in the flashlight. In my paint method, I set the graphics background color to the panel background color and use the clearRect method to clear an area around the mouse cursor.

public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    super.paint(g2);
    checkBounce();
    move();
    g2.drawImage(myImage, imageX, imageY, null);
    g2.setColor(Color.BLACK);
    g2.fillRect(0, 0, this.getWidth(), this.getHeight());
    g2.setBackground(Color.WHITE);
    g2.clearRect((int) mouse.getX() - 25, (int) mouse.getY() - 25, 50, 50);
    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    repaint();
}

这里实际上有两个问题。
1.)我如何创建一个 clearOval 效果,因为手电筒不会照在矩形中,
2.)我如何获得弹出的图像通过手电筒光束显示出来?我知道调用 g2.setBackground(Color.WHITE)将使用设置的颜色作为背景的清除区域,但我需要一种方法来清除所有图形

There are actually two problems here. 1.) How can I create a clearOval effect since a flashlight doesn't shine in a rectangle, and 2.) How can I get the bouncing image to show up through the flashlight beam? I know that calling g2.setBackground(Color.WHITE) will use the set color as the 'background' for the cleared area, but I need a way to clear all graphics except for the backmost JFrame or JPanel background color.

推荐答案

基本思想是创建一个 Rectangle ,创建一个 Ellipse2D 作为hole或spot light,并从<$ c减去 Ellipse2D $ c> Rectangle ,以便在其中创建一个洞,然后绘制它。

The basic idea is to create a Rectangle big enough to cover the component, create a Ellipse2D to act as the "hole" or "spot light" and subtract the Ellipse2D from Rectangle so as to create a hole in it, then paint it.


  • paint 在可能的地方使用 paintComponent paint $ 你应该避免在任何 paintXxx 方法。油漆可以因为任何数量的原因,许多其中你不会实例化。这可能是你的模型状态进入不一致的状态。相反,你应该使用 javax.swing.Timer 来调节模型的更新时间,只需调用 repaint

  • 不要调用 Thread.sleep Threasd.wait 在事件分派线程的上下文中执行任何类型的长运行循环或I / O操作。 Swing是一个单线程环境。也就是说,UI和事件处理的所有更新都是在单个线程内完成的。如果您执行任何阻止EDT的操作,它将无法处理这些事件并更新UI,直到您停止阻止...

  • 不要调用重绘或任何可能在 paintXxx 方法中调用重绘的方法。这将使你的程序陷入死亡螺旋,将看到它消耗你的CPU ...

  • You should avoid overridding paint where possible and instead, use paintComponent, paint tends to be to high in the paint chain and comes with a number of complications which are best avoided
  • You should avoid changing the state the state of your component or model within any paintXxx method. Paint can be called for any number of reasons, many of which you won't instantiate. This could be putting your models state into a inconsistent state. Instead, you should using something like a javax.swing.Timer to regulate when the model is updated and simply call repaint
  • Don't ever call Thread.sleep, Threasd.wait or perform any kind of long running loop or I/O operation within the context of the Event Dispatching Thread. Swing is a single threaded environment. That is, all the updates to the UI and event processing are done from within a single thread. If you do anything that blocks the EDT, it will be unable to process these events and update the UI until you stop blocking...
  • Don't call repaint or any method that might invoke a repaint from within in paintXxx method. This will place your program into a spiral of death that will see it consume your CPU...

有关更多详情, at ...

For more details, take a look at...

  • Performing Custom Painting
  • Concurrency in Swing

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Spotlight {

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

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

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

    public class TestPane extends JPanel {

        public static final int RADIUS = 80;

        private BufferedImage img;
        private Point mousePoint;

        public TestPane() {
            try {
                img = ImageIO.read(new File("C:\\hold\\thumbnails\\Rampage_Small.png"));
            } catch (IOException ex) {
                Logger.getLogger(Spotlight.class.getName()).log(Level.SEVERE, null, ex);
            }

            addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    mousePoint = e.getPoint();
                    repaint();
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (img != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
                g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

                int x = (getWidth() - img.getWidth()) / 2;
                int y = (getHeight() - img.getHeight()) / 2;

                g2d.drawImage(img, x, y, this);

                x = mousePoint == null ? getWidth() / 2 : mousePoint.x;
                y = mousePoint == null ? getHeight() / 2 : mousePoint.y;

                Rectangle rect = new Rectangle(0, 0, getWidth(), getHeight());
                Ellipse2D spot = new Ellipse2D.Float(
                        (float) x - (RADIUS / 2f),
                        (float) y - (RADIUS / 2f),
                        (float) RADIUS,
                        (float) RADIUS);

                Area area = new Area(rect);
                area.subtract(new Area(spot));

                g2d.setColor(Color.BLACK);
                g2d.fill(area);

                g2d.dispose();
            }
        }
    }

}

这篇关于清除底层图像的图形部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆