Qt开发案例实战:QML高级教程3-实施游戏逻辑

Qt是一个跨平台框架,通常用作图形工具包,它不仅创建CLI应用程序中非常有用。而且它也可以在三种主要的台式机操作系统以及移动操作系统(如Symbian,Nokia Belle,Meego Harmattan,MeeGo或BB10)以及嵌入式设备,Android(Necessitas)和iOS的端口上运行。现在我们为你提供了免费的试用版。

下载Qt6最新试用版

Qt组件推荐:

  • QtitanRibbon下载试用: 遵循Microsoft Ribbon UI Paradigm for Qt技术的Ribbon UI组件,致力于为Windows、Linux和Mac OS X提供功能完整的Ribbon组件。
  • QtitanChart | 下载试用 :是一个C ++库,代表一组控件,这些控件使您可以快速地为应用程序提供漂亮而丰富的图表。并且支持所有主要的桌面。
  • QtitanNavigation | 下载试用 :模拟Microsoft Dynamics CRM-2016/Office 365导航界面和一组控件改善Qt.C ++应用程序用户体验的QtitanNavigation组件。

通过前两章的讲解(创建游戏画布和块填充游戏画布),现在我们已经拥有了所有游戏组件,可以添加游戏逻辑了,该逻辑规定玩家如何与积木互动以及如何玩游戏,直到赢或输。

为此,我们将以下功能添加到samegame.js:

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

由于这是关于QML的教程,而不是游戏设计的教程,因此我们将仅在下面进行讨论handleClick(),victoryCheck()因为它们直接与QML类型交互。请注意,尽管此处的游戏逻辑是用JavaScript编写的。

启用鼠标单击交互

为了更方便的JavaScript代码接口与QML类型,我们增加了叫做项目gameCanvas来samegame.qml。它将背景替换为包含块的项目。它还接受来自用户的鼠标输入。这是商品代码:

  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: SameGame.handleClick(mouse.x, mouse.y)
            }
        }

gameCanvas项是棋盘的精确尺寸,并有一个分数属性和一个MouseArea来处理鼠标点击。块现在被创建为它的子项目,它的尺寸被用来确定棋盘的大小,这样应用程序就可以根据可用的屏幕尺寸进行缩放。由于它的尺寸被绑定到blockSize的倍数上,blockSize被移出了samegame.js,作为一个QML属性移到了samegame.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();
}

请注意,如果score是samegame.js文件中的全局变量,则将无法绑定到该文件。您只能绑定到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如果游戏结束,则更新值并显示“ Game Over”对话框。

“游戏结束”对话框是使用Dialog中定义的类型创建的Dialog.qml。这是Dialog.qml代码。注意如何通过功能和信号从脚本文件中强制使用它:

import QtQuick 2.0

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。

色彩冲刺

如果所有块都具有相同的颜色,玩“同一个游戏”并没有什么乐趣,因此我们修改了createBlock()函数,samegame.js以便每次调用时随机创建不同类型的块(用于红色,绿色或蓝色)。Block.qml还进行了更改,以便每个块包含一个不同的图像,具体取决于其类型:

import QtQuick 2.0

Item {
    id: block

    property int type: 0

    Image {
        id: img

        anchors.fill: parent
        source: {
            if (type == 0)
                return "../shared/pics/redStone.png";
            else if (type == 1)
                return "../shared/pics/blueStone.png";
            else
                return "../shared/pics/greenStone.png";
        }
    }
}

工作游戏

现在我们有了一款可以正常运行的游戏!可以单击块,玩家可以得分,游戏可以结束(然后您可以开始一个新的)。这是到目前为止已完成的屏幕截图:

这是现在的samegame.qml样子:

import QtQuick 2.0
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: "../shared/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: 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专家,则可以在第一次迭代中编写这些内容,但是在本教程中,我们将在下一章节中进行讲解----您的应用程序将在此活跃起来!

====================================================

Qt技术交流群现已开通,QQ搜索群号“765444821或者扫描下方二维码即可加入

猜你喜欢

转载自blog.csdn.net/qq_42444778/article/details/115196450