免责声明:我非常是JavaFX和模型 - 视图 - 控制器设计原则的新手。
这是我的基本情况:
我有一个类似于this教程中概述的ScreenManager。使用屏幕管理器,我使用屏幕按钮上的基本操作处理在几个FXML屏幕之间切换。
问题在于其中一个是带有地图的游戏画面。我将在这个游戏画面上绘制一个基于图块的地图,所以我在我的FXML文件中使用了TilePane(如果有更好的方法将图块绘制到屏幕区域,请告诉我。)
这是我创建TilePane的代码,我想将其绘制到游戏屏幕:
public TilePane createRandomMap(boolean centeredRiver)
{
Image atlas = new Image("resources/textures/tile_atlas.jpg");
Random rand = new Random();
int riverPos = 4,
tileHeight = (int)atlas.getHeight()/2,
tileWidth = (int)atlas.getWidth()/3;
if(!centeredRiver)
riverPos = rand.nextInt(10);
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < riverPos; j++)
{
int type = rand.nextInt(4);
Tile tile = new Tile(tileTypes[type], i, j);
tile.setImage(atlas);
tile.setViewport(new Rectangle2D((type%3)*tileWidth, //minX
tileHeight-(type/3)*tileHeight, //minY
tileWidth, tileHeight)); // width, height
tile.setFitHeight(tilePane.getHeight()/5); //fit to the size of the pane
tile.setFitWidth(tilePane.getWidth()/9); //fit to the size of the pane
tile.setPreserveRatio(true);
tilesToAdd.add(tile);
}
if(i == 2)
{
Tile tile = new Tile(tileTypes[5], i, riverPos);
tile.setImage(atlas);
tile.setViewport(new Rectangle2D(2*tileWidth, 0,
tileWidth, tileHeight));
tile.setFitHeight(tilePane.getHeight()/5);
tile.setFitWidth(tilePane.getWidth()/9);
tile.setPreserveRatio(true);
tilesToAdd.add(tile);
}
else
{
Tile tile = new Tile(tileTypes[4], i, riverPos);
tile.setImage(atlas);
tile.setViewport(new Rectangle2D(tileWidth, 0,
tileWidth, tileHeight));
tile.setFitHeight(tilePane.getHeight()/5);
tile.setFitWidth(tilePane.getWidth()/9);
tile.setPreserveRatio(true);
tilesToAdd.add(tile);
}
for(int j = riverPos + 1; j<9; j++)
{
int type = rand.nextInt(4);
Tile tile = new Tile(tileTypes[type], i, j);
tile.setImage(atlas);
tile.setViewport(new Rectangle2D((type%3)*tileWidth, //minX
tileHeight-(type/3)*tileHeight, //minY
tileWidth, tileHeight)); // width, height
tile.setFitHeight(tilePane.getHeight()/5); //fit to the size of the pane
tile.setFitWidth(tilePane.getWidth()/9); //fit to the size of the pane
tile.setPreserveRatio(true);
tilesToAdd.add(tile);
}
}
tilePane.getChildren().addAll(tilesToAdd);
return tilePane;
}
我已经能够在我的控制器类中访问此TilePane:
public class GameScreenController implements Initializable, ControlledScreen {
ScreenManager screenManager;
@FXML
TilePane mapPane
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
TileEngine engine = new TileEngine();
mapPane = engine.createRandomMap(true);
}
在上面的例子中,我将在FXML屏幕中定义的TilePane设置为我在模型中创建的TilePane,但是我收到以下错误:
Can not set javafx.scene.layout.TilePane field
screens.gameScreen.GameScreenController.mapPane to
javafx.scene.layout.AnchorPane
这是我处理TilePane的FXML文件的一部分:
<TilePane id="MapPane" fx:id="mapPane" layoutX="0.0" layoutY="0.0" prefColumns="9" prefHeight="560.0" prefTileHeight="112.0" prefTileWidth="112.0" prefWidth="1108.0" visible="true" />
我真的很难全面了解JavaFX和游戏设计,但非常想学习。我很乐意澄清并批评这个结构的任何部分,以使其更好,即使是与我所问的问题无关的事情。
提前谢谢!
答案 0 :(得分:3)
<强> MVC 强>
严格来说JavaFX不支持MVC(无论发明者自己都宣称死了)但是某种MVVM(Model-View-ViewModel)
模型和控制器之间的通信
我通常使用依赖注入来执行此操作。如果你想要一个简单的FrameWork,我可以建议你afterburner.fx或Google Guice。两个非常轻量级的框架,你做你想要的。基本上,他们可以为您处理类的实例化,并确保是否只需要模型的一个实例是活动的。
一些示例代码:
public class Presenter {
// Injects
@Inject private StateModel stateModel;
}
无需声明构造函数或任何其他内容。如果你愿意的话,你需要做更多的工作来测试它,但总的来说我不想再次错过这个功能,因为通常你只需要一个StateModel
,其中所有的信息都是来源的,所有的观点只是倾听他们或改变他们。
让我们再举一个例子来扩展到已发布的代码
@Singleton
public class StateModel {
// Properties
private final StringProperty name = new SimpleStringProperty();
// Property Getter
public StringProperty nameProperty() { return this.name; }
}
如果我们现在在Presenter / Controller中声明了标签,我们可以像这样听取模型中的更改
public class Presenter implements Initializable {
// Nodes
@FXML private Label nodeLabelName;
// Injects
@Inject private StateModel stateModel;
@Override
public void initialize(URL location, ResourceBundle resource) {
this.nodeLabelName.textProperty().bind(this.stateModel.nameProperty());
}
}
我可以给你的另一个建议是Threading
。您通常希望您的业务逻辑在另一个线程中执行,否则您的Application-Thread将在处理时开始滞后