【问题标题】:Projecting mouse coordinates投影鼠标坐标
【发布时间】:2016-02-29 16:37:46
【问题描述】:

这个问题可能已经回答了,但我发现他们似乎没有用,其他人实际上没有做任何改变。

我正在创建一个游戏,该游戏有一个位于窗口 (JFrame) 内的屏幕 (Canvas)。在这个游戏中,我想使用鼠标,以及允许用户最大化窗口。无论如何,游戏屏幕都保持相同的大小,但如果调整窗口大小,我会将游戏图像缩放到窗口大小。

我的问题是我找不到合适的方法来投影鼠标的坐标,因为当窗口最大化时,它的坐标仍在被读取,就好像窗口仍然是正常大小一样,创建了一个偏移量。

我试过了:

@Override public void mouseMoved(MouseEvent e){
    MOUSE_X = Math.round((float) e.getX() / (float) RenderableCanvas.oldSizeX * (float) f.getWidth());
    MOUSE_Y = Math.round((float) e.getY() / (float) RenderableCanvas.oldSizeY * (float) f.getHeight());
}

其中 MOUSE_X/MOUSE_Y 是静态变量,可以在程序的任何地方引用以获取鼠标位置。

RenderableCanvas 是游戏窗口,包含一个嵌入的画布对象,该类还跟踪窗口的原始大小,表示为 oldSizeX 和 oldSizeY

最后 f.getHeight() 和 f.getWidth() 是帧的当前大小,因为 f 是对 RenderableCanvas 类内部的 JFrame 的引用。

但所有这些都与以下内容相同:

@Override public void mouseMoved(MouseEvent e){
    MOUSE_X = e.getX();
    MOUSE_Y = e.getY();
}

提前感谢您的帮助。

【问题讨论】:

  • 我很好奇 oldSizeXoldSizeY 是什么,是 1:1 比例的恒定表示吗?
  • oldSizeX 和 oldSizeY 基本上是窗口的标准尺寸,所以,假设我要创建 640x480 的窗口,那么 oldSizeX 和 oldSizeY 就是这些值,它们保持不变,即使窗口被重新调整为 1280x200。所以是的。

标签: java swing canvas


【解决方案1】:

基本思想是您需要能够在两个坐标系之间进行转换,在这种情况下,“世界”是被缩放的空间,而“视图”是用户看到的(或类似的东西) )

基本的数学运算是使用默认值和当前值生成一个百分比值,然后您可以将目标值乘以该百分比值,例如从视图转换为世界可能看起来像...

pointInView * (staticSize / currentSize)

因此,给定“世界”坐标中的一个点,您需要缩小到“视图”坐标...

protected Point toView(int x, int y) {
    return toView(new Point(x, y));
}

protected Point toView(Point p) {
    Point scaled = new Point(p);
    scaled.x = Math.round(p.x * ((float) getWidth() / (float) DEFAULT_WIDTH));
    scaled.y = Math.round(p.y * ((float) getHeight() / (float) DEFAULT_HEIGHT));
    return scaled;
}

给定“视图”坐标,您需要放大到“世界”坐标...

protected Point toWorld(int x, int y) {
    return toWorld(new Point(x, y));
}

protected Point toWorld(Point p) {
    Point scaled = new Point(p);
    scaled.x = Math.round(p.x * ((float) DEFAULT_WIDTH) / (float) getWidth());
    scaled.y = Math.round(p.y * ((float) DEFAULT_HEIGHT) / (float) getHeight());
    return scaled;
}

因此,例如,当鼠标移动或单击您的“视图”时,您可以使用

Point world = toWorld(e.getPoint());

将鼠标点转换为世界坐标

...请随意重命名它们以满足您自己的需要,但基本上,视图是用户看到的物理视图,并且是您对该视图的虚拟概念...

