我正在尝试通过跟随Red Blob Games来构建十六进制网格。六角网格轴向坐标系从-radius < x < radius
和-radius < y < radius
运行。 Red Blob定义了一个将int
轴坐标转换为double
像素坐标的函数。
public Point tileToPixel(Tile tile) {
Hex hex = (Hex) tile;
double x = (orientation.getF0() * hex.getX() + orientation.getF1() * hex.getY()) * size.getX();
double y = (orientation.getF2() * hex.getX() + orientation.getF3() * hex.getY()) * size.getY();
return new Point(x, y);
}
Point
相当于Point2D
;我决定写自己的。
orientation
是enum
,它根据平顶或点顶六边形方向定义六边形的点。
POINT_TOP_ORIENTATION ( Math.sqrt(3.0), Math.sqrt(3.0)/2.0, 0.0, 3.0/2.0,
Math.sqrt(3.0)/3.0, -1.0/3.0, 0.0, 2.0/3.0,
0.5),
FLAT_TOP_ORIENTATION ( 3.0/2.0, 0.0, Math.sqrt(3.0)/2.0, Math.sqrt(3.0),
2.0/3.0, 0.0, -1.0/3.0, Math.sqrt(3.0)/3.0,
0.0);
private HexOrientation(double f0, double f1, double f2, double f3,
double b0, double b1, double b2, double b3,
double startAngle) {
this.f0 = f0;
this.f1 = f1;
this.f2 = f2;
this.f3 = f3;
this.b0 = b0;
this.b1 = b1;
this.b2 = b2;
this.b3 = b3;
this.startAngle = startAngle;
}
问题变成了轴坐标被转换为包含负值的像素坐标double
,并假定为正常的笛卡尔格式(正Y向上,正向X右),原点为(0,0)at中心。
我正在使用Scene Builder构建我的显示器。这是我非常基本的设置:
您可以看到我以AnchorPane
为根,BorderPane
和Pane
位于BorderPane
的中心,我打算将六边形作为显示。
我的Main
课程定义为:
public class Main extends Application {
@Override
public void start(Stage stage) {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/Display.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
stage.setTitle("Grid Display");
stage.setScene(scene);
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
我的FXML类定义为:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>
<AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.ScreenController">
<children>
<BorderPane layoutX="-8.0" layoutY="-69.0" prefHeight="297.0" prefWidth="610.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<center>
<Pane fx:id="nodePane" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
</children>
</AnchorPane>
最后,我的控制器类ScreenController
已定义:
public class ScreenController {
@FXML
private Pane nodePane;
@FXML
protected void initialize() {
Grid grid = new Grid(new HexScreen(HexOrientation.POINT_TOP_ORIENTATION, new Point (10,10)), new HexMap(MapShape.HEXAGON));
for(Tile tile : grid.getMap().getMap()) {
int i = 0;
Double[] points = new Double[12];
Point[] corners = grid.getScreen().polygonCorners(tile);
for(Point point : corners) {
points[i] = point.getX();
points[i+1] = point.getY();
i += 2;
}
Polygon polygon = drawTile(points);
if (tile.getX() == 0 && tile.getY() == 0) {
polygon.setFill(Color.BLACK);
}
this.nodePane.getChildren().add(polygon);
}
}
private Polygon drawTile(Double[] points) {
Polygon polygon = new Polygon();
polygon.getPoints().addAll(points);
polygon.setStroke(Color.BLACK);
polygon.setFill(Color.TRANSPARENT);
return polygon;
}
}
这个输出是:
如何将nodePane
的原点设置为Pane
的中心而不是左上角?我宁愿不通过tileToPixel()
重新计算像素坐标,因为此函数位于我作为JAR导入到实际JavaFX显示正在发生的GridDisplay
项目中的项目中。我打算能够将JAR用作独立于我如何构建GUI的库,因此需要“通用”磁贴到像素计算而不是特定于JavaFX(如果这是有意义的话)。
因此,我认为更改像素坐标的最佳位置是ScreenController
。到目前为止,我已经尝试过:
for(Tile tile : grid.getMap().getMap()) {
int i = 0;
Double[] points = new Double[12];
Point[] corners = grid.getScreen().polygonCorners(tile);
for(Point point : corners) {
points[i] = point.getX();
points[i+1] = point.getY();
i += 2;
}
Polygon polygon = drawTile(points);
if (tile.getX() == 0 && tile.getY() == 0) {
polygon.setFill(Color.BLACK);
}
polygon.setTranslateX(nodePane.getWidth()/2);
polygon.setTranslateY(nodePane.getHeight()/2);
this.nodePane.getChildren().add(polygon);
}
此输出看起来与上图完全相同。我还将nodePane.getWidth()
和nodePane.getHeight()
替换为:
polygon.setTranslateX(nodePane.getPrefWidth()/2);
polygon.setTranslateY(nodePane.getPrefHeight()/2);
这会轻微地移动原点但不是我想象它应该看起来。作为参考,我的PrefWidth
,PrefHeight
和AnchorPane
的{{1}}和BorderPane
都设置为Pane
。
最后,即使上面的解决方案位于USE_COMPUTED_SIZE
的中心,我也不相信如果用户调整窗口大小,它就会起作用。
感谢您阅读我的冗长帖子,如果您需要任何其他信息,请与我们联系。
答案 0 :(得分:3)
@Sedrick感谢您的帮助。
这是我的解决方案。
public class ScreenController {
@FXML
private StackPane nodePane;
@FXML
protected void initialize() {
Grid grid = new Grid(new HexScreen(HexOrientation.POINT_TOP_ORIENTATION, new Point (10,10)), new HexMap(MapShape.HEXAGON));
Group group = new Group();
for(Tile tile : grid.getMap().getMap()) {
int i = 0;
Double[] points = new Double[12];
Point[] corners = grid.getScreen().polygonCorners(tile);
for(Point point : corners) {
points[i] = point.getX();
points[i+1] = point.getY();
i += 2;
}
Polygon polygon = drawTile(points);
if (tile.getX() == 0 && tile.getY() == 0) {
polygon.setFill(Color.BLACK);
}
group.getChildren().add(polygon);
}
this.nodePane.getChildren().add(group);
}
private Polygon drawTile(Double[] points) {
Polygon polygon = new Polygon();
polygon.getPoints().addAll(points);
polygon.setStroke(Color.BLACK);
polygon.setFill(Color.TRANSPARENT);
//tileHandler.hoverHandler(polygon, Color.TRANSPARENT, Color.RED);
return polygon;
}
}
我首先将所有多边形(十六进制)放入Group
对象中。然后将Group
添加到StackPane
(而不是Pane
),如上所述。如果我使用Pane
而不是Group
,则此解决方案无效。以下是结果输出:
我仍然需要在X轴上镜像网格(因为-Y仍在运行),并且最好允许在窗口调整大小的情况下动态调整网格大小,以便始终查看整个网格。