【发布时间】:2021-06-24 07:59:06
【问题描述】:
我正在开发一个在 JavaFX 中使用六边形网格作为地图的 2D 游戏。
我使用Canvas 通过fillPolygon() 绘制自定义Hexagon 对象,现在想用项目中包含的ImagePattern 对象填充这些六边形,作为.png 文件大小为100x100 像素。
在尝试使用 AnimationTimer 将游戏置于渲染循环中时,我遇到了一些性能问题。
使用ImagePattern 绘制地图只能给我10-20 FPS,而使用Color 作为填充给我相当稳定的60 FPS。 ImagePattern 是从应用程序启动时构造的 HashMap<TerrainType, ImagePattern> 加载的。
绘制方法的主要部分如下所示:
boardGraphicsContext.setFill(
resourceMap.getTerrainSprite(gameBoardNodes[i][j].getTerrainType())
);
boardGraphicsContext.fillPolygon(
Hexagon.polygonCornersX(layout, hex),
Hexagon.polygonCornersY(layout, hex),
6
);
我也尝试在进入循环之前设置填充,根本不改变它,这也没有提高性能。
地图由 20x20 六边形组成。
以防万一:我使用的是 2017 年的 MacBook Pro,配备一些双核 i5 和 Intel Iris Plus Graphics 640,内存为 1536MB。
是否有可能使用画布方法提高性能?
问候
更新:
这里的实际问题是,现在使用 .png 作为使用 MacBook 触控板滚动的六边形的纹理似乎相当缓慢,而使用纯色则更平滑。我不知道这是我的计算机、JavaFX 还是我的特定实现的限制。
在我最初的帖子中,我说过我正在使用 Canvas 来绘制游戏,但下面的场景图实现与 Canvas 实现存在相同的问题,但更紧凑,更适合发布。
package sample;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.ImagePattern;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;
import java.util.HashMap;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
AnchorPane boardPane = new AnchorPane();
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 20; j++) {
HexNode newNode = new HexNode(i, j, "GRASS");
boardPane.getChildren().add(newNode);
}
}
boardPane.setOnScroll(scrollEvent -> {
double deltaY = scrollEvent.getDeltaY();
double zoomFactor = 1.05;
if (deltaY < 0){
zoomFactor = 2.0 - zoomFactor;
}
boardPane.setScaleX(boardPane.getScaleX() * zoomFactor);
boardPane.setScaleY(boardPane.getScaleY() * zoomFactor);
});
primaryStage.setScene(new Scene(boardPane));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class HexNode extends Polygon {
private final String type;
private final ResourceMap resourceMap = ResourceMap.getInstance();
public HexNode(int x, int y, String type) {
super();
double height = 50;
this.type = type;
double r = height / 2.0;
double h = r * Math.sin(Math.toRadians(30));
double w = r * Math.cos(Math.toRadians(30));
double xOffset, yOffset;
if (y % 2 == 0) {
xOffset = 2 * w * x;
} else {
xOffset = 2 * w * x + w;
}
yOffset = 2 * r * y - (y * h);
this.getPoints().addAll(
w + xOffset, 0.0 + yOffset,
2 * w + xOffset, h + yOffset,
2 * w + xOffset, 2 * r - h + yOffset,
w + xOffset, 2 * r + yOffset,
0.0 + xOffset, 2 * r - h + yOffset,
0.0 + xOffset, h + yOffset
);
drawType();
}
private void drawType() {
this.setFill(new ImagePattern(resourceMap.getTerrainSprite(type)));
// this.setFill(Color.BLACK); is much better
}
}
class ResourceMap {
private static final ResourceMap instance = new ResourceMap();
private final HashMap<String, Image> terrainSprites = new HashMap<>();
private ResourceMap() {
terrainSprites.put("GRASS", loadSpriteFromPath("PATH_TO_PNG"));
}
public static ResourceMap getInstance() {
return instance;
}
public Image getTerrainSprite(String terrainType) {
return terrainSprites.get(terrainType);
}
private Image loadSpriteFromPath(String filePath) {
return new Image(filePath);
}
}
【问题讨论】: