3

I'm coding a simple 2D maze game where you go through many rooms. I want to make it a bit challenging by limiting the view of the player. At first I thought of replacing the default mouse icon within the frame to a translucent PNG ellipse, but then I realized I needed to block out what's around it.

The only way I could think of doing this was to make the mouse pointer icon an image that is bigger than the frame (so when the user moves to a corner it would still be black) filling it in and then placing the clear-faded ellipse in the area of the pointer.

What I want to know is, is this possible, and how would I go about doing this? I'm learning java so examples and oracle documents will help me a lot. Thanks in advance!

As seen from here and this link (it takes a while to load) PS: I'm using eclipse.

enter image description here

gtgaxiola
  • 9,241
  • 5
  • 42
  • 64
SelfDeceit
  • 107
  • 1
  • 2
  • 13
  • Of course it possible, I personal would essentially create a gradient from the position of the mouse emanating outward that would darken each pixel gradually and black after a certain distance from the x,y pos of the mouse, there' probably a more efficient soltuion – SGM1 Mar 18 '13 at 23:31
  • 2
    [What have you tried?](http://mattgemmell.com/2008/12/08/what-have-you-tried/) – Zach Latta Mar 18 '13 at 23:33
  • @zachlatta LOL, love the link – SGM1 Mar 18 '13 at 23:34
  • Well, I'm not familiar with Mouse Listeners and Mouse Event Listeners. So I'm not sure where I would even start, let alone starting to code. I know how to use regular Action Listeners though, so I'd assume they aren't too different. – SelfDeceit Mar 18 '13 at 23:35
  • @SelfDeceit Familiar with [Javadoc 6](http://docs.oracle.com/javase/6/docs/api/) or [Javadoc 7](http://docs.oracle.com/javase/7/docs/api/)? Personally feel 6 is better documentation. You can answer everything about the Event Listners here. – SGM1 Mar 18 '13 at 23:39
  • 2
    Why not try playing around with them if you haven't used them before? I'm sure you can find an [example](http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html) somewhere online. Learning to program is all about experimentation. Don't be afraid to break things! – Zach Latta Mar 18 '13 at 23:40
  • Well I was hoping to find someone with experience with Mouse Events and post a small example. I don't want anyone to code the full class. I just want to know how I would go about changing the mouse icon to carry out this task. – SelfDeceit Mar 18 '13 at 23:46

2 Answers2

8

So you've identified the basic requirements.

  • You need a mouse listener to monitor the movements of the mouse, so you can update the position of the spot light. Take a read through how to write a mouse listener
  • You need to render the spot light effect over the image

The following example basically uses a RadialGradientPaint to paint a "spotlight" over an image. It uses a MouseMoitionListener to monitor the position of the mouse and updates the spotlight as you go.

enter image description here

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();
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thanks for the example! I'm still reading through it, both examples seem very helpful. – SelfDeceit Mar 19 '13 at 01:04
  • I've decided that this one was easier to apply to my applet but both answers were helpful. This is just the one I decided to use. PS: I love the Wall-E Image! Do you know the artists name? – SelfDeceit Mar 19 '13 at 01:28
5

What you are looking for is more commonly known as a "Spotlight" effect. You will need to use a JLayer, as this tutorial explains.

Here is the code excerpt from the tutorial:

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

I suggest reading the entire tutorial on Swing so you understand how listeners work and basically how this entire code works.

Atif
  • 942
  • 1
  • 6
  • 19