用鼠标而不是键盘选择按钮

时间:2017-06-11 17:25:49

标签: java button menu

您好我为我的游戏制作了一个暂停菜单,您可以使用键盘上的箭头键浏览它。我的问题是如何制作它以便我可以用鼠标导航,然后单击按钮而不必使用箭头键?

这是代码:

public class InGameMenu implements KeyListener {

private String[] string = { "Resume Game", "Options", "Save Game", "Load Game", "Exit Game" };
private String[] optionStrings = { "Help", "Back" };

public static int selected = 0;
private int space = 25;

public int width = 800;
public int height = 600;

public static boolean isInMenu = true;
public static boolean isInOptions = false;
public static boolean saving = false;
public static boolean loading = false;

public InGameMenu() {

}

public void tick() {

}

public void render(Graphics g) {

    g.setColor(new Color(0, 0, 0, 90));
    g.fillRect(0, 0, Component.width, Component.height);
    if (isInMenu) {
        g.setColor(Color.LIGHT_GRAY);
        if (saving) {
            g.drawString("Saving", Component.width / 2 / Component.pixelSize - (int) (Component.width / 25), 35);
        }
        if (loading) {
            g.drawString("Loading", Component.width / 2 / Component.pixelSize - (int) (Component.width / 25), 35);
        }

        for (int i = 0; i < string.length; i++) {
            if (selected == i) {
                g.setColor(Color.RED);
            } else {
                g.setColor(Color.WHITE);
            }
            g.drawString(string[i], Component.width / 2 / Component.pixelSize - (int) (Component.width / 17.5), Component.height / 8 + (i * space));
        }
    } else if (isInOptions) {
        for (int i = 0; i < optionStrings.length; i++) {
            if (selected == i) {
                g.setColor(Color.RED);
            } else {
                g.setColor(Color.WHITE);
            }
            g.drawString(optionStrings[i], Component.width / 2 / Component.pixelSize - (int) (Component.width / 17.5), Component.height / 8 + (i * space));

        }
    }

}

public void keyPressed(KeyEvent e) {
    int key = e.getKeyCode();
    if (isInMenu) {
        if (key == KeyEvent.VK_UP) {
            selected--;
            if (selected < 0) {
                selected = string.length - 1;
            }
        }
        if (key == KeyEvent.VK_DOWN) {
            selected++;
            if (selected > string.length - 1) {
                selected = 0;
            }
        }
        if (key == KeyEvent.VK_ENTER) {
            if (selected == 0) {
                Component.isInMenu = false;
            } else if (selected == 1) {
                isInMenu = false;
                isInOptions = true;
                selected = 0;
            } else if (selected == 2) {
                saving = true;
                SaveLoad.save();
                saving = false;
            } else if (selected == 3) {
                loading = true;
                SaveLoad.load();
                loading = false;
            } else if (selected == 4) {
                System.exit(0);
            }
        }
    } else if (isInOptions) {
        if (key == KeyEvent.VK_UP) {
            selected--;
            if (selected < 0) {
                selected = optionStrings.length - 1;
            }
        }
        if (key == KeyEvent.VK_DOWN) {
            selected++;
            if (selected > optionStrings.length - 1) {
                selected = 0;
            }
        }
        if (key == KeyEvent.VK_ENTER) {
            if (selected == 0) {
                System.out.println("HELP");
            } else if (selected == 1) {
                isInOptions = false;
                isInMenu = true;
            }
        }
    }

}

public void keyReleased(KeyEvent e) {

}

public void keyTyped(KeyEvent e) {

}

}

2 个答案:

答案 0 :(得分:1)

您也可以实施MouseListener

您可以从MouseListener添加这些方法:

public void mousePressed(MouseEvent e) {

    if(e.getSource() == button1)
    {
        isInMenu = false;
        isInOptions = true;
        selected = 0;
    }
    if(e.getSource() == button2)
    {
        saving = true;
        SaveLoad.save();
        saving = false;
    }
    if(e.getSource() == button3)
    {
        loading = true;
        SaveLoad.load();
        loading = false;
    }
    if(e.getSource() == button4)
    {
        System.exit(0);
    }
}

public void mouseReleased(MouseEvent e) {

}

public void mouseEntered(MouseEvent e) {

}

public void mouseExited(MouseEvent e) {

}

public void mouseClicked(MouseEvent e) {

}

答案 1 :(得分:0)

首先,您必须获得文本的边界(xywidthheight)。

您已拥有xy

g.drawString(string[i], Component.width / 2 / Component.pixelSize - (int) (Component.width / 17.5), Component.height / 8 + (i * space));
// x = Component.width / 2 / Component.pixelSize - (int) (Component.width / 17.5)
// y = Component.height / 8 + (i * space)

