清除底层图像的图形部分 [英] Clear portion of graphics with underlying image
问题描述
我正在做一个游戏,其中玩家必须点击在屏幕上弹跳的图像。抓住的是屏幕在黑暗中,鼠标光标是一个手电筒,它点亮了一个小圆周围。
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, usepaintComponent
,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 ajavax.swing.Timer
to regulate when the model is updated and simply callrepaint
- 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 inpaintXxx
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屋!