返回

JavaFX GridPane单元格颜色设置 - 俄罗斯方块开发实践

java

JavaFX GridPane 单元格颜色设置:俄罗斯方块开发实践

搞俄罗斯方块项目的时候,想用 GridPane 来划分游戏区域,把舞台(Stage)分割成一个个小格子。 初步设想是改变每个单元格的颜色来模拟方块,但不知道怎么下手。 试过直接加彩色矩形,不行。颜色信息是放在一个15x10的二维数组 colorArray 里面的,每个索引对应一个颜色。

public void start(Stage primaryStage) throws Exception {
    pane = new GridPane();
    pane.setGridLinesVisible(true);
    pane.setVgap(40);
    pane.setHgap(40);
    primaryStage.setResizable(false);
    scene = new Scene(pane,height,width);
    for(int x = 0; x < 16; x++){
        pane.getRowConstraints().addAll(getFifteenRowConstraints());
        for(int y = 0; y<10; y++){
            pane.getColumnConstraints().addAll(getTenColumnConstraints());


        }
    }
    primaryStage.setScene(scene);
    primaryStage.setTitle("Russian Game");
    primaryStage.show();
}

对行约束(Row Constraints)和列约束(Column Constraints)具体干啥的,还真不太清楚,就知道现在格子是均匀分隔开了,有线隔着。

现在的问题就是:怎么单独改变 GridPane 里每个单元格的颜色?

问题原因分析

直接添加彩色矩形到 GridPane 不起作用,是因为 GridPane 默认情况下不会直接把子节点作为背景。 GridPane 的布局方式是管理子节点的位置和大小,而不是把它们“画”在自己身上。设置了 setGridLinesVisible(true),能看到网格线,但网格线和单元格背景是两码事。

至于行约束和列约束,它们决定了 GridPane 的行高和列宽。 getFifteenRowConstraints()getTenColumnConstraints() (代码中未给出实现)很可能是用来设置行高和列宽的具体数值。 但是这些约束并不能直接控制单元格颜色。

解决方案

要实现改变 GridPane 单元格颜色,有几种方法。

1. 使用背景填充 (Background Fill)

最直接的方法是给每个单元格添加一个 PaneRegion,然后设置它们的背景颜色。

原理:

PaneRegion 都是可以设置背景的节点。把它们作为 GridPane 的子节点,并设置好对应的行和列,就能通过控制这些节点的背景色来改变单元格的颜色。

代码示例:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class TetrisGrid extends Application {

    private GridPane pane;
    private final int rows = 15;
    private final int cols = 10;
    private Color[][] colorArray = new Color[rows][cols]; //假设已初始化

      private Pane[][] cellPanes = new Pane[rows][cols]; // 保存每个单元格的Pane

    @Override
    public void start(Stage primaryStage) {
       //初始化colorArray,此处随便设置几个
       for (int i = 0; i < rows; i++) {
          for (int j = 0; j < cols; j++) {
             colorArray[i][j] = Color.WHITE; // 默认白色
          }
       }
       colorArray[0][0] = Color.RED;
        colorArray[1][1] = Color.BLUE;

        pane = new GridPane();
        pane.setGridLinesVisible(true);
        // 这里可以根据需要调整间距,或者直接去掉
      //  pane.setVgap(1); //垂直
       // pane.setHgap(1); //水平

        primaryStage.setResizable(false);

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                Pane cellPane = new Pane();
                cellPane.setPrefSize(40, 40); // 设置单元格大小
                updateCellColor(i, j);  // 初始化时也更新颜色
                pane.add(cellPane, j, i); // 注意:GridPane.add(node, columnIndex, rowIndex)
                 cellPanes[i][j] = cellPane; // 保存Pane引用
            }
        }

        Scene scene = new Scene(pane, 400, 600); // 根据单元格大小调整场景大小
        primaryStage.setScene(scene);
        primaryStage.setTitle("Tetris Grid");
        primaryStage.show();
    }
   //更新单个格子颜色的方法.
   public void updateCellColor(int row, int col) {
        Pane cellPane = cellPanes[row][col]; // 获取对应的Pane
       cellPane.setBackground(new javafx.scene.layout.Background(new javafx.scene.layout.BackgroundFill(colorArray[row][col], null, null)));
    }

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

解释:

  1. 创建 Pane 对象作为每个单元格。
  2. setPrefSize() 设置单元格的 preferred 大小。
  3. updateCellColor() 用于设置对应 Pane 的背景色,使用了colorArray 中的颜色。
  4. pane.add(cellPane, j, i);Pane 添加到 GridPane 的指定位置。注意 add 方法的参数顺序:先列索引,后行索引。
  5. 使用了一个 cellPanes数组保存单元格中每一个Pane.

2. 使用矩形 (Rectangle) 并设置填充色

虽然一开始你说直接添加矩形不行,但可能是方法不对。Rectangle 本身可以设置填充色,正确使用也能实现目标。

原理:

Rectangle 是一个形状节点,可以设置填充颜色 (setFill())。把它添加到 GridPane 作为子节点,就能通过改变填充色来改变单元格的外观。

代码示例:


import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.scene.layout.StackPane;

