-1

我正在创建一个游戏,我有两个类正在监听事件。我有一个在 the 上Menu监听 s 的类和一个在自身上监听s、s 和s 的类。当菜单关闭时,变量被设置并被阻止执行任何操作。像这样:ActionEventJFrame.getContentpane() ContainerInputManagerKeyEventMouseEventMouseWheelEventJFrameblocked

private boolean blocked;

public void actionPerformed(ActionEvent e)
{
    if (!blocked)
    {
        // Do stuff
    }
}

public void blockActionEvents(boolean blocked)
{
    this.blocked = blocked;
}

也是InputManager畅通的,因此游戏可以监听任何(鼠标、按键、鼠标滚轮)事件并执行相应的GameAction.

问题是,actionPerformed当在先前隐藏的按钮所在的区域单击时,该功能仍然会吃掉我的所有事件。我怎样才能很好地解决这个问题?

编辑 SSCCE: 对于一个完整的工作示例(Java 的 400 行以下),请下载我的示例项目下载链接(如果出现任何问题,请报告):http ://wikisend.com/download/307016/jLevel.zip 您可以使用如果您愿意,可以提供 makefile(我还附上了一个编译版本)。游戏可以使用run.bash文件运行(Windows用户必须手动运行,用法:java GameMain [屏幕宽度] [屏幕高度] [位深度])。

现在如何复制问题:

  • 从控制台运行游戏
  • 您可以单击一下(不是在按钮上!),您不会在控制台中看到任何消息。
  • 现在单击Resume game按钮。以下消息发布到控制台:ActionEvent caught in Menu class。这很好。
  • 现在只需单击一下,每次单击您都会收到消息:MouseEvent caught in InputManager class. 这也很好。
  • 现在,还记得按钮的位置吗?点击那里没有消息出现,它们仍然被类actionPerformed()中的函数捕获Menu。问题基本上是我如何将这些消息传递给我的InputManager班级,以便它们可以在游戏中使用。

按钮将在 10 秒后恢复,因此您可以使用该Exit game按钮关闭应用程序。

如果您不想下载,可以从此处复制粘贴所需的文件

GameMain.java

import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.DisplayMode;
import javax.swing.JFrame;


public final class GameMain extends JFrame
{
    public long ticker = 0;

    public static ScreenManager screenManager;

    // Managing keyboard and mouse input
    public static InputManager inputManager;
    // Main menu
    public static Menu mainMenu;


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


    private GameMain(String[] args)
    {
        DisplayMode displayMode = new DisplayMode(Integer.parseInt(args[0]) /* width */,
                              Integer.parseInt(args[1]) /* heigth */,
                              Integer.parseInt(args[2]) /* bit depth */,
                              DisplayMode.REFRESH_RATE_UNKNOWN /* refresh rate */);

        screenManager = ScreenManager.getInstance();
        if (!screenManager.setFullScreen(displayMode, this));
        // Prevent Swing from drawing its own components
        RepaintManagerResetter.resetRepaintManager();

        mainMenu = new Menu(false);
        inputManager = InputManager.createInstance(screenManager.getFullScreenWindow());

        for (;;)
        {
            if (ticker % 200 == 0) // Bring buttons back
            {
                mainMenu.blockActionEvents(false);
                inputManager.setBlocking(true);
            }

            Graphics2D screenGraphics = screenManager.getGraphics();
            draw(screenGraphics);
            screenGraphics.dispose();
            screenManager.updateGraphicsDisplay();
            try { Thread.sleep(50); ++ticker;} catch (Exception ex){}
        }
    }

    // Draw game game graphics
    private void draw(Graphics g)
    {
        g.clearRect(0, 0, screenManager.getWidth(), screenManager.getHeight());

        // Draw
        if (showMainMenu())
        {
            mainMenu.drawComponents(g);
        }
        else
        {
            // Draw game
            g.drawString("Do interesting stuff", 200, 200);
        }
    }

    public static boolean showMainMenu()
    {
        return !mainMenu.isBlocked();
    }
}

ScreenManager.java

import java.awt.*;
import javax.swing.JFrame;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;


public class ScreenManager
{
    private static ScreenManager screenManager;

