【问题标题】:Overlapping of Buttons with canvas for mouseinput按钮与画布重叠以进行鼠标输入
【发布时间】:2016-09-30 16:04:46
【问题描述】:

我目前仅使用标准库在 java 中制作 RPG hack 和 slash。

对于这些游戏,我在一个独立的包中创建了一个 CustomButton 类,我只是复制并粘贴到我几乎所有的游戏中,然后进行一些特定于游戏的修改。

这是类::

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;

import objects.Collectable;

public final class CustomButton implements MouseListener {

    // private BufferedImage image;
    private String text = "";
    private boolean pressed = false;
    private int x;
    private int y;
    private int width;
    private int height;
    private Color currentColor, defaultColor, hoverColor, pressColor;
    private Point mousePoint = new Point(0, 0);
    private ButtonListener btnListener = null;
    private Canvas canvasObject;
    private BufferedImage image;
    private BufferedImage darkImage;
    private String actionCommand = "default";
    private Collectable object;

    private boolean enabled;
    /*
     * private CustomButton(Canvas canvasObject,JFrame frame) { this.x=100;
     * this.y=100; this.width=100; this.height=100;
     * 
     * canvasObject.addMouseListener(this); currentColor=new Color(255,255,255);
     * defaultColor=new Color(255,255,255); hoverColor=new Color(255,255,255);
     * pressColor=new Color(255,255,255); }
     */

