本页内容

QML 高级教程 2 - 为游戏画布填充内容

使用 JavaScript 生成方块

既然我们已经定义了一些类型,接下来就开始编写游戏吧。

首要任务是生成游戏方块。每次点击“新游戏”按钮时,游戏画布都会填充一组新的随机方块。由于我们需要为每局新游戏动态生成新的方块,因此无法使用Repeater 来定义方块。取而代之,我们将使用JavaScript来创建方块。

以下是用于生成方块的 JavaScript 代码,保存在新文件 `samegame.js` 中。代码说明如下。

var blockSize = 40;
var maxColumn = 10;
var maxRow = 15;
var maxIndex = maxColumn * maxRow;
var board = new Array(maxIndex);
var component;

//Index function used instead of a 2D array
function index(column, row) {
    return column + (row * maxColumn);
}

function startNewGame() {
    //Delete blocks from previous game
    for (var i = 0; i < maxIndex; i++) {
        if (board[i] != null)
            board[i].destroy();
    }

    //Calculate board size
    maxColumn = Math.floor(background.width / blockSize);
    maxRow = Math.floor(background.height / blockSize);
    maxIndex = maxRow * maxColumn;

    //Initialize Board
    board = new Array(maxIndex);
    for (var column = 0; column < maxColumn; column++) {
        for (var row = 0; row < maxRow; row++) {
            board[index(column, row)] = null;
            createBlock(column, row);
        }
    }
}

function createBlock(column, row) {
    if (component == null)
        component = Qt.createComponent("Block.qml");

    // Note that if Block.qml was not a local file, component.status would be
    // Loading and we should wait for the component's statusChanged() signal to
    // know when the file is downloaded and ready before calling createObject().
    if (component.status == Component.Ready) {
        var dynamicObject = component.createObject(background);
        if (dynamicObject == null) {
            console.log("error creating block");
            console.log(component.errorString());
            return false;
        }
        dynamicObject.x = column * blockSize;
        dynamicObject.y = row * blockSize;
        dynamicObject.width = blockSize;
        dynamicObject.height = blockSize;
        board[index(column, row)] = dynamicObject;
    } else {
        console.log("error loading block component");
        console.log(component.errorString());
        return false;
    }
    return true;
}

startNewGame() 函数会删除上一局游戏中生成的方块,并计算填满新游戏窗口所需的方块行数和列数。随后,它创建一个数组来存储所有游戏方块,并调用createBlock() 来生成足以填满游戏窗口的方块。

createBlock() 函数从Block.qml 文件中创建一个方块,并将新方块移动到游戏画布上的指定位置。这涉及以下几个步骤:

  • Qt.createComponent调用 () 从Block.qml 中生成一个类型。如果组件已就绪,我们可以调用createObject() 来创建Block 项的实例。
  • 如果createObject() 返回 null(即加载对象时发生错误),则打印错误信息。
  • 将该积木放置在画板上的指定位置,并设置其宽度和高度。此外,将其存储在 blocks 数组中以便日后引用。
  • 最后,如果组件因某种原因无法加载(例如文件缺失),请将错误信息打印到控制台。
将 JavaScript 组件连接到 QML

现在,我们需要从 QML 文件中调用samegame.js 中的 JavaScript 代码。为此,我们需在samegame.qml 中添加以下代码行,将该 JavaScript 文件作为模块导入:

import "samegame.js" as SameGame

这样,我们就可以使用“SameGame”作为前缀来引用samegame.js 中的任何函数:例如,SameGame.startNewGame() 或SameGame.createBlock() 。这意味着现在我们可以将“新游戏”按钮的onClicked 处理程序连接到startNewGame() 函数,如下所示:

        Button {
            anchors { left: parent.left; verticalCenter: parent.verticalCenter }
            text: "New Game"
            onClicked: SameGame.startNewGame()
        }

因此,当你点击“新游戏”按钮时,会调用startNewGame() 并生成一个由方块组成的场景,如下所示:

游戏画布上填充了一组方块网格

现在,我们已经有了一个由积木组成的屏幕,可以开始添加游戏机制了。

示例项目 @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.