QML学习
工程目录
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/7474c11a93324979b9739acf41c3b6c6.png#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ad95fcfd9ff54bbc84e219ebac17a139.png#pic_center)
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtGraphicalEffects 1.15
import "game.js" as Game
Window {
width: 480
height: 640
minimumWidth: 480
maximumWidth: 480
minimumHeight: 640
maximumHeight: 640
visible: true
title: qsTr("Canvas Game")
Canvas {
id: canvas
anchors.fill: parent
// 得分
property int score: 0
// 准度宽松系数
property int loose: 200
onPaint: {
var ctx = getContext('2d')
// 绘制背景
drawBackground(ctx)
// 界面刷新
draw(ctx)
}
function drawBackground(ctx) {
ctx.setLineDash([1, 5, 1, 1, 5])
ctx.lineWidth = 2
ctx.strokeStyle = "#e1ad0f"
ctx.lineCap = "round"
// 画边框
ctx.beginPath()
ctx.moveTo(180, 0)
ctx.lineTo(0, 640)
ctx.stroke();
ctx.beginPath()
ctx.moveTo(300, 0)
ctx.lineTo(480, 640)
ctx.stroke()
// 音符线
ctx.setLineDash([3])
ctx.beginPath()
ctx.moveTo(18, 576)
ctx.lineTo(462, 576)
ctx.stroke()
// 画轨道
ctx.setLineDash([1, 4, 5])
ctx.beginPath()
ctx.moveTo(200, 0)
ctx.lineTo(80, 640)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(220, 0)
ctx.lineTo(160, 640)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(240, 0)
ctx.lineTo(240, 640)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(260, 0)
ctx.lineTo(320, 640)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(280, 0)
ctx.lineTo(400, 640)
ctx.stroke()
}
// 分数显示
Text{
anchors.centerIn: parent
font{
pointSize: 40
bold: true
}
text: canvas.score
}
// 界面刷新
function draw(ctx) {
Game.process(ctx)
// 平滑动画效果
requestAnimationFrame(draw);
}
// 生成音符
Timer {
interval: 200
repeat: true
running: true
onTriggered: {
// 计算在第几条轨道上生成
var randomNumber = Math.floor(Math.random() * 6.99)
Game.generatedNote(canvas, randomNumber)
}
}
// 音符越界
Timer {
interval: 20
repeat: true
running: true
onTriggered: {
Game.noteOver(canvas)
}
}
// 按键触发
focus: true
Keys.onPressed: {
Game.pressedKeys(canvas, event.key)
}
}
}
Note.qml
import QtQuick 2.15
Item {
id: item
// 轨道序号
required property var number
Rectangle {
anchors.fill: parent
radius: 10
gradient: Gradient {
GradientStop { position: 0.0; color: "#ffffff" }
GradientStop { position: 1.0; color: "#0004bd" }
}
}
}
game.js
.import QtQuick 2.15 as QQ
// 音符集合
var notes = Array()
// 界面刷新
function process(ctx) {
// 重新计算每个计算音符 x, y, width, height
for (var i=0; i<notes.length; i++) {
var note = notes[i]
note.y += 4
var scale = note.y/640
note.x = (1-scale)*180 + (480-(1-scale)*180*2)/6*(note.number-1)
note.width = 20 + scale*60
note.height = 10 + scale*54
}
}
// 生成音符
function generatedNote(canvas, number) {
if (number === 0) return
var noteComponent = Qt.createComponent("Note.qml")
if (noteComponent.status === QQ.Component.Ready) {
var note = noteComponent.createObject(canvas, {
x: 180+(number-1)*20,
y: 0,
width: 20,
height: 10,
number: number
});
notes.push(note)
}
}
// 音符越界
function noteOver(canvas){
for (var i=0; i<notes.length; i++) {
var note = notes[i]
if (note.y > (640 + canvas.loose/2)){
canvas.score = 0
note.destroy()
notes[i] = null
notes.splice(i, 1)
}
}
}
// 按键触发
function pressedKeys(canvas, key) {
switch (key) {
case Qt.Key_S:
noteKey(canvas, 1)
break
case Qt.Key_D:
noteKey(canvas, 2)
break
case Qt.Key_F:
noteKey(canvas, 3)
break
case Qt.Key_J:
noteKey(canvas, 4)
break
case Qt.Key_K:
noteKey(canvas, 5)
break
case Qt.Key_L:
noteKey(canvas, 6)
break
default:
console.log("other key pressed")
break
}
}
// 按键位置判断
function noteKey(canvas, number) {
var result = false
for (var i=0; i<notes.length; i++) {
if (notes[i].number === number) {
// 判断当前位置是否在击打键附近,
var note = notes[i]
var noteCentreX = note.x + note.width/2
var noteCentreY = note.y + note.height/2
var keyCentreX = 80*(number-1) + 40
var keyCentreY = 608
var dx = noteCentreX - keyCentreX
var dy = noteCentreY - keyCentreY
var distance = Math.sqrt(dx * dx + dy * dy)
if (distance < canvas.loose) {
result = true
note.destroy()
notes[i] = null
notes.splice(i, 1)
}
}
}
if (result === true){
canvas.score += 1
} else {
canvas.score = 0
}
}
演示