Java 鼠标在钻石平铺 map 上采摘

标签 java swing isometric mouselistener mouse-picking

好吧,我已经无计可施了。我正在尝试创建一个比屏幕大的小等距平铺 map ,我可以通过鼠标拖动来修改视点。 我画对了(我认为),拖动工作正常,只是似乎无法正确选择鼠标。 到目前为止,我已经做到了,我得到的瓷砖几乎是正确的,但它偏离了大约一半的瓷砖大小,我找不到弥补该偏移的方法。

代码如下:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MapView {

    public static void main(String[] args) {
        JFrame test = new JFrame("IsoView");
        test.setSize(800, 600);
        MapViewPane pane = new MapViewPane();
        test.getContentPane().setLayout(new BorderLayout());
        test.getContentPane().add(pane, BorderLayout.CENTER);
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        test.setVisible(true);
    }

    private static class MapViewPane extends JPanel
            implements MouseMotionListener, MouseListener {

        private BufferedImage BackImage;
        BufferedImage GrassTile, SelectedBorder;
        private Point MousePoint, PrevView, ViewLocation, Selected;
        private boolean Dragging;
        private int mapwidth, mapheight, tilecount;

        public MapViewPane() {
            super();
            this.setOpaque(true);
            createAssets();
            tilecount = 30;
            mapwidth = GrassTile.getWidth() * tilecount;
            mapheight = GrassTile.getHeight() * tilecount;
            ViewLocation = new Point(0, mapheight / 2);
            Selected = new Point(-1, -1);
            addMouseListener(this);
            addMouseMotionListener(this);
        }

        private void createAssets() {
            GraphicsConfiguration gc =
                    GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
            GrassTile = gc.createCompatibleImage(128,
                    64, Transparency.TRANSLUCENT);
            Graphics g = GrassTile.getGraphics();
            Polygon poly = new Polygon();
            poly.addPoint(0, 32);
            poly.addPoint(64, 0);
            poly.addPoint(128, 32);
            poly.addPoint(64, 64);
            g.setColor(Color.GREEN);
            g.fillPolygon(poly);
            g.setColor(Color.BLUE);
            g.drawPolygon(poly);
            g.dispose();
            SelectedBorder = gc.createCompatibleImage(128,
                    64, Transparency.TRANSLUCENT);
            g = SelectedBorder.getGraphics();
            g.setColor(Color.red);
            g.drawPolygon(poly);
            g.dispose();
        }

        @Override
        public void paint(Graphics g) {
            //super.paint(g);
            Rectangle visiblerec = this.getVisibleRect();
            g.setColor(Color.BLACK);
            g.fillRect(visiblerec.x, visiblerec.y,
                    visiblerec.width, visiblerec.height);
            checkBackImage();
            Graphics bg = BackImage.getGraphics();
            drawGrassGrid(bg);
            bg.dispose();
            g.drawImage(BackImage, 0, 0, this);
        }

        private void drawGrassGrid(Graphics g) {
            int dx = 0;
            int dy = 0;
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, BackImage.getWidth(), BackImage.getHeight());
            for (int x = 0; x < tilecount; x++) {
                for (int y = 0; y < tilecount; y++) {
                    dx = x * GrassTile.getWidth() / 2
                            - y * GrassTile.getWidth() / 2;
                    dy = x * GrassTile.getHeight() / 2
                            + y * GrassTile.getHeight() / 2;
                    dx -= ViewLocation.x;
                    dy -= ViewLocation.y;
                    g.drawImage(GrassTile, dx, dy, this);
                    if ((x == Selected.x) && (y == Selected.y)) {
                        g.drawImage(SelectedBorder, dx, dy, this);
                    }
                    g.drawString("(" + x + "," + y + ")", dx, dy
                            + GrassTile.getHeight() / 2);
                }
            }
        }

        private void checkBackImage() {
            if ((BackImage == null) || (BackImage.getWidth() != this.getWidth())
                    || (BackImage.getHeight() != this.getHeight())) {
                GraphicsConfiguration gc =
                        GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
                BackImage = gc.createCompatibleImage(this.getWidth(),
                        this.getHeight(), Transparency.BITMASK);
            }
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (Dragging) {
                ViewLocation.x = PrevView.x + MousePoint.x - e.getX();
                ViewLocation.y = PrevView.y + MousePoint.y - e.getY();
                if (ViewLocation.x < -mapwidth / 2) {
                    ViewLocation.x = -mapwidth / 2;
                }
                if (ViewLocation.y < -mapheight / 2 + this.getHeight()) {
                    ViewLocation.y = -mapheight / 2 + this.getHeight();
                }
                if (ViewLocation.x > mapwidth / 2 - this.getWidth()
                        + GrassTile.getWidth()) {
                    ViewLocation.x = mapwidth / 2 - this.getWidth()
                            + GrassTile.getWidth();
                }
                if (ViewLocation.y > mapheight / 2 + this.getHeight()) {
                    ViewLocation.y = mapheight / 2 + this.getHeight();
                }
                repaint();
            }
        }

        @Override
        public void mouseMoved(MouseEvent e) {
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            if (!Dragging) {
                int x = (GrassTile.getWidth() * (e.getY() + ViewLocation.y)
                        + GrassTile.getHeight() * (e.getX() + ViewLocation.x))
                        / (GrassTile.getWidth() * GrassTile.getHeight());
                int y = (GrassTile.getWidth() * (e.getY() + ViewLocation.y)
                        - GrassTile.getHeight() * (e.getX() + ViewLocation.x))
                        / (GrassTile.getWidth() * GrassTile.getHeight());

//      int x = (int) Math.floor((e.getY() + ViewLocation.y)
//              / (double) GrassTile.getHeight() - (e.getX() + ViewLocation.x)
//              / (double) GrassTile.getWidth());
//      int y = (int) Math.floor((e.getY() + ViewLocation.y)
//              / (double) GrassTile.getHeight() + (e.getX() + ViewLocation.x)
//              / (double) GrassTile.getWidth());

                Selected.setLocation(x, y);
                repaint();
                System.out.println("(" + x + "," + y + ")");
            }
        }

        @Override
        public void mousePressed(MouseEvent e) {
            if ((e.getButton() == MouseEvent.BUTTON1) && !Dragging) {
                MousePoint = e.getPoint();
                PrevView = new Point(ViewLocation);
                Dragging = true;
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            Dragging = false;
            MousePoint = null;
        }

        @Override
        public void mouseEntered(MouseEvent e) {
        }

        @Override
        public void mouseExited(MouseEvent e) {
        }
    }
}