基本概念适用于 Dimension 以及扩展的 Rectangle...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        protected static final int DEFAULT_WIDTH = 200;
        protected static final int DEFAULT_HEIGHT = 200;

        private Dimension preferredSize = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);

        private JLabel properties;
        private boolean highlighted = false;

        private Rectangle hoverRect = new Rectangle(10, 10, 50, 50);

        public TestPane() {
            setLayout(new GridBagLayout());
            properties = new JLabel("...");
            add(properties);

            addMouseMotionListener(new MouseMotionAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    int x = e.getX();
                    int y = e.getY();

                    Point world = toWorld(e.getPoint());

                    highlighted = hoverRect.contains(world);
                    repaint();

                    properties.setText("<html>@" + format(e.getPoint())
                            + "<br>world = " + format(world)
                            + "<br>view = " + format(toView(world)));
                }

            });

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    preferredSize = new Dimension(DEFAULT_WIDTH * 2, DEFAULT_HEIGHT * 2);
                    SwingUtilities.windowForComponent(TestPane.this).pack();
                }
            });
        }

        protected String format(Point p) {
            return p.x + "x" + p.y;
        }

        protected Point toView(int x, int y) {
            return toView(new Point(x, y));
        }

        protected Point toView(Point p) {
            Point scaled = new Point(p);
            scaled.x = Math.round(p.x * ((float) getWidth() / (float) DEFAULT_WIDTH));
            scaled.y = Math.round(p.y * ((float) getHeight() / (float) DEFAULT_HEIGHT));
            return scaled;
        }

        protected Point toWorld(int x, int y) {
            return toWorld(new Point(x, y));
        }

        protected Point toWorld(Point p) {
            Point scaled = new Point(p);
            scaled.x = Math.round(p.x * ((float) DEFAULT_WIDTH) / (float) getWidth());
            scaled.y = Math.round(p.y * ((float) DEFAULT_HEIGHT) / (float) getHeight());
            return scaled;
        }

        protected Rectangle toWorld(Rectangle bounds) {
            return toWorld(bounds.x, bounds.y, bounds.width, bounds.height);
        }

        protected Rectangle toWorld(int x, int y, int width, int height) {
            Rectangle scaled = new Rectangle();
            scaled.setLocation(toWorld(x, y));
            scaled.width = Math.round(width * ((float) DEFAULT_WIDTH / (float) getWidth()));
            scaled.height = Math.round(height * ((float) DEFAULT_HEIGHT / (float) getHeight()));
            return scaled;
        }

        protected Rectangle toView(Rectangle bounds) {
            return toView(bounds.x, bounds.y, bounds.width, bounds.height);
        }

        protected Rectangle toView(int x, int y, int width, int height) {
            Rectangle scaled = new Rectangle();
            scaled.setLocation(toView(x, y));
            scaled.width = Math.round(width * ((float) getWidth() / (float) DEFAULT_WIDTH));
            scaled.height = Math.round(height * ((float) getHeight() / (float) DEFAULT_HEIGHT));
            return scaled;
        }

        @Override
        public Dimension getPreferredSize() {
            return preferredSize;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            Rectangle bounds = toView(hoverRect);
            if (highlighted) {
                g2d.setColor(Color.BLUE);
                g2d.fill(bounds);
            }
            g2d.setColor(Color.BLACK);
            g2d.draw(bounds);
        }

    }

}

【讨论】:

  • 谢谢你,如果我自己想通了,由于某种原因你的答案不会出现在我的电脑上,但会出现在我的手机上。
【解决方案2】:

所以我想我明白了,我做了一些旧的笔和纸数学,并意识到我的部分方程式与我认为应该有的相反。

这似乎有效:

@Override public void mouseMoved(MouseEvent e){
    MOUSE_X = (int) ((float) e.getX() / (float) f.getWidth() * (float) RenderableCanvas.oldSizeX);
    MOUSE_Y = (int) ((float) e.getY() /  (float) f.getHeight() * (float) RenderableCanvas.oldSizeY);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    相关资源
    最近更新 更多