QML 고급 튜토리얼 3 - 게임 로직 구현하기
플레이 가능한 게임 만들기
이제 모든 게임 컴포넌트가 준비되었으므로 플레이어가 블록과 상호작용하고 게임이 승패가 결정될 때까지 게임을 플레이하는 방법을 지시하는 게임 로직을 추가할 수 있습니다.
이를 위해 samegame.js
에 다음 함수를 추가했습니다:
handleClick(x,y)
floodFill(xIdx,yIdx,type)
shuffleDown()
victoryCheck()
floodMoveCheck(xIdx, yIdx, type)
이 튜토리얼은 게임 디자인이 아닌 QML에 대한 튜토리얼이므로 아래에서는 handleClick()
와 victoryCheck()
에 대해서만 설명하겠습니다. 여기서의 게임 로직은 자바스크립트로 작성되었지만 C++로 작성한 다음 QML에 노출할 수도 있습니다.
마우스 클릭 인터랙션 활성화
자바스크립트 코드가 QML 유형과 쉽게 인터페이스할 수 있도록 samegame.qml
에 gameCanvas
이라는 항목을 추가했습니다. 이 항목은 배경을 블록이 포함된 항목으로 대체합니다. 또한 사용자의 마우스 입력도 허용합니다. 다음은 항목 코드입니다:
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
의 배수로 바인딩되므로 blockSize
은 samegame.js
에서 samegame.qml
으로 이동되어 QML 속성으로 지정되었습니다. 스크립트에서 여전히 액세스할 수 있습니다.
클릭하면 MouseArea 은 samegame.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.js
의 createBlock()
함수를 수정하여 호출될 때마다 다른 유형의 블록(빨간색, 녹색 또는 파란색)을 무작위로 생성하도록 했습니다. 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 전문가라면 첫 번째 반복에서 이러한 내용을 작성할 수 있었지만 이 튜토리얼에서는 애플리케이션이 살아 움직이는 다음 장까지 저장해 두었습니다!
© 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.