Java 鼠标在菱形平铺地图上拾取
好吧,我已经束手无策了。我正在尝试创建一个比屏幕大的小型等距平铺地图,其中的视点我可以通过鼠标拖动进行修改。 我的绘图正确(我认为),我的拖动工作正常,只是似乎无法正确选择鼠标。 到目前为止,我已经做到了,我得到的瓷砖几乎是正确的,但它偏离了大约瓷砖尺寸的一半,我找不到弥补该偏移的方法。
这是代码:
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) {
}
}
}
我在 click 方法中有一些公式被注释掉,但它们不起作用(x 和 y 轴以这种方式反转,还没有尝试找出原因)。 如果有人能指出我所犯的错误,我将不胜感激。
Ok, im at my wits end. I am trying to create a small isometric tile map thats bigger then the screen witha viewpoint i can modify with mouse dragging.
I got the drawing right (i think), i got the dragging working, just do't seem to be able to get the mouse picking right.
I have made it so far that i get the tile nearly right, but its off by about half a tiles size and i can't find a way to make up that offset.
Here is the code:
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) {
}
}
}
I have some formulas in the click method commented out wich i tried, but they dont work (x and y axis are inverted that way, havent tried to figure out why yet).
Would realy appreciate if someone can point me to the mistake i'm making.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我设法为你解决了它。首先,我做了一些代数运算(希望通过内联注释进行解释)来简化计算哪个图块被击中。接下来你确实有所意识到了;选角存在问题。在使用之前,您需要将所有内容转换为双精度值。如果您执行
int/int
那么您已经进行了强制转换并失去了精度。让它击中正确的图块的技巧是 1) 尽早转换和 2)
+/- 0.5
用于强制返回int
强制转换为单向或另一个。详细来说,(int)6.9 == 6
。这是工作答案:
I managed to fix it for you. Firstly I did a bit of algebra (hopefully explained by the inline comments) to simplify the calculation of which tile is hit. The next bit you did somewhat realise; there's issues casting. You need to convert everything to a double before you use it. If you do
int/int
then you already made a cast and lost precision.The trick to making it hit the right tile is 1) casting early and 2) the
+/- 0.5
which is used to force the returnint
cast to go one way or the other. To elaborate,(int)6.9 == 6
.Here's the working answer:
Polygon
实现Shape
接口,因此几个contain()
变体之一可以简化您的计算。AffineTransform
也可能会有帮助,如本 示例。Polygon
implements theShape
interface, so one of the severalcontain()
variations may simplify your calculation. ThecreateTransformedShape()
method ofAffineTransform
may also be helpful, as suggested in this example.