    private GraphicsDevice graphicsDevice;


    protected ScreenManager()
    {
        GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
        graphicsDevice = graphicsEnvironment.getDefaultScreenDevice();
    }


    public static ScreenManager getInstance()
    {
        if (screenManager == null)
        {
            screenManager = new ScreenManager();
        }
        return screenManager;
    }


    public boolean setFullScreen(DisplayMode displayMode, JFrame hwnd)
    {
        hwnd.setUndecorated(true);
        hwnd.setResizable(true);
        hwnd.setVisible(true);
        hwnd.setIgnoreRepaint(true);

        graphicsDevice.setFullScreenWindow(hwnd);

        if (displayMode != null && graphicsDevice.isDisplayChangeSupported())
        {
            try
            {
                graphicsDevice.setDisplayMode(displayMode);
            }
            catch (IllegalArgumentException ex)
            {
                System.out.println("WARNING: Could not set the screen to desired display mode: " + ex.getMessage());
            }
        }
        else
        {
            System.out.println("ERROR: Accessing graphics device failed.");
            return false;
        }

        /* Create buffer strategy for the window */
        hwnd.createBufferStrategy(2);

        return true;
    }


    public DisplayMode[] getDisplayModes()
    {
        return graphicsDevice.getDisplayModes();
    }


    public Window getFullScreenWindow()
    {
        return graphicsDevice.getFullScreenWindow();
    }


    public BufferStrategy getBufferStrategy()
    {
        return getFullScreenWindow().getBufferStrategy();
    }


    public Graphics2D getGraphics()
    {
        return (Graphics2D) getBufferStrategy().getDrawGraphics();
    }


    public int getWidth()
    {
        return getFullScreenWindow().getWidth();
    }


    public int getHeight()
    {
        return getFullScreenWindow().getHeight();
    }


    public void updateGraphicsDisplay()
    {
        BufferStrategy bufferStrategy = getBufferStrategy();
        if (!bufferStrategy.contentsLost())
        {
            bufferStrategy.show();
        }

        Toolkit.getDefaultToolkit().sync();
    }
}

Menu.Java

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Menu implements ActionListener
{
    protected boolean blocked;

    protected ScreenManager screenManager;
    protected JFrame menuWindow;
    protected Container contentPane;

    private JPanel panel = new JPanel();
    private JButton startButton;
    private JButton stopButton;


    public Menu(boolean blocked)
    {
        this.blocked = blocked;

        screenManager = GameMain.screenManager;
        menuWindow = (JFrame) screenManager.getFullScreenWindow();

        /* Make sure content pane is transparent */
        contentPane = menuWindow.getContentPane();
        if (contentPane instanceof JComponent)
        {
            ((JComponent) contentPane).setOpaque(false);
        }

        contentPane.setLayout(new FlowLayout(FlowLayout.CENTER, 50, screenManager.getHeight() / 2));

        startButton = createGUIButton("Resume game");
        stopButton = createGUIButton("Exit game");
        panel.add(startButton);
        panel.add(stopButton);
        contentPane.add(panel);

        menuWindow.validate();
    }


    public void actionPerformed(ActionEvent e)
    {
        if (!blocked)
        {
            Object source = e.getSource();

            if (stopButton == (JButton) source)
            {
                System.exit(0);
            }
            else if (startButton == (JButton) source)
            {
                blockActionEvents(true);
                GameMain.inputManager.setBlocking(false);
            }
            System.out.println("ActionEvent caught in Menu class");
        }
    }


    public void drawComponents(Graphics g)
    {
        menuWindow.getLayeredPane().paintComponents(g);
    }


    protected JButton createGUIButton(String text)
    {
        /* Set button attributes */
        JButton button = new JButton(text);
        button.addActionListener(this);
        button.setIgnoreRepaint(true);
        button.setFocusable(false);
        button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        return button;
    }


    public void blockActionEvents(boolean blocked)
    {
        this.blocked = blocked;
    }


    public boolean isBlocked()
    {
        return blocked;
    }
}

RepaintManagerResetter.java

import javax.swing.RepaintManager;
import javax.swing.JComponent;

public class RepaintManagerResetter extends RepaintManager
{
    public static void resetRepaintManager()
    {
        RepaintManager repaintManager = new RepaintManagerResetter();
        repaintManager.setDoubleBufferingEnabled(false);
        repaintManager.setCurrentManager(repaintManager);
    }


    public void addInvalidComponent(JComponent c)
    {
    }

    public void addDirtyRegion(JComponent c, int x, int y, int w, int h)
    {
    }

    public void markCompletelyDirty(JComponent c)
    {
    }

    public void paintDirtyRegions()
    {
    }
}

InputManager.java

import java.awt.*;
import java.awt.event.*;

public class InputManager implements KeyListener, MouseListener
{
    private static InputManager inputManager;
    private boolean blocking;

    private Component inputManagerComponent;


    protected InputManager(Component inputManagerComponent)
    {
        this.inputManagerComponent = inputManagerComponent;

        /* Register listeners */
        inputManagerComponent.addKeyListener(this);
        inputManagerComponent.addMouseListener(this);
        inputManagerComponent.setFocusTraversalKeysEnabled(false);
    }


    public static InputManager createInstance(Component inputManagerComponent)
    {
        if (inputManager == null)
        {
            inputManager = new InputManager(inputManagerComponent);
        }
        return inputManager;
    }


    public boolean isBlocking()
    {
        return blocking;
    }


    public void setBlocking(boolean blocking)
    {
        this.blocking = blocking;
    }


    public static InputManager getInstance()
    {
        return inputManager;
    }


    /****** Keyboard events ******/

    public void keyPressed(KeyEvent e)
    {
        if (blocking) return;
        // Do stuff
        e.consume();
    }


    public void keyReleased(KeyEvent e)
    {
        if (blocking) return;
        // Do stuff
        e.consume();
    }


    public void keyTyped(KeyEvent e)
    {
        if (blocking) return;
        // Do stuff
        e.consume();
    }



    /****** Mouse events ******/

    public void mousePressed(MouseEvent e)
    {
        if (blocking) return;
        // Do stuff
        e.consume();
    }


    public void mouseReleased(MouseEvent e)
    {
        if (blocking) return;
        // Do stuff
        e.consume();
    }


    public void mouseClicked(MouseEvent e)
    {
        if (blocking) return;
        // Do stuff
        System.out.println("MouseEvent caught in InputManager class");
        e.consume();
    }



    public void mouseEntered(MouseEvent e)
    {
    }

    public void mouseExited(MouseEvent e)
    {
    }
}

makefile

PROJECTNAME = test
CC = javac
CLASS_FILES = GameMain.class ScreenManager.class InputManager.class Menu.class RepaintManagerResetter.class


jLevel: $(CLASS_FILES)
    @echo Done.

%.class : %.java
    @echo Compiling $*.java to $@ [command: $(CC) $*.java ] ...
    $(CC) -source 6 -Xlint:unchecked $*.java

clean:
    @rm $(CLASS_FILES)
    @echo Cleaned...

run.bash

#!/bin/bash
STARUP_CLASS="GameMain"
ARGUMENTS="1280 1024 -1"
java $STARUP_CLASS $ARGUMENTS
4

1 回答 1

1

我对该类进行了简单的修改,Menu如下所示:

public class Menu implements ActionListener
{
    ...

    public Menu(boolean blocked)
    {
        // this.blocked = blocked;

        ...

        startButton = createGUIButton("Resume game");
        stopButton = createGUIButton("Exit game");
        panel.add(startButton);
        panel.add(stopButton);
        // contentPane.add(panel);

        // menuWindow.validate();
        blockActionListeners(blocked); // added this line
    }

    ...

    public void blockActionEvents(boolean blocked)
    {
        this.blocked = blocked;
        if (blocked) {  // added from here...
                contentPane.remove(panel);
                menuWindow.validate();
        } else {
                contentPane.add(panel);
                menuWindow.validate();
        } // to here
    }

    ...
}

添加的行由注释指示,删除的行被简单地注释掉。

这种修改只是在按钮应该不可见时将其删除,而不是仅仅不绘制它们。如果您只是不绘制它们,事件仍将转到按钮。我测试了这个解决方案,它可以工作。

于 2013-07-22T00:44:44.683 回答