QML 고급 튜토리얼 3 - 게임 로직 구현하기

플레이 가능한 게임 만들기

이제 모든 게임 컴포넌트가 준비되었으므로 플레이어가 블록과 상호작용하고 게임이 승패가 결정될 때까지 게임을 플레이하는 방법을 지시하는 게임 로직을 추가할 수 있습니다.

이를 위해 samegame.js 에 다음 함수를 추가했습니다:

  • handleClick(x,y)
  • floodFill(xIdx,yIdx,type)
  • shuffleDown()
  • victoryCheck()
  • floodMoveCheck(xIdx, yIdx, type)

이 튜토리얼은 게임 디자인이 아닌 QML에 대한 튜토리얼이므로 아래에서는 handleClick()victoryCheck() 에 대해서만 설명하겠습니다. 여기서의 게임 로직은 자바스크립트로 작성되었지만 C++로 작성한 다음 QML에 노출할 수도 있습니다.

마우스 클릭 인터랙션 활성화

자바스크립트 코드가 QML 유형과 쉽게 인터페이스할 수 있도록 samegame.qmlgameCanvas 이라는 항목을 추가했습니다. 이 항목은 배경을 블록이 포함된 항목으로 대체합니다. 또한 사용자의 마우스 입력도 허용합니다. 다음은 항목 코드입니다:

        Item {
            id: gameCanvas

            property int score: 0
            property int blockSize: 40

            width: parent.width - (parent.width % blockSize)
            height: parent.height - (parent.height % blockSize)
            anchors.centerIn: parent

            MouseArea {
                anchors.fill: parent
                onClicked: (mouse)=> SameGame.handleClick(mouse.x, mouse.y)
            }
        }

gameCanvas 항목은 보드의 정확한 크기이며 score 프로퍼티와 마우스 클릭을 처리하는 MouseArea 프로퍼티가 있습니다. 이제 블록이 자식으로 생성되고 그 크기가 보드 크기를 결정하는 데 사용되므로 애플리케이션이 사용 가능한 화면 크기에 맞게 확장됩니다. 크기가 blockSize 의 배수로 바인딩되므로 blockSizesamegame.js 에서 samegame.qml 으로 이동되어 QML 속성으로 지정되었습니다. 스크립트에서 여전히 액세스할 수 있습니다.

클릭하면 MouseAreasamegame.js 에서 handleClick() 을 호출하여 플레이어의 클릭으로 인해 블록이 제거될지 여부를 결정하고 필요한 경우 gameCanvas.score 을 현재 점수로 업데이트합니다. 다음은 handleClick() 함수입니다:

function handleClick(xPos, yPos) {
    var column = Math.floor(xPos / gameCanvas.blockSize);
    var row = Math.floor(yPos / gameCanvas.blockSize);
    if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
        return;
    if (board[index(column, row)] == null)
        return;
    //If it's a valid block, remove it and all connected (does nothing if it's not connected)
    floodFill(column, row, -1);
    if (fillFound <= 0)
        return;
    gameCanvas.score += (fillFound - 1) * (fillFound - 1);
    shuffleDown();
    victoryCheck();
}

samegame.js 파일에 score 가 전역 변수인 경우 바인딩할 수 없다는 점에 유의하세요. QML 프로퍼티에만 바인딩할 수 있습니다.

점수 업데이트하기

플레이어가 블록을 클릭하고 handleClick() 을 트리거하면 handleClick()victoryCheck() 을 호출하여 점수를 업데이트하고 플레이어가 게임을 완료했는지 확인합니다. 다음은 victoryCheck() 코드입니다:

function victoryCheck() {
    //Award bonus points if no blocks left
    var deservesBonus = true;
    for (var column = maxColumn - 1; column >= 0; column--)
        if (board[index(column, maxRow - 1)] != null)
        deservesBonus = false;
    if (deservesBonus)
        gameCanvas.score += 500;

    //Check whether game has finished
    if (deservesBonus || !(floodMoveCheck(0, maxRow - 1, -1)))
        dialog.show("Game Over. Your score is " + gameCanvas.score);
}