    public CustomButton(int x, int y, int width, int height, Canvas canvasObject) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.canvasObject = canvasObject;
        canvasObject.addMouseListener(this);
        currentColor = Color.GREEN;
        currentColor = new Color(255, 255, 255);
        defaultColor = new Color(255, 255, 255);
        hoverColor = new Color(255, 255, 255);
        pressColor = new Color(255, 255, 255);
        enabled = true;
    }

    public CustomButton(int x, int y, int width, int height, Canvas canvasObject, BufferedImage image,
            Collectable object) {
        this.image = image;
        this.darkImage = darkenImage(image);
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        canvasObject.addMouseListener(this);
        currentColor = Color.GREEN;
        currentColor = new Color(255, 255, 255);
        defaultColor = new Color(255, 255, 255);
        hoverColor = new Color(255, 255, 255);
        pressColor = new Color(255, 255, 255);
        this.canvasObject = canvasObject;
        this.object = object;

        enabled = true;
    }

    public void render(Graphics g) {
        if (image == null) {
            g.setColor(currentColor);
            if (!pressed)
                g.fillRect(this.x, this.y, width, height);
            else
                g.fill3DRect(this.x, this.y, width, height, true);
            g.setColor(Color.BLACK);
            g.drawString(text, this.x + 10, this.y + 15);
        } else {
            if (enabled) {
                g.drawImage(image, x, y, width, height, null);
            } else {
                g.drawImage(darkImage, x, y, width, height, null);
            }
        }
    }

    public Rectangle getBounds() {
        return new Rectangle(x, y, width, height);

    }

    public void tick() {
        mousePoint = getMouseLocation();
        changeColor();
    }

    private Point getMouseLocation() {
        int x = 0;
        int y = 0;

        try {
            x = (int) (canvasObject.getMousePosition().getX());
            y = (int) (canvasObject.getMousePosition().getY());
        } catch (NullPointerException nl) {
        }

        return new Point(x, y);
    }

    public void changeColor() {

        if (!pressed) {
            if (getBounds().contains(mousePoint))
                currentColor = hoverColor;
            else
                currentColor = defaultColor;
        } else {
            currentColor = pressColor;
        }

    }

    public void addButtonListener(ButtonListener btnListener) {
        this.btnListener = btnListener;
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mouseClicked(MouseEvent e) {
        if (enabled) {
            if (btnListener != null) {

                if (getBounds().contains(mousePoint)) {
                    ButtonID id = ButtonID.UNDETERMINABLE;
                    if (e.getButton() == MouseEvent.BUTTON1) id = ButtonID.LEFT;
                    if (e.getButton() == MouseEvent.BUTTON2) id = ButtonID.RIGHT;

                    btnListener.buttonClicked(new ButtonEvent(id, object, actionCommand));
                }
            }
        }
    }

    public void mousePressed(MouseEvent e) {
        if (getBounds().contains(mousePoint)) pressed = true;
    }

    public void mouseReleased(MouseEvent e) {
        pressed = false;
    }

    public void setActionCommand(String actionCommand) {
        this.actionCommand = actionCommand;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public void setDefaultColor(Color c) {
        defaultColor = c;
    }

    public void setHoverColor(Color c) {
        hoverColor = c;
    }

    public void setPressColor(Color c) {
        pressColor = c;
    }

    public Collectable getObject() {
        return object;
    }

    public void setObject(Collectable object) {
        this.object = object;
    }

    public void destroy() {
        canvasObject.removeMouseListener(this);
    }

    public void disable() {
        enabled = false;
    }

    public void enable() {
        enabled = true;
    }

    public boolean isEnabled() {
        return enabled;
    }

    private BufferedImage darkenImage(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();
        image = deepCopy(image);

        WritableRaster raster = image.getRaster();

        for (int xx = 0; xx < width; xx++) {
            for (int yy = 0; yy < height; yy++) {
                int[] pixels = raster.getPixel(xx, yy, (int[]) null);
                pixels[0] -= 50;
                pixels[1] -= 50;
                pixels[2] -= 50;

                pixels[0] = Math.max(pixels[0], 0);
                pixels[1] = Math.max(pixels[0], 0);
                pixels[2] = Math.max(pixels[0], 0);

                raster.setPixel(xx, yy, pixels);
            }
        }
        return image;
    }

    private BufferedImage deepCopy(BufferedImage bi) {
        ColorModel cm = bi.getColorModel();
        boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
        WritableRaster raster = bi.copyData(null);
        return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
    }

}

你可能从mouseClicked()方法中可以看出,一个事件被发送到ButtonListener类。ButtonListener接口也在包中声明。

这个按钮是在画布本身上绘制的。例如,在关卡地图的右下角有一个按钮,点击它会打开库存。让这个按钮被称为btn_INV

到目前为止,我一直在通过键盘输入来移动玩家。但我计划将 keyInput 更改为鼠标输入,玩家将移动到用户点击的图块。

为此,我必须创建一个类,比如实现MouseListenerMouseInput。现在的问题是,当我单击btn_INV 时,按钮不仅会生成事件,而且由于按钮是实际上在画布上绘制,MouseInput 类也会得到一个关于玩家想要移动到的瓷砖的事件。现在,我想当MouseInput 类得到一个MouseEvent 时,它会检查按钮就像在画布上单击鼠标一样,按钮总是 会收到通知,尽管它可能不会生成ButtonEvent,正如您从代码中看到的那样。但这是一个相当糟糕的方法而且效率很低。所以,我想要另一种方法。

注意:我想创建另一个画布来显示 HUD 和 btn_INV 和其他此类按钮,但这并不能真正解决问题,而是绕过它。

【问题讨论】:

    标签: java user-interface button canvas mouseevent


    【解决方案1】:

    我认为有两种方法可以解决这个问题:

    • 第一个是将您的游戏屏幕分为两部分:一个用于按钮,另一个用于图块,因此您可以在捕获鼠标事件时测试点击是否位于图块上。请注意,瓷砖可以放置在新按钮上。此解决方案易于实施,但您无法在磁贴区域放置按钮。

    • 第二个是创建一个“ButtonManager”。你的游戏类将有这个按钮管理器,它将监听鼠标事件并发送给按钮。按钮不会直接监听此事件。如果点击在他们的边界上,他们会一个接一个地说,如果没有触发任何按钮,则意味着点击发生在瓷砖上。这种方法实现起来有点困难,但允许您在按钮之间创建优先级,因此按钮可以让它们的边界相交!

    希望对你有所帮助!

    【讨论】:

      【解决方案2】:

      一般来说,按钮监听器等概念用于应用程序,而不是游戏。

      游戏通常使用具有更新和平局阶段的游戏循环。在更新阶段,用户输入被捕获(嗯......检查比捕获更多,但我稍后会谈到)并解释。

      所以你只需要一个大的鼠标监听器,然后检查哪个按钮可能被按下,或者鼠标是否在游戏区域内,所以角色应该得到移动命令。

      当然,从技术上讲,鼠标侦听器不应该直接做任何事情,因为它绑定到摆动线程。它应该只更改一些变量(例如:“鼠标左键按下,位置是 x,y”),然后将在您的更新阶段进行检查,然后实际使用它。这样一来,您就不再依赖挥杆线程(无论如何这对游戏来说并不理想),而且几乎同样重要的是,您的游戏逻辑是完全可预测的。

      但是,您仍然必须确保您的 draw 方法被定期调用并实际绘制您想要绘制的内容和时间。不过这不是问题,所以我不会详细说明它。

      请记住,即使是挥杆也不仅仅是某种神奇的构造。单击鼠标时,swing 还将遍历您拥有的所有元素,并查看其中一个是否应该获得事件。如果您编写自己的 Button,那么您也必须这样做。

      为每个按钮提供它自己的鼠标侦听器只会让您的游戏变得越大越混乱。它还会破坏您的游戏循环,因为无论您目前在做什么,都可以随时抛出和捕获鼠标事件。如果您的游戏逻辑发生在与 swing 不同的线程中(应该如此),那么您甚至有可能在处理某些事情时收到一个事件。这会搞砸你的结果。

      这也可能导致一些非常奇怪的一次性错误,您无法理解且无法重现。所以要非常小心。

      【讨论】:

      • 感谢您的宝贵时间和建议。我会相应地更改我的 a=program,因为您提到的内容是有效的。但我要说的一件事是 btn_INV 只会更改 GameState所以我在主游戏线程上执行一些其他更新时调用该方法并不重要。但是你所说的MouseListener线程只是创建一些“ActionCommands”是一个好点,我会尝试实现它。谢谢.
      猜你喜欢
      • 1970-01-01
      • 2010-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-26
      • 1970-01-01
      • 2019-09-25
      • 2016-04-17
      相关资源
      最近更新 更多