-1

私はゲームを作成しており、イベントをリッスンする 2 つのクラスがあります。上で sをリッスンするMenuクラスと、それ自体で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 の編集: 完全な動作例 (400 行以下の Java) については、サンプル プロジェクトのダウンロード リンクをダウンロードしてください (問題が発生した場合は報告してください) : 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 に答える