이렇게 하면 gameCanvas.score 값이 업데이트되고 게임이 완료되면 "게임 종료" 대화 상자가 표시됩니다.

게임 종료 대화 상자는 Dialog.qml 에 정의된 Dialog 유형을 사용하여 생성됩니다. 다음은 Dialog.qml 코드입니다. 스크립트 파일에서 함수와 시그널을 통해 바로 사용할 수 있도록 설계된 것을 주목하세요:

import QtQuick

Rectangle {
    id: container

    function show(text) {
        dialogText.text = text;
        container.opacity = 1;
    }

    function hide() {
        container.opacity = 0;
    }

    width: dialogText.width + 20
    height: dialogText.height + 20
    opacity: 0

    Text {
        id: dialogText
        anchors.centerIn: parent
        text: ""
    }

    MouseArea {
        anchors.fill: parent
        onClicked: hide();
    }
}

그리고 이것이 기본 samegame.qml 파일에서 사용되는 방식입니다:

    Dialog {
        id: dialog
        anchors.centerIn: parent
        z: 100
    }

대화 상자에 z 값을 100으로 지정하여 다른 컴포넌트 위에 표시되도록 합니다. 항목의 기본 z 값은 0입니다.

색채의 대시

모든 블록이 같은 색이면 같은 게임을 플레이하는 재미가 떨어지기 때문에 samegame.jscreateBlock() 함수를 수정하여 호출될 때마다 다른 유형의 블록(빨간색, 녹색 또는 파란색)을 무작위로 생성하도록 했습니다. Block.qml 또한 각 블록이 유형에 따라 다른 이미지를 포함하도록 변경했습니다:

import QtQuick

Item {
    id: block

    property int type: 0

    Image {
        id: img

        anchors.fill: parent
        source: {
            if (type == 0)
                return "pics/redStone.png";
            else if (type == 1)
                return "pics/blueStone.png";
            else
                return "pics/greenStone.png";
        }
    }
}
작동하는 게임

이제 작동하는 게임이 생겼습니다! 블록을 클릭하고, 플레이어가 점수를 획득하고, 게임을 종료할 수 있습니다(그리고 새 게임을 시작할 수 있습니다). 다음은 지금까지 완료된 작업의 스크린샷입니다:

현재 samegame.qml 의 모습입니다:

import QtQuick
import "samegame.js" as SameGame

Rectangle {
    id: screen

    width: 490; height: 720

    SystemPalette { id: activePalette }

    Item {
        width: parent.width
        anchors { top: parent.top; bottom: toolBar.top }

        Image {
            id: background
            anchors.fill: parent
            source: "pics/background.jpg"
            fillMode: Image.PreserveAspectCrop
        }

        Item {
            id: gameCanvas

            property int score: 0
            property int blockSize: 40

            width: parent.width - (parent.width % blockSize)
            height: parent.height - (parent.height % blockSize)
            anchors.centerIn: parent

            MouseArea {
                anchors.fill: parent
                onClicked: (mouse)=> SameGame.handleClick(mouse.x, mouse.y)
            }
        }
    }

    Dialog {
        id: dialog
        anchors.centerIn: parent
        z: 100
    }

    Rectangle {
        id: toolBar
        width: parent.width; height: 30
        color: activePalette.window
        anchors.bottom: screen.bottom

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

        Text {
            id: score
            anchors { right: parent.right; verticalCenter: parent.verticalCenter }
            text: "Score: Who knows?"
        }
    }
}

게임은 작동하지만 지금은 조금 지루합니다. 부드러운 애니메이션 전환은 어디 있나요? 높은 점수가 나오는 부분은 어디인가요? QML 전문가라면 첫 번째 반복에서 이러한 내용을 작성할 수 있었지만 이 튜토리얼에서는 애플리케이션이 살아 움직이는 다음 장까지 저장해 두었습니다!

예제 프로젝트 @ 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.