翻譯|使用教程|編輯:鮑佳佳|2021-03-26 10:50:30.540|閱讀 565 次
概述:前三章講了游戲前期搭建,現在我們要做兩件事來活躍游戲:給積木做動畫,并添加一個高分系統。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關鏈接:
Qt是一個跨平臺框架,通常用作圖形工具包,它不僅創建CLI應用程序中非常有用。而且它也可以在三種主要的臺式機操作系統以及移動操作系統(如Symbian,Nokia Belle,Meego Harmattan,MeeGo或BB10)以及嵌入式設備,Android(Necessitas)和iOS的端口上運行?,F在我們為你提供了免費的試用版。
Qt組件推薦:
現在我們要做兩件事來活躍游戲:給積木做動畫,并添加一個高分系統。
我們還清理了應用程序文件的目錄結構。我們現在有很多文件,所以所有samegame.qml以外的JavaScript和QML文件都被移到了一個名為 "content "的新子目錄中。
為了迎接新的塊狀動畫,Block.qml文件現在改名為BoomBlock.qml。
動畫塊運動
首先我們將對塊進行動畫,使它們以流體的方式移動。QML有很多方法來添加流體運動,在這種情況下,我們將使用Behavior類型來添加一個SpringAnimation。在BoomBlock.qml中,我們將SpringAnimation行為應用到x和y屬性中,這樣塊體將以類似彈簧的方式跟隨并向指定的位置移動(其值將由samegame.js設置)。以下是添加到BoomBlock.qml中的代碼。
property bool spawned: false Behavior on x { enabled: spawned; SpringAnimation{ spring: 2; damping: 0.2 } } Behavior on y { SpringAnimation{ spring: 2; damping: 0.2 } }
spring和damping值可以改變,以修改動畫的類似彈簧的作用。
enabled: spawned設置指的是在samegame.js中從createBlock()中設置的spawned值。這保證了只有在createBlock()將塊設置到正確的位置后,才會啟用x上的SpringAnimation。否則,當游戲開始時,塊會從角落(0,0)滑出,而不是成行地從頂部落下。試著注釋出enabled: spawned,然后自己看看)。
動畫塊不透明度變化
接下來,我們將添加一個平滑的退出動畫。為此,我們將使用一個Behavior類型,它允許我們在發生屬性變化時指定一個默認的動畫。在這種情況下,當一個Block的不透明度變化時,我們將對不透明度值進行動畫處理,使其逐漸淡入和淡出,而不是在完全可見和不可見之間突然變化。要做到這一點,我們將在 BoomBlock.qml 中的 Image 類型的不透明度屬性上應用一個 Behavior。
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"; } opacity: 0 Behavior on opacity { NumberAnimation { properties:"opacity"; duration: 200 } } }
請注意不透明度:0,這意味著塊在第一次創建時是透明的。我們可以在創建和銷毀塊時在samegame.js中設置不透明度,但我們將使用狀態,因為這對我們將要添加的下一個動畫很有用。最初,我們將這些狀態添加到BoomBlock.qml的根類型中。
property bool dying: false states: [ State{ name: "AliveState"; when: spawned == true && dying == false PropertyChanges { target: img; opacity: 1 } }, State{ name: "DeathState"; when: dying == true PropertyChanges { target: img; opacity: 0 } } ]
現在,塊會自動淡入,因為我們在實現塊動畫時已經將 spawned 設置為 true。為了淡出,我們將死亡設置為true,而不是在塊被破壞時將不透明度設置為0(在floodFill()函數中)。
添加粒子效果
最后,我們將在積木被破壞時為它們添加一個看起來很酷的粒子效果。要做到這一點,我們首先在BoomBlock.qml中添加一個粒子系統,像這樣。
ParticleSystem { id: sys anchors.centerIn: parent ImageParticle { // ![0] source: { if (type == 0) return "../../shared/pics/redStar.png"; else if (type == 1) return "../../shared/pics/blueStar.png"; else return "../../shared/pics/greenStar.png"; } rotationVelocityVariation: 360 // ![0] } Emitter { id: particles anchors.centerIn: parent emitRate: 0 lifeSpan: 700 velocity: AngleDirection {angleVariation: 360; magnitude: 80; magnitudeVariation: 40} size: 16 } }
要想完全理解這一點,你應該閱讀《使用Qt快速粒子系統》,但需要注意的是,emitRate被設置為零,這樣粒子就不會正常發射了。另外,我們還擴展了垂死狀態,它通過調用粒子類型上的burst()方法來創建粒子的爆發。現在狀態的代碼是這樣的。
states: [ State { name: "AliveState" when: spawned == true && dying == false PropertyChanges { target: img; opacity: 1 } }, State { name: "DeathState" when: dying == true StateChangeScript { script: particles.burst(50); } PropertyChanges { target: img; opacity: 0 } StateChangeScript { script: block.destroy(1000); } } ]
現在,游戲的動畫效果非常漂亮,為玩家的所有動作添加了微妙(或不那么微妙)的動畫。最終的效果如下圖所示,用不同的一組圖片來演示基本的主題。
這里的主題變化只是通過替換塊圖像產生的。這可以在運行時通過改變Image source屬性來完成,所以為了進一步的挑戰,你可以添加一個按鈕來切換不同圖片的主題。
保持高分表
我們可能要添加到游戲中的另一個功能是一種存儲和檢索高分的方法。
要做到這一點,我們將在游戲結束時顯示一個對話框來請求玩家的名字并將其添加到高分表中。這需要對Dialog.qml進行一些修改。除了Text類型之外,現在它還有一個TextInput子項用于接收鍵盤文本輸入。
Rectangle { id: container ... TextInput { id: textInput anchors { verticalCenter: parent.verticalCenter; left: dialogText.right } width: 80 text: "" onAccepted: container.hide() // close dialog when Enter is pressed } ... }
我們還將添加一個showWithInput()函數。只有調用這個函數而不是show(),文本輸入才會可見。當對話框關閉時,它會發出一個closed()信號,其他類型的對話框可以通過inputText屬性檢索用戶輸入的文本。
Rectangle { id: container property string inputText: textInput.text signal closed function show(text) { dialogText.text = text; container.opacity = 1; textInput.opacity = 0; } function showWithInput(text) { show(text); textInput.opacity = 1; textInput.focus = true; textInput.text = "" } function hide() { textInput.focus = false; container.opacity = 0; container.closed(); } ... }
現在可以在samegame.qml中使用該對話框。
Dialog { id: nameInputDialog anchors.centerIn: parent z: 100 onClosed: { if (nameInputDialog.inputText != "") SameGame.saveHighScore(nameInputDialog.inputText); } }
當對話框發出關閉信號時,我們調用samegame.js中新的saveHighScore()函數,將高分存儲在本地的SQL數據庫中,如果可能的話還可以將分數發送到在線數據庫中。
在samegame.js中的victoryCheck()函數中,nameInputDialog被激活。
function victoryCheck() { ... //Check whether game has finished if (deservesBonus || !(floodMoveCheck(0, maxRow - 1, -1))) { gameDuration = new Date() - gameDuration; nameInputDialog.showWithInput("You won! Please enter your name: "); } }
離線存儲高分
現在我們需要實現實際保存高分表的功能。
這里是samegame.js中的saveHighScore()函數。
function saveHighScore(name) { if (scoresURL != "") sendHighScore(name); var db = Sql.LocalStorage.openDatabaseSync("SameGameScores", "1.0", "Local SameGame High Scores", 100); var dataStr = "INSERT INTO Scores VALUES(?, ?, ?, ?)"; var data = [name, gameCanvas.score, maxColumn + "x" + maxRow, Math.floor(gameDuration / 1000)]; db.transaction(function(tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS Scores(name TEXT, score NUMBER, gridSize TEXT, time NUMBER)'); tx.executeSql(dataStr, data); var rs = tx.executeSql('SELECT * FROM Scores WHERE gridSize = "12x17" ORDER BY score desc LIMIT 10'); var r = "\nHIGH SCORES for a standard sized grid\n\n" for (var i = 0; i < rs.rows.length; i++) { r += (i + 1) + ". " + rs.rows.item(i).name + ' got ' + rs.rows.item(i).score + ' points in ' + rs.rows.item(i).time + ' seconds.\n'; } dialog.show(r); }); }
首先,我們調用sendHighScore()(在下面的章節中解釋),如果可以將高分發送到在線數據庫。
然后,我們使用本地存儲API來維護這個應用程序特有的持久化SQL數據庫。我們使用openDatabaseSync()為高分創建一個離線存儲數據庫,并準備好我們要用來保存高分的數據和SQL查詢。離線存儲API使用SQL查詢來進行數據操作和檢索,在db.transaction()調用中,我們使用三個SQL查詢來初始化數據庫(如果需要的話),然后添加到和檢索高分。為了使用返回的數據,我們將其變成一個字符串,每行返回一行,并顯示一個包含該字符串的對話框。
這是本地存儲和顯示高分的一種方式,但肯定不是唯一的方式。一個更復雜的選擇是創建一個高分對話框組件,并將結果傳遞給它進行處理和顯示(而不是重復使用Dialog)。這將允許一個更有主題的對話框,可以更好地展示高分。如果你的QML是一個C++應用的UI,你也可以將分數傳遞給一個C++函數,以多種方式將其存儲在本地,包括不用SQL的簡單格式或另一個SQL數據庫中。
在線存儲高分
你已經看到了如何在本地存儲高分,但也很容易在你的QML應用程序中集成一個支持網絡的高分存儲。我們對她的實現非常簡單:將高分數據發布到某個服務器上運行的php腳本中,然后該服務器將其存儲并顯示給訪問者。你也可以從同一個服務器上請求一個XML或QML文件,其中包含并顯示分數,但這超出了本教程的范圍。我們在這里使用的php腳本可以在examples目錄下找到。
如果玩家輸入了他們的名字,我們可以將數據發送到網絡服務中,我們
如果玩家輸入一個名字,我們就用samegame.js中的這段代碼將數據發送到服務。
function sendHighScore(name) { var postman = new XMLHttpRequest() var postData = "name=" + name + "&score=" + gameCanvas.score + "&gridSize=" + maxColumn + "x" + maxRow + "&time=" + Math.floor(gameDuration / 1000); postman.open("POST", scoresURL, true); postman.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); postman.onreadystatechange = function() { if (postman.readyState == postman.DONE) { dialog.show("Your score has been uploaded."); } } postman.send(postData); }
這段代碼中的XMLHttpRequest與標準瀏覽器JavaScript中的XMLHttpRequest()是一樣的,可以用同樣的方式從web服務中動態獲取XML或QML來顯示高分。在這種情況下,我們不用擔心響應--我們只是將高分數據發布到web服務器上。如果它返回了一個QML文件(或一個QML文件的URL),你可以用與塊相同的方式來實例化它。
#### 未完待續持續更新
====================================================
想要了解或購買Qt正版授權的朋友,歡迎
Qt技術交流群現已開通,QQ搜索群號“765444821”或者掃描下方二維碼即可加入
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自: