QML上級者向けチュートリアル2 - ゲームキャンバスの作成

JavaScriptでブロックを生成する

さて、いくつかの型を書いたところで、ゲームを書き始めましょう。

最初の仕事はゲームブロックを生成することです。New Gameボタンがクリックされるたびに、ゲーム・キャンバスに新しいランダムなブロックが入力されます。新しいゲームごとに新しいブロックを動的に生成する必要があるので、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 を返した場合(オブジェクトのロード中にエラーが発生した場合)、エラー情報を表示します。
  • ブロックをボード上のその位置に置き、幅と高さを設定する。また、将来参照できるようにブロック配列に格納します。
  • 最後に、何らかの理由でコンポーネントをロードできなかった場合(例えば、ファイルが見つからない場合)、エラー情報をコンソールに表示します。
JavaScriptコンポーネントをQMLに接続する

さて、QMLファイルからsamegame.js のJavaScriptコードを呼び出す必要があります。そのために、samegame.qml に JavaScript ファイルをモジュールとしてインポートする行を追加します:

import "samegame.js" as SameGame

これにより、samegame.js 内の関数を、"SameGame" をプレフィックスとして参照できるようになります。例えば、SameGame.startNewGame()SameGame.createBlock() などです。 つまり、New Game ボタンのonClicked ハンドラを、startNewGame() 関数に、このように接続できるようになります:

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

つまり、New Gameボタンをクリックすると、startNewGame() が呼び出され、このようにブロックのフィールドが生成される:

これで、ブロックの画面ができたので、ゲームの仕組みを追加し始めることができる。

プロジェクト例 @ code.qt.io

© 2025 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.