Watercycle.qml 25.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/* GCompris - watercycle.qml
 *
 * Copyright (C) 2015 Sagar Chand Agarwal <atomsagar@gmail.com>
 *
 * Authors:
 *   Bruno Coudoin <bruno.coudoin@gcompris.net>(GTK+ version)
 *   Sagar Chand Agarwal <atomsagar@gmail.com> (Qt Quick port)
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

import QtQuick 2.1
import GCompris 1.0

import "../../core"
import "."

ActivityBase {
    id: activity

    onStart: focus = true
    onStop: {}

    property string url: "qrc:/gcompris/src/activities/watercycle/resource/"

    pageComponent: Item {
        id: background
        anchors.fill: parent

        signal start
        signal stop

44
45
46
47
48
49
50
51
52
53
        Component.onCompleted: {
            activity.start.connect(start)
            activity.stop.connect(stop)
        }

        onStart: {
            shower.hide()
            river.level = 0
        }

54
55
        QtObject {
            id: items
56
57
58
            property var dataset: {
                "none": "",
                "start": qsTr("Sun is the main component of water cycle. Click on the sun to start the water cycle."),
Yuri Chornoivan's avatar
Yuri Chornoivan committed
59
                "sun": qsTr("As the sun rises, the water of the sea starts heating and evaporates."),
60
                "cloud": qsTr(" Water vapor condenses to form cloud and when clouds become heavy, it rains. Click on the cloud."),
61
62
63
                "rain": qsTr("Rain causes rivers to swell up and this water is transported to us via motor pumps through water-tower." +
                             " Click on the motor pump to supply water to residents."),
                "tower": qsTr("See the tower filled with water. Activate the sewage treatment station by clicking on it."),
64
                "shower": qsTr("Great, click on the shower, as Tux arrives home."),
65
66
67
68
                "done":  qsTr("Fantastic, you have completed water cycle. You can continue playing.")
            }

            property bool cycleDone: false
Bruno Coudoin's avatar
Bruno Coudoin committed
69
            property GCAudio audioEffects: activity.audioEffects
70
71
72
73
        }

        IntroMessage {
            id: message
74
75
76
77
78
79
80
81
82
            anchors {
                top: parent.top
                topMargin: 10
                right: parent.right
                rightMargin: 5
                left: parent.left
                leftMargin: 5
            }
            z: 100
83
84
85
            onIntroDone: {
                anim.running = true
                info.visible = true
86
                sun_area.enabled = true
87
88
            }
            intro: [
89
                qsTr("The water cycle (also known as the hydrologic cycle) is the journey water takes"
90
                     +" as it circulates from the land to the sky and back again."
91
                     +" The sun's heat provides energy to evaporate water from water bodies like oceans."),
Yuri Chornoivan's avatar
Yuri Chornoivan committed
92
                qsTr("Plants also lose water to the air through transpiration. The water vapor eventually, "
93
94
95
96
97
98
99
100
                     +"cools forming tiny droplets in clouds. When the clouds meet cool air over land, "
                     +"precipitation is triggered and fall down as rain.") ,
                qsTr("Some of the water is trapped between rock or clay layers, called groundwater. "
                     +"But most of the water flows as runoff, eventually returning to the seas via rivers."),
                qsTr("Your goal is to complete water cycle before Tux reaches home. "
                     +"Click on the different components which make up the water cycle. "
                     +"First click on sun, then cloud, water pumping station near the river, "
                     +"sewage treatment, and at last regulate the switch to provide water to Tux's shower.")
101
102
103
104
105
106
107
108
109
            ]
        }

        Image {
            id: sky
            anchors.top: parent.top
            sourceSize.width: parent.width
            source: activity.url + "sky.svg"
            height: (background.height - landscape.paintedHeight) / 2 + landscape.paintedHeight * 0.3
110
            z: 1
111
112
113
114
115
116
117
118
119
120
        }

        Image {
            id: sea
            anchors {
                left: parent.left
                bottom: parent.bottom
            }
            sourceSize.width: parent.width
            source: activity.url + "sea.svg"
121
            height: (background.height - landscape.paintedHeight) / 2 + landscape.paintedHeight * 0.7
122
            z:3
123
124
125
126
127
128
129
        }

        Image {
            id: landscape
            anchors.fill: parent
            sourceSize.width: parent.width
            source: activity.url + "landscape.svg"
130
            z: 6
131
132
133
134
135
136
        }

        Image {
            id: tuxboat
            opacity: 1
            source: activity.url + "boat.svg"
137
138
            sourceSize.width: parent.width*0.15
            sourceSize.height: parent.height*0.15
139
140
141
142
143
            anchors{
                bottom: parent.bottom
                bottomMargin: 15
            }
            x:0
144
            z:30
145

146
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 200 } }
147
148
149
            NumberAnimation on x {
                id: anim
                running: false
150
                to: parent.width - tuxboat.width
151
                duration: 15000
152
                easing.type: Easing.InOutSine
153
154
155
                onRunningChanged: {
                    if(!anim.running)
                    {
Bruno Coudoin's avatar
Bruno Coudoin committed
156
                        items.audioEffects.play('qrc:/gcompris/src/activities/watercycle/resource/harbor2.wav')
157
                        tuxboat.opacity = 0
158
159
                        boatparked.opacity = 1
                        shower.stop()
160
161
                        if(!sun.hasRun)
                            info.setText('start')
Bruno Coudoin's avatar
Bruno Coudoin committed
162
163
                    } else {
                        items.audioEffects.play('qrc:/gcompris/src/activities/watercycle/resource/harbor1.wav')
164
165
166
167
168
169
                    }
                }
            }
        }

        Image {
170
            id: boatparked
171
172
173
174
175
176
177
178
179
            source: activity.url + "boat_parked.svg"
            sourceSize.width: parent.width*0.15
            sourceSize.height: parent.height*0.15
            opacity: 0
            anchors {
                right: parent.right
                bottom: parent.bottom
                bottomMargin: 20
            }
180
            z: 29
181
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 200 } }
182
183
184
185
186
        }

        Image {
            id: sun
            source: activity.url + "sun.svg"
187
            sourceSize.width: parent.width * 0.05
188
189
190
191
            anchors {
                left: parent.left
                top: parent.top
                leftMargin: parent.width*0.05
192
                topMargin: parent.height * 0.28
193
            }
194
            z: 2
195
            property bool hasRun: false
196
            MouseArea {
197
198
199
                id: sun_area
                anchors.fill: sun
                onClicked: {
200
201
                    if(cloud.opacity == 0)
                        sun.up()
202
203
                }
            }
204
205
            Behavior on anchors.topMargin { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 5000 } }
            function up() {
Bruno Coudoin's avatar
Bruno Coudoin committed
206
                items.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/bleep.wav')
207
208
                info.setText('sun')
                sun.hasRun = true
209
210
                sun.anchors.topMargin = parent.height * 0.05
                vapor.up()
211
            }
212
213
            function down() {
                sun.anchors.topMargin = parent.height * 0.28
214
215
216
217
218
219
220
221
222
223
            }
        }

        Image {
            id: vapor
            opacity: 0
            state: "vapor"
            source: activity.url + "vapor.svg"
            sourceSize.width: parent.width*0.05
            anchors {
224
                left: sun.left
225
            }
226
            y: background.height * 0.28
227
            z: 10
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

            SequentialAnimation {
                id: vaporAnim
                loops: 2
                NumberAnimation {
                    target: vapor
                    property: "opacity"
                    duration: 200
                    from: 0
                    to: 1
                }
                NumberAnimation {
                    target: vapor
                    property: "y"
                    duration: 5000
                    from: background.height * 0.28
                    to: background.height * 0.1
                }
                NumberAnimation {
                    target: vapor
                    property: "opacity"
                    duration: 200
                    from: 1
                    to: 0
                }
                NumberAnimation {
                    target: vapor
                    property: "y"
                    duration: 0
                    to: background.height * 0.28
                }
259
260
261
262
                onRunningChanged: {
                    if(!running)
                        info.setText('cloud')
                }
263
264
265
266
267
268
269
            }
            function up() {
                vaporAnim.start()
                cloud.up()
            }
            function down() {
            }
270
271
272
273
274
275
276
277
        }


        Image {
            id: cloud
            opacity: 0
            source: activity.url + "cloud.svg"
            sourceSize.width: parent.width * 0.20
278
279
            fillMode: Image.PreserveAspectFit
            width: 0
280
281
            anchors {
                top: parent.top
282
                topMargin: parent.height * 0.05
283
            }
284
285
            x: parent.width * 0.05
            z: 11
286
287
288
289
            MouseArea {
                id: cloud_area
                anchors.fill: cloud
                onClicked: {
290
291
                    sun.down()
                    rain.up()
292
293
                }
            }
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
            ParallelAnimation {
                id: cloudanimOn
                running: false
                PropertyAnimation {
                    target: cloud
                    property: 'opacity'
                    easing.type: Easing.InOutQuad
                    duration: 5000
                    from: 0
                    to: 1
                }
                PropertyAnimation {
                    target: cloud
                    property: 'width'
                    easing.type: Easing.InOutQuad
                    duration: 15000
                    from: 0
                    to: cloud.sourceSize.width
                }
                PropertyAnimation {
                    target: cloud
                    property: 'x'
                    easing.type: Easing.InOutQuad
                    duration: 15000
                    from: background.width * 0.05
                    to: background.width * 0.4
                }
            }
            SequentialAnimation {
                id: cloudanimOff
                running: false
                PropertyAnimation {
                    target: cloud
                    property: 'opacity'
                    easing.type: Easing.InOutQuad
                    duration: 3000
                    from: 1
                    to: 0
                }
                PropertyAnimation {
                    target: cloud
                    property: 'width'
                    easing.type: Easing.InOutQuad
                    duration: 0
                    to: 0
                }
                PropertyAnimation {
                    target: cloud
                    property: 'x'
                    easing.type: Easing.InOutQuad
                    duration: 0
                    to: background.width * 0.05
                }
            }

349
            function up() {
350
                cloudanimOn.start()
351
352
353
            }
            function down() {
                opacity = 0
354
                width = 0
355
                x = parent.width * 0.05
356
357
358
359
360
361
            }
        }

        Image {
            id: rain
            source: activity.url + "rain.svg"
362
363
            sourceSize.height: cloud.height * 2
            opacity: 0
364
365
366
            anchors {
                top: cloud.bottom
            }
367
            x: cloud.x
368
            z: 10
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 300 } }
            SequentialAnimation{
                id: rainAnim
                running: false
                loops: 10
                NumberAnimation {
                    target: rain
                    property: "scale"
                    duration: 500
                    to: 0.95
                }
                NumberAnimation {
                    target: rain
                    property: "scale"
                    duration: 500
                    to: 1
                }
                onRunningChanged: {
                    if(!running) {
                        rain.down()
                        cloud.down()
                    }
                }
            }
            function up() {
Bruno Coudoin's avatar
Bruno Coudoin committed
394
                items.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/water.wav')
395
                info.setText('rain')
396
397
398
399
400
                opacity = 1
                rainAnim.start()
            }
            function down() {
                opacity = 0
401
402
403
404
405
406
            }
        }

        Image {
            id: river
            source: activity.url + "river.svg"
407
408
409
410
            sourceSize.width: parent.width * 0.415
            sourceSize.height: parent.height * 0.74
            width: parent.width * 0.415
            height: parent.height * 0.74
411
            opacity: level > 0 ? 1 : 0
412
413
414
            anchors {
                top: parent.top
                left: parent.left
415
416
                topMargin: parent.height*0.1775
                leftMargin: parent.width*0.293
417
            }
418
            z: 10
419
420
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 5000 } }
            property double level: 0
421
422
423
424
425
        }

        Image {
            id: reservoir1
            source: activity.url + "reservoir1.svg"
426
            sourceSize.width: parent.width*0.06
427
428
429
430
431
432
433
            width: parent.width*0.06
            height: parent.height*0.15
            anchors {
                top: parent.top
                left: parent.left
                topMargin: parent.height*0.2925
                leftMargin: parent.width*0.3225
434
            }
435
            opacity: river.level > 0.2 ? 1 : 0
436
            z: 10
437
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 5000 } }
438
439
        }

440
441
442
        Image {
            id: reservoir2
            source: activity.url + "reservoir2.svg"
443
            sourceSize.width: parent.width*0.12
444
445
446
447
448
449
450
451
            width: parent.width*0.12
            height: parent.height*0.155
            anchors {
                top: parent.top
                left: parent.left
                topMargin: parent.height*0.2925
                leftMargin: parent.width*0.285
            }
452
            opacity: river.level > 0.5 ? 1 : 0
453
            z: 10
454
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 5000 } }
455
456
457
458
459
        }

        Image {
            id: reservoir3
            source: activity.url + "reservoir3.svg"
460
            sourceSize.width: parent.width*0.2
461
462
463
464
465
466
467
468
            width: parent.width*0.2
            height: parent.height*0.17
            anchors {
                top: parent.top
                left: parent.left
                topMargin: parent.height*0.29
                leftMargin: parent.width*0.25
            }
469
            opacity: river.level > 0.8 ? 1 : 0
470
            z: 10
471
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 5000 } }
472
473
        }

474
        Image {
475
            id: waterplant
476
            source: activity.url + "motor.svg"
477
478
            sourceSize.width: parent.width*0.07
            sourceSize.height: parent.height*0.08
479
480
481
482
483
484
            anchors {
                top: parent.top
                left:parent.left
                topMargin: parent.height*0.38
                leftMargin: parent.width*0.4
            }
485
            z: 20
486
            property bool running: false
487
488
            MouseArea {
                id: motor_area
489
490
                enabled: river.level > 0.2
                anchors.fill: parent
491
                onClicked: {
Bruno Coudoin's avatar
Bruno Coudoin committed
492
                    items.audioEffects.play('qrc:/gcompris/src/activities/watercycle/resource/bubble.wav')
493
                    info.setText('tower')
494
                    waterplant.running = true
495
496
497
498
                }
            }
        }

499
500
501
502
503
504
505
506
507
508
        Image {
            id: fillpipe
            anchors.fill: parent
            sourceSize.width: parent.width
            width: parent.width
            source: activity.url + "fillwater.svg"
            opacity: waterplant.running ? 1 : 0.1
            z: 9
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 300 } }
        }
509

510
511
512
513
514
515
516
517
518
        Image {
            id: sewageplant
            source: activity.url + "waste.svg"
            sourceSize.height: parent.height * 0.15
            anchors {
                top: parent.top
                left: parent.left
                topMargin: parent.height*0.74
                leftMargin: parent.width*0.66
519
            }
520
521
522
523
524
525
526
            z: 11
            property bool running: false
            MouseArea {
                id: waste_area
                enabled: river.opacity == 1
                anchors.fill: parent
                onClicked: {
Bruno Coudoin's avatar
Bruno Coudoin committed
527
                    items.audioEffects.play('qrc:/gcompris/src/activities/watercycle/resource/bubble.wav')
528
                    info.setText('shower')
529
530
                    sewageplant.running = true
                }
531
532
533
            }
        }

534
535
536
537
538
539
540
541
542
        Image {
            id: wastepipe
            anchors.fill: parent
            sourceSize.width: parent.width
            width: parent.width
            source: activity.url + "wastewater.svg"
            opacity: sewageplant.running ? 1 : 0.1
            z: 10
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 300 } }
543
544
545
546
547
548
549
550
551
552
553
554
555
        }

        Image {
            id: tower
            source: activity.url + "watertower.svg"
            sourceSize.width: parent.width*0.18
            sourceSize.height: parent.height*0.15
            anchors {
                top: parent.top
                right: parent.right
                topMargin: parent.height*0.225
                rightMargin: parent.width*0.175
            }
556
            z: 10
557
            property double level: 0
558
559

            Image {
560
561
                id: towerfill
                scale: tower.level
562
563
564
565
566
567
568
569
                source: activity.url + "watertowerfill.svg"
                sourceSize.width: tower.width*0.4
                anchors {
                    top: tower.top
                    left:tower.left
                    topMargin: tower.height*0.13
                    leftMargin: tower.width*0.3
                }
570
                Behavior on scale { PropertyAnimation { duration: timer.interval } }
571
572
573
574
575
576
            }
        }

        Image {
            id: shower
            source: activity.url + "shower.svg"
577
578
            sourceSize.height: parent.height*0.2
            sourceSize.width: parent.width*0.15
579
580
581
582
583
584
            anchors {
                bottom: parent.bottom
                right: parent.right
                bottomMargin: parent.height* 0.32
                rightMargin: parent.width*0.012
            }
585
            z: 10
586
            visible: false
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
            property bool on: false

            MouseArea {
                id: shower_area
                anchors.fill: parent
                onClicked: {
                    if(!shower.on &&
                            river.opacity == 1 && wastepipe.opacity > 0.8 &&
                            fillpipe.opacity > 0.8 && tower.level > 0.5)
                        shower.start()
                    else
                        shower.stop()
                }
            }

            function start() {
                shower.on = true
                shower.visible = true
                showerhot.visible = true
                tuxbath.visible = true
                showercold.visible = false
                tuxoff.visible = false
609
610
611
612
613
614

                if(!items.cycleDone) {
                    info.setText('done')
                    bonus.good('smiley')
                    items.cycleDone = true
                }
Bruno Coudoin's avatar
Bruno Coudoin committed
615
                items.audioEffects.play('qrc:/gcompris/src/activities/watercycle/resource/apert.wav')
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
            }

            function stop() {
                shower.on = false
                shower.visible = true
                showerhot.visible = false
                tuxbath.visible = false
                showercold.visible = true
                tuxoff.visible = true
            }
            function hide() {
                shower.visible = false
                shower.on = false
                tuxoff.visible = false
                showercold.visible = false
                showerhot.visible = false
                tuxbath.visible = false
            }
634
635
636
637
638
        }

        Image {
            id: tuxoff
            source:activity.url + "tuxoff.svg"
639
            sourceSize.width: shower.height * 0.4
640
641
642
643
644
645
            anchors {
                horizontalCenter: shower.horizontalCenter
                verticalCenter: shower.verticalCenter
                verticalCenterOffset: shower.height*0.1
                horizontalCenterOffset: -shower.width*0.05
            }
646
            z: 10
647
648
649
650
651
652
            visible: false
        }

        Image {
            id: tuxbath
            source: activity.url + "tuxbath.svg"
653
            sourceSize.width: shower.height * 0.5
654
655
656
657
658
659
            anchors {
                horizontalCenter: shower.horizontalCenter
                verticalCenter: shower.verticalCenter
                verticalCenterOffset: shower.height*0.1
                horizontalCenterOffset: -shower.width*0.05
            }
660
            z: 10
661
662
663
664
665
666
            visible: false
        }

        Image {
            id: showerhot
            source: activity.url + "showerhot.svg"
667
            sourceSize.width: shower.width * 0.1
668
669
670
671
672
673
            anchors {
                right: shower.right
                top: shower.top
                rightMargin: shower.width*0.15
                topMargin: shower.height*0.25
            }
674
            z: 10
675
676
677
678
679
680
            visible: false
        }

        Image {
            id: showercold
            source: activity.url + "showercold.svg"
681
            sourceSize.width: shower.width * 0.1
682
683
684
685
686
687
            anchors {
                right: shower.right
                top: shower.top
                rightMargin: shower.width*0.15
                topMargin: shower.height*0.25
            }
688
            z: 10
689
690
691
            visible: false
        }

692
693
694
695
696
697
698
699
700
        // Manage stuff that changes periodically
        Timer {
            id: timer
            interval: 100
            running: true
            repeat: true
            onTriggered: {
                if(rain.opacity > 0.9 && river.level < 1) {
                    river.level += 0.01
701
                }
702
703
704
                if(river.level > 0 && fillpipe.opacity > 0.9 && tower.level < 1 && !shower.on) {
                    river.level -= 0.02
                    tower.level += 0.05
705
                }
706
707
                if(tower.level > 0 && shower.on) {
                    tower.level -= 0.02
708
                }
709
710
                if(tower.level <= 0 && boatparked.opacity) {
                    shower.stop()
711
712
                }
            }
713
        }
714
715
716

        GCText {
            id: info
717
            visible: true
718
719
720
721
722
723
724
725
726
            fontSize: smallSize
            font.weight: Font.DemiBold
            horizontalAlignment: Text.AlignHCenter
            anchors {
                top: parent.top
                topMargin: 10 *ApplicationInfo.ratio
                right: parent.right
                rightMargin: 5 * ApplicationInfo.ratio
                left: parent.left
727
                leftMargin: parent.width * 0.50
728
729
730
            }
            width: parent.width
            wrapMode: Text.WordWrap
731
732
733
            z: 100
            onTextChanged: textanim.start()
            property string newKey
734

735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
            SequentialAnimation {
                id: textanim
                NumberAnimation {
                    target: info
                    property: "opacity"
                    duration: 200
                    from: 1
                    to: 0
                }
                PropertyAction {
                    target: info
                    property: 'text'
                    value: items.dataset[info.newKey]
                }
                NumberAnimation {
                    target: info
                    property: "opacity"
                    duration: 200
                    from: 0
                    to: 1
                }
756
757
            }

758
            function setText(key) {
759
760
761
762
                if(newKey != key) {
                    newKey = key
                    textanim.start()
                }
763
            }
764
765
        }

766
767
768
769
770
771
772
773
774
775
        Rectangle {
            id: infoBg
            z: 99
            anchors.fill: info
            color: '#8ebfc7'
            radius: width * 0.01
            opacity: info.text ? 0.7 : 0
            Behavior on opacity { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 200 } }
        }

776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
        DialogHelp {
            id: dialogHelp
            onClose: home()
        }

        Bar {
            id: bar
            content: BarEnumContent { value: help | home }
            onHelpClicked: {
                displayDialog(dialogHelp)
            }
            onHomeClicked: activity.home()
        }

        Bonus {
            id:bonus
        }

    }
}