我尝试在点击方法中注释掉了一些公式,但它们不起作用(x 和 y 轴以这种方式倒置,还没有试图找出原因)。 如果有人能指出我正在犯的错误,我将不胜感激。

最佳答案

我设法为您修复了它。首先,我做了一些代数运算(希望通过内联注释解释)来简化命中哪个方 block 的计算。接下来你有点意识到;类型转换有问题。在使用之前,您需要将一切 转换为 double 。如果你执行 int/int 那么你已经进行了转换并失去了精度。

让它命中正确方 block 的诀窍是 1) 尽早转换和 2) +/- 0.5 用于强制返回 int 转换一种或另一种方式。详细说明,(int)6.9 == 6

这是有效的答案:

    @Override
    public void mouseClicked(MouseEvent e) {
        if (!Dragging) {
            /*
            // copy of the tile location assignment code as a reminder
            dx = x * GrassTile.getWidth() / 2
                    - y * GrassTile.getWidth() / 2;
            dy = x * GrassTile.getHeight() / 2
                    + y * GrassTile.getHeight() / 2;
            dx -= ViewLocation.x;
            dy -= ViewLocation.y;
            */
            int pickX = e.getX() + ViewLocation.x;
            int pickY = e.getY() + ViewLocation.y;
            int tileW = GrassTile.getWidth();
            int tileH = GrassTile.getHeight();
            /*
            // assignment code refactored
            x - y = 2 * pickX / tileW;
            x + y = 2 * pickY / tileH;

            // x+y= refactored to y=
            y = (2*pickY / tileH) - x;
            // substitute into x-y + refactor
            2x = (2 * pickX / tileW) + (2 * pickY / tileH);

            // x+y= refactored to x=
            x = (2*pickY / tileH) - y;
            // substitute x-y + refactor
            -2y = (2 * pickX / tileW) - (2 * pickY / tileH);
            2y = (2 * pickY / tileH) - (2 * pickX / tileW);
            */
            int hitx = (int)(((double)pickX / (double)tileW) + ((double)pickY / (double)tileH) - 0.5);
            int hity = (int)(((double)pickY / (double)tileH) - ((double)pickX / (double)tileW) + 0.5);
            Selected.setLocation(hitx, hity);
            repaint();
            //System.out.println("(" + x + "," + y + ")");
        }
    }

关于Java 鼠标在钻石平铺 map 上采摘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6737617/

相关文章:

java - JLabel 中的自定义字体被截断

javascript - 使用 xdim 和 ydim 进行等距简单排序

java - 如何在运行程序文件中给出功能文件的路径

java - 通过使用 netbeans 单击 jbutton 将带有行的 jbutton 添加到 jtable 中

java - double 值与常量的比较

java - 有没有比使用 instanceof 更好/更干净的方法来有条件地创建类型? [ java ]

java - 为什么 Netbeans 设计者将 JFrame 大小设置为与我指定的不同的值?

java - 如何在 JSpinner 上只显示日期

python - 带 python 的等距 ascii 立方体

javascript - 鼠标位置到等距图 block (包括高度)