public class TetrisGridRect extends Application {

   private GridPane pane;
    private final int rows = 15;
    private final int cols = 10;
    private Color[][] colorArray = new Color[rows][cols]; // 假设已初始化
      private Rectangle[][] cellRects = new Rectangle[rows][cols];

    @Override
    public void start(Stage primaryStage) {
       //初始化colorArray,此处随便设置几个
        for (int i = 0; i < rows; i++) {
          for (int j = 0; j < cols; j++) {
             colorArray[i][j] = Color.WHITE; // 默认白色
          }
       }
       colorArray[0][0] = Color.RED;
        colorArray[1][1] = Color.BLUE;
        pane = new GridPane();
        pane.setGridLinesVisible(true);

        primaryStage.setResizable(false);

       for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                Rectangle rect = new Rectangle(40, 40); // 设置矩形大小
                 updateCellColor(i,j);
                pane.add(rect, j, i);
                cellRects[i][j] = rect;
            }
        }
       Scene scene = new Scene(pane, 400, 600);
       primaryStage.setScene(scene);
        primaryStage.setTitle("Tetris Grid with Rectangles");
        primaryStage.show();
    }

     public void updateCellColor(int row, int col) {

         cellRects[row][col].setFill(colorArray[row][col]);
    }

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

解释:
类似第一种, 只是将Pane替换成Rectangle

  1. 创建 Rectangle 对象,并设置其大小。
  2. setFill() 设置矩形的填充颜色。
  3. pane.add(rect, j, i);Rectangle 添加到 GridPane。
  4. 使用了一个 cellRects数组保存单元格中每一个Rectangle.

3. 使用 Canvas (进阶)

如果对性能要求比较高,或者需要更精细的绘图控制,可以使用 Canvas

原理:

Canvas 提供了一个绘图区域,可以在上面直接绘制像素。可以通过计算每个单元格的坐标,然后用指定的颜色填充对应的矩形区域。

代码示例:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class TetrisGridCanvas extends Application {

    private final int rows = 15;
    private final int cols = 10;
    private final int cellSize = 40; // 每个单元格的大小
    private Color[][] colorArray = new Color[rows][cols];
    private Canvas canvas;

    @Override
    public void start(Stage primaryStage) {
        //初始化colorArray,此处随便设置几个
       for (int i = 0; i < rows; i++) {
          for (int j = 0; j < cols; j++) {
             colorArray[i][j] = Color.WHITE; // 默认白色
          }
       }
       colorArray[0][0] = Color.RED;
        colorArray[1][1] = Color.BLUE;

        canvas = new Canvas(cols * cellSize, rows * cellSize);
        Pane root = new Pane(canvas); // 使用 Pane 作为根节点
         drawGrid(); // 初始绘制
        Scene scene = new Scene(root, cols * cellSize, rows * cellSize);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Tetris Grid with Canvas");
        primaryStage.show();
    }

     public void updateCellColor(int row, int col, Color color) {
       colorArray[row][col] = color;
       drawCell(row, col);

    }

    private void drawGrid() {
        GraphicsContext gc = canvas.getGraphicsContext2D();

        // 绘制网格线
        gc.setStroke(Color.LIGHTGRAY);
        for (int i = 0; i <= rows; i++) {
            gc.strokeLine(0, i * cellSize, cols * cellSize, i * cellSize);
        }
        for (int j = 0; j <= cols; j++) {
            gc.strokeLine(j * cellSize, 0, j * cellSize, rows * cellSize);
        }

          // 根据colorArray填充颜色
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
               drawCell(i,j);
            }
        }
    }

    private void drawCell(int row, int col){
        GraphicsContext gc = canvas.getGraphicsContext2D();
          gc.setFill(colorArray[row][col]);
          gc.fillRect(col * cellSize, row * cellSize, cellSize, cellSize);

    }

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

解释:

  1. Canvas 的大小设置为整个游戏区域的大小。
  2. drawGrid() 绘制网格线和初始的单元格颜色。
  3. drawCell()绘制单个方格
  4. 通过updateCellColor来更新colorArray,并调用drawCell()重绘指定单元格

这种方法的优势: 对于大量单元格, 使用Canvas手动绘制, 性能优于创建大量的Pane或Rectangle对象.

安全建议

上述方法都主要集中在 UI 层面。 在实际的俄罗斯方块游戏中,颜色数组 (colorArray) 通常对应着游戏逻辑中的一个数据结构(例如一个二维数组表示的棋盘)。

  • 数据一致性: 确保 UI 上的颜色变化与游戏逻辑中的数据保持同步。 UI 只是数据的可视化表示,不要直接在 UI 上修改游戏数据。
  • 边界检查: 在访问 colorArray 时,注意进行边界检查,防止数组越界。
  • 模块化: 把 UI 渲染和游戏逻辑分开, 方便代码维护和测试。 可以考虑 MVC (Model-View-Controller) 或类似的设计模式。
  • 代码清晰 : 及时更新和重新绘制格子颜色,逻辑应该清晰

以上就是给 GridPane 单元格设置颜色的几种办法。做俄罗斯方块,选哪个都行,看具体需求和个人喜好。希望这些信息有用!