我想实现某种"黑暗",即使像黑色包围的玩家周围的透明形状一样简单,如下所示:
我使用Swing发现的问题是,虽然这是可能的,但这意味着必须重新绘制所有内容,这会产生令人讨厌的"闪烁的"每次发生时效果。有没有办法在Swing中进行某种叠加,或者只是一种很好的方式来做这个?我现在对GUI /视觉资料不是很有经验,所以如果可能的话,我想坚持使用Swing。
编辑:这是我绘制背景的方法,即地板,墙壁和出口:
public final void paintBG(Graphics g){
g.setColor(Color.LIGHT_GRAY); // Screen background
g.fillRect(0, 0, getWidth(), getHeight());
// Draw the Walls of the maze
// scalex and y are for scaling images/walls within the maze since I let users specify how big they want the maze
for (int j = 0; j < this.height; j++, y += scaley) {
x = 20;
for (int i = 0; i < this.width; i++, x += scalex) {
if (!(maze[j][i].northwall.isBroken())) // If the north wall isn't broken
{
g.drawImage(walltile, x, y, scalex, scaley / 5, null); // Draw a wall there (image, xpos, ypos, width, height, observer)
}
if (!(maze[j][i].eastwall.isBroken())) // etc
{
g.drawImage(walltile, x + scalex, y, scalex / 5, scaley, null);
}
if (!(maze[j][i].southwall.isBroken())) {
g.drawImage(walltile, x, y + scaley, scalex, scaley / 5, null);
}
if (!(maze[j][i].westwall.isBroken())) {
g.drawImage(walltile, x, y, scalex / 5, scaley, null);
}
if ((j == mazeinfo.getTargetM()) && (i == mazeinfo.getTargetN())) {
// Draw the exit
g.drawImage(jeep, x + (scalex / 2), y + (scaley / 2), cx, cy, null);
g.setColor(Color.LIGHT_GRAY);
if (maze[j][i].northwall.isEdge()) {
// Paint over the edge creating a 'way out'
g.fillRect(x, y, scalex, scaley / 4);
} else if (maze[j][i].eastwall.isEdge()) {
g.fillRect(x + scalex, y, scalex / 4, scaley);
} else if (maze[j][i].southwall.isEdge()) {
g.fillRect(x, y + scaley, scalex, scaley / 4);
} else if (maze[j][i].westwall.isEdge()) {
g.fillRect(x, y, scalex / 4, scaley);
}
}
}
}
}
然后我有&#34; paintPlayer&#34;和#34; paintEnemy&#34;每次移动时绘制这些精灵的方法。背景只在开始时被绘制一次。
答案 0 :(得分:4)
的可能性:
Graphics#drawImage(...)
绘制BufferedImage。repaint()
,这是永远不应该做的事情。修改
您的代码显示您可能会在每次绘画迭代时重新绘制迷宫 - 不要这样做。而是将上面的内容绘制到BufferedImage中,并在paintComponent方法中绘制该图像。如果墙壁结构发生变化,则更改BufferedImage。
请注意,迷宫的逻辑结构(指示哪个墙是打开的,非关闭的非可视数据)应该是程序数据的一部分,而不是其代码。
答案 1 :(得分:3)
这里是使用Oracle的Swing UI文档中的LayerUI的示例。只需将AlphaComposite常量更改为更暗的颜色。
以下是一个LayerUI子类,可以在鼠标在面板内移动的任何地方绘制半透明圆圈。
class SpotlightLayerUI extends LayerUI<JPanel> {
private boolean mActive;
private int mX, mY;
@Override
public void installUI(JComponent c) {
super.installUI(c);
JLayer jlayer = (JLayer)c;
jlayer.setLayerEventMask(
AWTEvent.MOUSE_EVENT_MASK |
AWTEvent.MOUSE_MOTION_EVENT_MASK
);
}
@Override
public void uninstallUI(JComponent c) {
JLayer jlayer = (JLayer)c;
jlayer.setLayerEventMask(0);
super.uninstallUI(c);
}
@Override
public void paint (Graphics g, JComponent c) {
Graphics2D g2 = (Graphics2D)g.create();
// Paint the view.
super.paint (g2, c);
if (mActive) {
// Create a radial gradient, transparent in the middle.
java.awt.geom.Point2D center = new java.awt.geom.Point2D.Float(mX, mY);
float radius = 72;
float[] dist = {0.0f, 1.0f};
Color[] colors = {new Color(0.0f, 0.0f, 0.0f, 0.0f), Color.BLACK};
RadialGradientPaint p =
new RadialGradientPaint(center, radius, dist, colors);
g2.setPaint(p);
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, .6f));
g2.fillRect(0, 0, c.getWidth(), c.getHeight());
}
g2.dispose();
}
@Override
protected void processMouseEvent(MouseEvent e, JLayer l) {
if (e.getID() == MouseEvent.MOUSE_ENTERED) mActive = true;
if (e.getID() == MouseEvent.MOUSE_EXITED) mActive = false;
l.repaint();
}
@Override
protected void processMouseMotionEvent(MouseEvent e, JLayer l) {
Point p = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), l);
mX = p.x;
mY = p.y;
l.repaint();
}
}
为了让您的播放器更新聚光灯中心,请为玩家移动创建一个事件并注册LayerUI以收听更新。请参阅下面JLayer链接中的setLayerEventMask()
示例。