您可以通过width确定heightFont#getStringBounds(String, FontRenderContext)

FontRenderContext renderContext = new FontRenderContext(null, true, true);
Font font = new Font("Arial", Font.PLAIN, 14);
String labelText = "Start";

Rectangle2D labelBounds = font.getStringBounds(labelText, renderContext);
int labelWidth = (int) labelBounds.getWidth();
int labelHeight = (int) labelBounds.getHeight();

需要界限来确定点击发生时鼠标是否悬停在文本上。

接下来,您必须维护每个菜单项的边界。

目前,您只需在stringoptionStrings中维护名称。您需要为每个菜单项维护xywidthheight

由于每个菜单项都有自己的名称,大小和位置,因此创建由这些属性组成的新类型会更容易:

public class Label {    
    private String name;
    private Font font;
    private int x, y;
    private int width, height;

    public Label(String name, Font font, int x, int y, int width, int height) {
        this.name = name;
        this.font = font;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
}

而不是String[],您可以拥有Label[]。虽然最好使用List来获得更高级别的功能:

public class InGameMenu implements MouseListener {
    private List<Label> labels;

    public void mousePressed(MouseEvent event) {
        int x = event.getX();
        int y = event.getY();

        labels.forEach(label -> {
        //  if (mouse hovering over label)
        //     ...
        });
    }
}

然后,您必须确定鼠标位置是否在标签的位置。

公式非常简单:

// checks if mouse intersects with label on X axis
intersectsHorizontally := mouseX > labelX && mouseX < labelX + labelWidth;

// checks if mouse intersects with label on Y axis
intersectsVertically := mouseY > labelY && mouseY < labelY + labelHeight;

// if both conditions above are true, mouse is hovering over label

实现此目标的最简单方法是为Label个对象提供containsPoint(int x, int y)行为:

public class Label {
    private int x, y;
    private int width, height;

    //...

    public boolean containsPoint(int pointX, int pointY) {
        boolean containsHorizontally = pointX > x && pointX < x + width;
        boolean containsVertically = pointY > y && pointY < y + height;

        return containsHorizontally && containsVertically;
    }
}

现在,您可以轻松确定鼠标是否悬停在特定标签上:

public void mousePressed(MouseEvent event) {
    int x = event.getX();
    int y = event.getY();

    labels.forEach(label -> {
        if(label.containsPoint(x, y)) {
            //...
        }
    });
}

最后,您必须确定单击了哪个标签

有很多方法可以解决这个问题。您可以独立维护标签并检查每个标签,而不是List

public class InGameMenu implements MouseListener {
    private Label startLabel;
    private Label loadLabel;

    public InGameMenu(Label startLabel, Label loadLabel) {
         this.startLabel = startLabel;
         this.loadLabel = loadLabel;
    }

    public void mousePressed(MouseEvent event) {
        int x = event.getX();
        int y = event.getY();

        if(startLabel.containsPoint(x, y)) {
            //start game
        } else if(loadLabel.containsPoint(x, y)) {
            //load game
        }
    }
}

但这不是动态的,因为InGameMenu被迫了解它所拥有的每个标签,添加标签会很痛苦。

更好的方法是在Label之外创建所有InGameMenu个对象,如上面的示例所示:

FontRenderContext renderContext = ...;
Font font = ...;

// start label
String labelText = "Start";
Rectangle2D labelBounds = font.getStringBounds(labelText, renderContext);
int x = ...;
int y = ...;
int width = (int) labelBounds.getWidth();
int height = (int) labelBounds.getHeight();
Label label = new Label(labelText, font, labelX, labelY, labelWidth, labelHeight);

// list of all labels for menu
List<Label> labels = new ArrayList<>();
labels.add(label);

InGameMenu menu = new InGameMenu(labels);

然后让标签对象告诉我们何时单击它。我们可以通过Label click() InGameMenu方法为public class InGameMenu implements MouseListener { private List<Label> labels; public InGameMenu(List<Label> labels) { this.labels = labels; } public void mousePressed(MouseEvent event) { int x = event.getX(); int y = event.getY(); labels.forEach(label -> { if(label.containsPoint(x, y)) label.click(); }); } } 触发标签点击时执行此操作:

Label

然后允许public class Label { private String name; private Font font; private int x, y; private int width, height; private Runnable onClick; public Label(String name, Font font, int x, int y, int width, int height, Runnable onClick) { this.name = name; this.font = font; this.x = x; this.y = y; this.width = width; this.height = height; this.onClick = onClick; } public void click() { onClick.run(); } //... } 接受回调函数:

Label

因此,当您创建GameStateManager个对象时,您可以为其提供使用外部数据的操作(可能是Runnable onClick = () -> System.out.println("Start button was clicked!"); Label label = new Label("Start", ..., onClick); 或其他内容):

${logger}