接上篇《qml自学笔记------自己写类似于劲舞团的按键小游戏(上)》
第三部分DisplayPart.qml
代码的其他部分都是渣,就这里花了点时间,整个小游戏就靠这个文件。
首先,屏幕上要随机的滑过空格或者箭头,每一个图片就是一个项目,那么就要动态的创建项目。动态创建项目方法有三种(我所知道的),第一种是通过JavaScript调用Qt.createComponent(),Qt.createQmlObject()来创建对象,这里要注意的是创建时必须传父对象,因为图形项目没有父对象是无法显示在场景上的;第二种是使用重复器Repeater,但是Repeater元素是用来创建大量相似项目的;第三种是使用Loader元素加载组件创建对象,Loader元素可以使用source属性加载一个QML文件或者使用sourceComponent属性创建一个对象,但是如果source或者sourceComponent更改了,任何先前实例化的项目都会被销毁;在本游戏中source肯定要随机切换,所以不能选第三种,各个对象之间也是不一样的,所以我选了第一种方法使用JS调用来动态创建对象。
并且,使用JS来产生随机数也非常简单,使用Math.random()调用就好。要是使用QML来产生随机数我还真不会。
随机问题解决了就使用Timer定时器,定时的动态创建项目。interval属性设置时间间隔,单位毫秒;repeat属性设置是否重复触发;running属性设置定时器的开启关闭;onTriggered属性设置处理函数,等等。。。
然后就是最头疼的判决是否得分的问题了,一开始我想的实现方法是当项目到达某个坐标时开始计时,到走出计时结束,在计时的这段时间里看是否有跟项目图片一致的按键事件,而且根据时间距离中心时间的长短来判决得分是perfect、good或者OK等等级,经过一番折腾,诶... 毕竟是做工控的,没做过游戏,有点难度(这又让我想起了那丑陋的界面,诶... 感觉自己完全没有艺术细胞呀)。于是我换了一种思路,当按键按下时,判决处于某坐标的项目的图片是否和按键事件是一样的,这样会简单很多,于是就有了如下代码。
import QtQuick 1.1
Rectangle {
id: m_displayPart
property bool timerRunning: false
function startGame(){
var rand = Math.floor(5*Math.random()+1);
switch(rand){
case 1:
var componetImageUP = Qt.createComponent("ImageUp.qml");
componetImageUP.createObject(rowDisplay);
break;
case 2:
var componetImageDown = Qt.createComponent("ImageDown.qml");
componetImageDown.createObject(rowDisplay);
break;
case 3:
var componetImageLeft = Qt.createComponent("ImageLeft.qml");
componetImageLeft.createObject(rowDisplay);
break;
case 4:
var componetImageRight = Qt.createComponent("ImageRight.qml");
componetImageRight.createObject(rowDisplay);
break;
case 5:
var componetImageSpace = Qt.createComponent("ImageSpace.qml");
componetImageSpace.createObject(rowDisplay);
break;
default:
break;
}
//imageLoader.source = "ImageUp.qml"
if(++mainWindow.currentNum > 99) {
displayPart.timerRunning = false;
pauseButton.pauseText = "重新开始";
pauseButton.stat = false;
}
}
function score(){
m_displayPart.color = "lightgreen";
mainWindow.currentScore++;
//console.log("score!");
}
function unScore(){
m_displayPart.color = "red";
//console.log("un score!");
}
width: 500
height: 200
color: "lightblue"
Rectangle {
id: rowDisplay
z: 1; width: 500;
anchors.verticalCenter: parent.verticalCenter
focus: true
Keys.onPressed: {
if(childAt(250,0)===null) {
unScore();
}
else if( (event.key===Qt.Key_Up)&&(childAt(250,0).getValue()===1) ) {
score();
}
else if( (event.key === Qt.Key_Down)&&(childAt(250,0).getValue()===2) ) {
score();
}
else if( (event.key === Qt.Key_Left)&&(childAt(250,0).getValue()===3) ) {
score();
}
else if( (event.key === Qt.Key_Right)&&(childAt(250,0).getValue()===4) )
score();
else if( (event.key === Qt.Key_Space)&&(childAt(250,0).getValue()===5) )
score();
else
unScore();
//event.accepted = true;
}
Keys.onReleased: {m_displayPart.color = "lightblue"}
}
Rectangle {
id: pjLine
width: 10; height: parent.height
z: 0
color: "pink"
anchors.horizontalCenter: parent.horizontalCenter
}
Timer {
id: timerDisplay
interval: 600
running: timerRunning
repeat: true
onTriggered: startGame();
}
}
五个文件很类似,以ImageUp为例。使用source属性加载图片;使用states属性设置状态;使用transitions属性设置切换效果。
这个效果大概就是先创建,等创建完成后从x=0的位置滑动到x=500的位置,历时duration:3000毫秒,滑动效果用easing.type: Easing.InOutQuad来设置。
import QtQuick 1.1
Image {
id: upimage
function getValue(){
return 1;
}
width: 60
height: 60
anchors.verticalCenter: parent.verticalCenter
source: "../img/up.png"
states: State {
name: "loaded"; when: upimage.status === Image.Ready
PropertyChanges { target: upimage; x: 500}
}
transitions: Transition {
NumberAnimation {
to: 500; from: 0
duration: 3000
properties: "x"; easing.type: Easing.InOutQuad
}
}
}