【问题标题】:Java Mouse "Flashlight" effect?Java鼠标“手电筒”效果?
【发布时间】:2013-03-18 23:26:36
【问题描述】:

我正在编写一个简单的 2D 迷宫游戏,您可以在其中穿过许多房间。我想通过限制玩家的视角让它变得有点挑战性。起初我想将框架内的默认鼠标图标替换为半透明的 PNG 椭圆,但后来我意识到我需要屏蔽掉它周围的东西。

我能想到的唯一方法是让鼠标指针图标成为比框架更大的图像(所以当用户移动到角落时它仍然是黑色的)填充它然后放置清除- 指针区域中的淡化椭圆。

我想知道的是,这是否可能,我将如何去做?我正在学习 java,所以示例和 oracle 文档会对我有很大帮助。提前致谢!

从这里和这个link 看到(加载需要一段时间) PS:我正在使用 eclipse。

【问题讨论】:

  • 当然有可能,我个人基本上会从鼠标的位置创建一个向外发出的渐变,在距离鼠标的 x,y 位置一定距离后,每个像素会逐渐变暗并变黑,可能有更有效的解决方案
  • @zachlatta LOL,喜欢这个链接
  • 好吧,我不熟悉鼠标监听器和鼠标事件监听器。所以我什至不确定我会从哪里开始,更不用说开始编码了。不过我知道如何使用常规的动作监听器,所以我认为它们并没有太大的不同。
  • 如果您以前没有使用过它们,为什么不尝试使用它们呢?我相信您可以在网上某处找到example。学习编程就是实验。不要害怕破坏东西!

标签: java swing mouseevent


【解决方案1】:

所以你已经确定了基本要求。

  • 您需要一个鼠标监听器来监控鼠标的移动,这样您就可以更新聚光灯的位置。阅读how to write a mouse listener
  • 您需要在图像上渲染聚光灯效果

以下示例基本上使用RadialGradientPaint 在图像上绘制“聚光灯”。它使用MouseMoitionListener 来监控鼠标的位置并在您移动时更新聚光灯。

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.Paint;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MouseCover {

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

    public MouseCover() {
        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 static class TestPane extends JPanel {

        public static final int RADIUS = 200;
        private Point mousePoint = null;
        private BufferedImage background;

        public TestPane() {

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

                @Override
                public void mouseExited(MouseEvent e) {
                    mousePoint = null;
                    repaint();
                }
            };

            addMouseMotionListener(mouseHandler);
            addMouseListener(mouseHandler);
            try {
                background = ImageIO.read(...);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            if (background != null) {
                int x = (getWidth() - background.getWidth()) / 2;
                int y = (getHeight() - background.getHeight()) / 2;
                g2d.drawImage(background, x, y, this);
            }

            Paint paint = Color.BLACK;
            if (mousePoint != null) {
                paint = new RadialGradientPaint(
                        mousePoint,
                        RADIUS,
                        new float[]{0, 1f},
                        new Color[]{new Color(0, 0, 0, 0), new Color(0, 0, 0, 255)});
            }

            g2d.setPaint(paint);
            g2d.fillRect(0, 0, getWidth(), getHeight());

            g2d.dispose();
        }
    }
}

【讨论】:

  • 感谢您的示例!我还在通读它,这两个例子似乎都很有帮助。
  • 我认为这个更容易应用于我的小程序,但两个答案都很有帮助。这只是我决定使用的一个。 PS:我喜欢 Wall-E Image!你知道艺术家的名字吗?
【解决方案2】:

您要寻找的通常称为“聚光灯”效果。正如tutorial 解释的那样,您将需要使用 JLayer。

这是教程的代码摘录:

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();
  }
}

我建议阅读 Swing 上的 entire tutorial,以便了解侦听器的工作原理以及整个代码的基本工作原理。

【讨论】:

  • 抱歉回复太长了!我目前正在查看这两个示例,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
相关资源
最近更新 更多