Qt Quick综合示例小游戏Maroon in Trouble(2)

907 阅读4分钟

本文已参加【新人创作礼】活动,一起开启掘金创作之路。


📒博客首页:何名取 的个人主页 - 文章 - 掘金 (juejin.cn)
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
❤️期待一起交流!
🙏作者水平很有限,如果发现错误,求告知,多谢!
🌺有问题可私信交流!!!


创建屏幕

前言

上节已经对Maroon in Trouble小游戏进行了简单介绍,介绍游戏的玩法时可以明确地知道此游戏有三个背景界面,分别是游戏的开始界面、游戏中界面和游戏结束界面。本节先介绍一下游戏文件的整体结构,然后对游戏的开始界面、游戏中界面和游戏结束界面分解并研究学习。

文件结构

Maroon in Trouble由资源文件、js逻辑和qml组件组成。 image.png 其中资源文件中包含audio游戏音效和gfx图片文件。

image.png qml部分的主文件是maroon.qml文件。游戏的开始界面、游戏中界面和游戏结束界面分别是:

  • NewGameScreen.qml
  • GameCanvas.qml
  • GameOverScreen.qml

游戏开始界面

maroon1.gif 从图中我们可以看到有背景图片、阳光、暗流、气泡、logo、小黄鱼和一个按钮。背景、logo和开始按钮都是静态地,不需要动画或者粒子系统。从水底向上浮动的气泡是粒子系统发射的,而在气泡中游动的小黄鱼使用的是循环的动画效果,在它周围笼罩它的气泡也是一样的。

上浮的气泡

其中从海底向上浮动的气泡在整个游戏过程中也是持续存在的,因此将发射气泡的粒子系统放置在主文件中。在maroon.qml中编写代码:

        ParticleSystem {
            id: particles
            anchors.fill: parent

            ImageParticle {
                id: bubble
                anchors.fill: parent
                source: "content/gfx/catch.png"
                opacity: 0.25
            }

            Wander {
                xVariance: 25;
                pace: 25;
            }

            Emitter {
                width: parent.width
                height: 150
                anchors.bottom: parent.bottom
                anchors.bottomMargin: 3
                startTime: 15000

                emitRate: 2
                lifeSpan: 15000

                acceleration: PointDirection{ y: -6; xVariation: 2; yVariation: 2 }

                size: 24
                sizeVariation: 16
            }
        }

这里的气泡发射系统对QML中粒子系统的使用比较完整,将粒子系统的四个组成全部用到了,包括ParticleSystem粒子系统、ImageParticle渲染器、Emitter发射器和Wander影响器。

游动的小黄鱼

接下来是小黄鱼的游动动画:

    Image {
        source: "gfx/logo-fish.png"
        anchors.top: parent.top

        SequentialAnimation on x {
            loops: Animation.Infinite
            NumberAnimation { from: x + 148; to: x + 25; duration: 2000; easing.type: Easing.InOutQuad }
            NumberAnimation { from: x + 25; to: x + 148; duration: 1600; easing.type: Easing.InOutQuad }
        }
        SequentialAnimation on anchors.topMargin {
            loops: Animation.Infinite
            NumberAnimation { from: 100; to: 60; duration: 1600; easing.type: Easing.InOutQuad }
            NumberAnimation { from: 60; to: 100; duration: 2000; easing.type: Easing.InOutQuad }
        }
    }

小黄鱼的游动使用的是顺序动画,改变图片的x和锚的位置即可实现斜向的循环运动。

