Game Programming using Qt 5 Beginner’s Guide, 2nd Editio 学习笔记- HeartBeat

Game Programming using Qt 5 Beginner’s Guide, 2nd Editio 学习笔记- HeartBeat

我们现在将扩展我们的组件并实现它的主要功能——绘制一个类似心跳的图表。

HeartBeat.qml

import QtQuick 2.9
import QtQuick.Window 2.2

Canvas {
    id: canvas
    //通过引入lineWidth,我们可以操纵可视化心跳线的宽度
    property int lineWidth: 2
    
    property color color: "black"
    property color topColor: "red"
    property color bottomColor: "blue"
    
    implicitWidth: 600
    implicitHeight: 300
    
    onPaint: {
        //在检索上下文后,我们将画布重置为其初始状态
        var ctx = canvas.getContext("2d");
        ctx.reset();
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        //然后使用 slice() 计算要再次绘制的点数组
        var pointsToDraw = d.points.slice(-canvas.width);
        //我们通过在垂直轴上平移和缩放来准备画布,以便将原点移动到画布高度的一半(
        ctx.translate(0, canvas.height / 2);
        
        // fill:
        //之后,调用 beginPath() 以通知上下文我们开始构建新路径
        ctx.beginPath();
        ctx.moveTo(0, 0);
        var i;
        for(i = 0; i < pointsToDraw.length; i++) {
            //然后,通过附加行逐段构建路径
            //每个值都乘以 canvas.height / 2
            //以便点数组中的值缩放到项目的大小
            ctx.lineTo(i, -pointsToDraw[i] * canvas.height/2);
        }
        ctx.lineTo(i, 0);
        var gradient = ctx.createLinearGradient(
                    0, -canvas.height / 2, 0, canvas.height / 2);
        gradient.addColorStop(0.1, canvas.topColor);
        gradient.addColorStop(0.5, Qt.rgba(1, 1, 1, 0));
        gradient.addColorStop(0.9, canvas.bottomColor);
        ctx.fillStyle = gradient;
        ctx.fill();
        
        // stroke:
        ctx.beginPath();
        ctx.moveTo(0, -pointsToDraw[0] * canvas.height / 2);
        for(i = 1; i < pointsToDraw.length; i++) {
            ctx.lineTo(i, -pointsToDraw[i] * canvas.height / 2);
        }
        ctx.lineWidth = canvas.lineWidth;
        ctx.strokeStyle = canvas.color;
        //我们通过调用stroke()设置笔的宽度并绘制路径
        ctx.stroke();
    }
    
    QtObject {
        id: d
        //points 变量存储已计算的函数值数组
        //我们将它初始化为一个空数组
        property var points: []
        //arg 变量存储最后的函数参数。函数的参数应该在-π到+π的范围内
        //我们将 arg 初始化为 -Math.PI
        property real arg: -Math.PI
        
        function func(argument) {
            var a = (2 * Math.PI / 10);
            var b = 4 * Math.PI / 5;
            return Math.sin(20 * argument) * (
                        Math.exp(-Math.pow(argument / a, 2)) +
                        Math.exp(-Math.pow((argument - b) / a, 2)) +
                        Math.exp(-Math.pow((argument + b) / a, 2))
                        );
        }
        //在 Canvas 部分中,定义修改 arg 值时的处理程序
        onArgChanged: {
            points.push(func(arg));
            //Array.slice() 从点数组中删除最旧的记录
            //以便最多将最后的 canvas.width 项保留在数组中
            //这样我们就可以为画布宽度的每个像素绘制一个点
            points = points.slice(-canvas.width);
            //我们调用 requestPaint(),它相当于 QWidget::update() 并计划重新绘制画布
            //它会调用我们的 onPaint 信号处理程序
            canvas.requestPaint();
        }
    }
    //在 Canvas 部分中,触发图片更新的计时器
    //添加一个定期计时的计时器
    Timer {
        interval: 10
        repeat: true
        running: true
        onTriggered: {
            //将 arg 增加 1°
            //直到达到 +π,在这种情况下,它会重置为初始值
            d.arg += Math.PI / 180;
            while(d.arg >= Math.PI) {
                d.arg -= 2 * Math.PI;
            }
        }
    }
    
    
}

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0

//要应用阴影效果,您需要一个现有项目作为效果源
Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    HeartBeat {
        id: heartBeat
        anchors.centerIn: parent
        visible: false
    }
    //要向 HeartBeat.qml 文件中定义的基于画布的心跳元素添加微妙的黑色阴影
    //我们使用了一个以*Item为中心的 HeartBeat 类的实例
    DropShadow {
        source: heartBeat
            //然后,使用 anchors.fill 元素定义阴影效果
            //其几何形状遵循其源的几何形状
        anchors.fill: heartBeat
        horizontalOffset: 3
        verticalOffset: 3
        radius: 8
        samples: 16
        color: "black"
    }
    /*
    GaussianBlur {
        source: heartBeat
        anchors.fill: heartBeat
        radius: 12
        samples: 20
        transparentBorder: true
    }*/
}

上一篇:Electron IPC(进程间通信)之ipcMain和ipcRenderer


下一篇:Python教程-使用Python解释器