气泡的动画与小黄鱼的游动基本类似,与小黄鱼的区别在于图片本身的宽度也会产生变化。

    Image {
        source: "gfx/logo-bubble.png"
        anchors.top: parent.top

        SequentialAnimation on x {
            loops: Animation.Infinite
            NumberAnimation { from: x + 140; to: x + 40; duration: 2000; easing.type: Easing.InOutQuad }
            NumberAnimation { from: x + 40; to: x + 140; duration: 1600; easing.type: Easing.InOutQuad }
        }
        SequentialAnimation on anchors.topMargin {
            loops: Animation.Infinite
            NumberAnimation { from: 100; to: 60; duration: 1600; easing.type: Easing.InOutQuad }
            NumberAnimation { from: 60; to: 100; duration: 2000; easing.type: Easing.InOutQuad }
        }
        SequentialAnimation on width {
            loops: Animation.Infinite
            NumberAnimation { from: 140; to: 160; duration: 1000; easing.type: Easing.InOutQuad }
            NumberAnimation { from: 160; to: 140; duration: 800; easing.type: Easing.InOutQuad }
        }
        SequentialAnimation on height {
            loops: Animation.Infinite
            NumberAnimation { from: 150; to: 140; duration: 800; easing.type: Easing.InOutQuad }
            NumberAnimation { from: 140; to: 150; duration: 1000; easing.type: Easing.InOutQuad }
        }
    }

maroon4.gif

此时的游戏开始界面就已经有了上浮的气泡,游动的小黄鱼了,另外还需要一些照到海底的阳光和涌动的暗流。

海底阳光与暗流

暗流分为上下交错的两部分,使用Row横向排列来布局两个wave波浪图片,这样做的意义在于将两张图片拼接起来,在将波浪做成动画效果时无缝衔接,不会有突然的断隔。

            Row {
                height: childrenRect.height
                Image {
                    id: wave
                    y: 30
                    source:"content/gfx/wave.png"
                }
                Image {
                    y: 30
                    source:"content/gfx/wave.png"
                }
                NumberAnimation on x { from: 0; to: -(wave.width); duration: 16000; loops: Animation.Infinite }
                SequentialAnimation on y {
                    loops: Animation.Infinite
                    NumberAnimation { from: y - 2; to: y + 2; duration: 1600; easing.type: Easing.InOutQuad }
                    NumberAnimation { from: y + 2; to: y - 2; duration: 1600; easing.type: Easing.InOutQuad }
                }
            }

            Row {
                opacity: 0.5
                Image {
                    id: wave2
                    y: 25
                    source: "content/gfx/wave.png"
                }
                Image {
                    y: 25
                    source: "content/gfx/wave.png"
                }
                NumberAnimation on x { from: -(wave2.width); to: 0; duration: 32000; loops: Animation.Infinite }
                SequentialAnimation on y {
                    loops: Animation.Infinite
                    NumberAnimation { from: y + 2; to: y - 2; duration: 1600; easing.type: Easing.InOutQuad }
                    NumberAnimation { from: y - 2; to: y + 2; duration: 1600; easing.type: Easing.InOutQuad }
                }
            }

阳光同样使用两层图片形成交错效果,不同于暗流,阳光定位在整个显示区域的顶部正中,使用旋转角度的动画来形成阳光照射的效果。

            Image {
                source: "content/gfx/sunlight.png"
                opacity: 0.02
                y: 0
                anchors.horizontalCenter: parent.horizontalCenter
                transformOrigin: Item.Top
                SequentialAnimation on rotation {
                    loops: Animation.Infinite
                    NumberAnimation { from: -10; to: 10; duration: 8000; easing.type: Easing.InOutSine }
                    NumberAnimation { from: 10; to: -10; duration: 8000; easing.type: Easing.InOutSine }
                }
            }

            Image {
                source: "content/gfx/sunlight.png"
                opacity: 0.04
                y: 20
                anchors.horizontalCenter: parent.horizontalCenter
                transformOrigin: Item.Top
                SequentialAnimation on rotation {
                    loops: Animation.Infinite
                    NumberAnimation { from: 10; to: -10; duration: 8000; easing.type: Easing.InOutSine }
                    NumberAnimation { from: -10; to: 10; duration: 8000; easing.type: Easing.InOutSine }
                }
            }

            Image {
                source: "content/gfx/grid.png"
                opacity: 0.5
            }

此时,整个开始界面的动态效果已经完全做好了,只需将其余的静态部件加入即可完成一个完整的游戏开始界面。