Warning, /education/gcompris/src/activities/mining/Mining.qml is written in an unsupported language. File is not indexed.

0001 /* GCompris - mining.qml
0002  *
0003  * SPDX-FileCopyrightText: 2014 Bruno Coudoin <bruno.coudoin@gcompris.net>
0004  *
0005  * Authors:
0006  *   Peter Albrecht <pa-dev@gmx.de> (GTK+ version)
0007  *   Bruno Coudoin <bruno.coudoin@gcompris.net> (Qt Quick port)
0008  *
0009  *   SPDX-License-Identifier: GPL-3.0-or-later
0010  */
0011 import QtQuick 2.12
0012 import GCompris 1.0
0013 
0014 import "../../core"
0015 import "mining.js" as Activity
0016 
0017 ActivityBase {
0018     id: activity
0019 
0020     onStart: focus = true
0021     onStop: {}
0022 
0023     pageComponent: Item {
0024         id: background
0025         anchors.fill: parent
0026 
0027         signal start
0028         signal stop
0029 
0030         property bool gotIt: false
0031         property bool horizontalLayout: background.width >= background.height
0032 
0033         Component.onCompleted: {
0034             activity.start.connect(start)
0035             activity.stop.connect(stop)
0036         }
0037 
0038         // Add here the QML items you need to access in javascript
0039         QtObject {
0040             id: items
0041             property Item main: activity.main
0042             property alias background: background
0043             property alias miningBg: miningBg
0044             property int currentLevel: activity.currentLevel
0045             property alias bonus: bonus
0046             property alias mineModel: mineObjects.model
0047             property Item nugget
0048             property int collectedNuggets: 0
0049         }
0050 
0051         onStart: { Activity.start(items) }
0052         onStop: { Activity.stop() }
0053 
0054         Image {
0055                 id: miningBg
0056                 source: Activity.url + "rockwall.svg"
0057                 anchors.horizontalCenter: parent.horizontalCenter
0058                 anchors.verticalCenter: parent.verticalCenter
0059                 sourceSize.width: parent.width
0060                 width: parent.width
0061                 height: parent.height
0062                 scale: miningBg._MIN_SCALE
0063 
0064                 property int subLevel
0065                 property int maxSubLevel
0066                 property real _MAX_SCALE: 3
0067                 property real _MIN_SCALE: 1
0068 
0069                 onScaleChanged: items.nugget.checkOnScreen()
0070 
0071                 Image {
0072                     source: Activity.url + "vertical_border.svg"
0073                     sourceSize.height: parent.height
0074                     width: parent.width * 0.05
0075                     anchors {
0076                         top: parent.top
0077                         left: parent.left
0078                         bottom: parent.bottom
0079                     }
0080                 }
0081 
0082                 Image {
0083                     source: Activity.url + "vertical_border.svg"
0084                     sourceSize.height: parent.height
0085                     width: parent.width * 0.05
0086                     anchors {
0087                         top: parent.top
0088                         right: parent.right
0089                         bottom: parent.bottom
0090                     }
0091                 }
0092 
0093                 Image {
0094                     source: Activity.url + "horizontal_border.svg"
0095                     sourceSize.width: parent.width
0096                     height: parent.height * 0.05
0097                     anchors {
0098                         top: parent.top
0099                         right: parent.right
0100                         left: parent.left
0101                     }
0102                 }
0103 
0104                 GridView {
0105                     id: mineObjects
0106                     anchors.fill: parent
0107                     cellWidth: parent.width / 4
0108                     cellHeight: parent.height / 4
0109 
0110                     delegate: Item {
0111                         width: mineObjects.cellWidth
0112                         height: mineObjects.cellHeight
0113                         // Calculated value true when the nugget is on the visible
0114                         // part of the screen
0115                         property bool onScreen: true
0116                         property alias nuggetImg: nuggetImg
0117                         signal hit(real x, real y)
0118                         signal checkOnScreen
0119 
0120                         onHit: {
0121                             if(!mouseArea.enabled)
0122                                 return
0123 
0124                             var point = parent.mapToItem(nuggetImg, x, y)
0125                             if(point.x > 0 && point.x < nuggetImg.width &&
0126                                point.y > 0 && point.y < nuggetImg.height)
0127                                 nuggetImg.hit()
0128                         }
0129 
0130                         onCheckOnScreen: {
0131                             // Calc if the nugget is visible or not
0132                             var nuggetCoord1 =
0133                                     background.mapFromItem(miningBg,
0134                                                            items.nugget.x + items.nugget.nuggetImg.x,
0135                                                            items.nugget.y + items.nugget.nuggetImg.y)
0136                             var nuggetCoord2 =
0137                                     background.mapFromItem(miningBg,
0138                                                            items.nugget.x + items.nugget.nuggetImg.x + items.nugget.nuggetImg.width,
0139                                                            items.nugget.y + items.nugget.nuggetImg.y + items.nugget.nuggetImg.height)
0140 
0141                             if(nuggetCoord1.x > miningBg.width ||
0142                                     nuggetCoord2.x < 0 ||
0143                                     nuggetCoord1.y > miningBg.height ||
0144                                     nuggetCoord2.y < 0)
0145                                 onScreen = false
0146                             else
0147                                 onScreen = true
0148                         }
0149 
0150                         Image {
0151                             id: nuggetImg
0152                             source: Activity.url + "gold_nugget.svg"
0153                             sourceSize.width: mineObjects.cellWidth * 3
0154                             width: mineObjects.cellWidth * modelData.widthFactor / 2
0155                             height: mineObjects.cellHeight * modelData.widthFactor / 2
0156                             anchors.horizontalCenter: parent.horizontalCenter
0157                             anchors.verticalCenter: parent.verticalCenter
0158                             opacity: modelData.isTarget &&
0159                                      miningBg.scale === miningBg._MAX_SCALE &&
0160                                      !background.gotIt ? 1 : 0
0161 
0162                             signal hit
0163                             onHit: {
0164                                 activity.audioEffects.play(Activity.url + "pickaxe.wav")
0165                                 background.gotIt = true
0166                                 items.collectedNuggets++
0167                                 tuto.setState("Unzoom")
0168                             }
0169 
0170                             Component.onCompleted: {
0171                                 if(modelData.isTarget)
0172                                     items.nugget = parent
0173                             }
0174 
0175                             MouseArea {
0176                                 id: mouseArea
0177                                 anchors.fill: parent
0178                                 enabled: modelData.isTarget &&
0179                                          miningBg.scale === miningBg._MAX_SCALE &&
0180                                          background.gotIt === false
0181                                 onClicked: parent.hit()
0182                             }
0183 
0184                             Behavior on opacity { PropertyAnimation { duration: 1000 } }
0185                         }
0186 
0187                         Image {
0188                             id: cell
0189                             source: modelData.source
0190                             sourceSize.width: mineObjects.cellWidth * 3
0191                             width: mineObjects.cellWidth * modelData.widthFactor
0192                             height: mineObjects.cellHeight * modelData.widthFactor
0193                             anchors.horizontalCenter: parent.horizontalCenter
0194                             anchors.verticalCenter: parent.verticalCenter
0195                             rotation: modelData.rotation
0196                             opacity: !modelData.isTarget ? 1 : (background.gotIt ? 0 : 1)
0197 
0198                             Component.onCompleted: {
0199                                 activity.audioEffects.play(Activity.url + "realrainbow.wav")
0200                             }
0201 
0202                             ParallelAnimation {
0203                                 running: modelData.isTarget && !background.gotIt
0204                                 loops: Animation.Infinite
0205                                 SequentialAnimation {
0206                                     loops: Animation.Infinite
0207                                     NumberAnimation {
0208                                         target: cell
0209                                         property: "rotation"
0210                                         from: 0; to: 360
0211                                         duration: 5000;
0212                                         easing.type: Easing.InOutQuad
0213                                     }
0214                                     NumberAnimation {
0215                                         target: cell; property: "rotation"
0216                                         from: 360; to: 0
0217                                         duration: 5000;
0218                                         easing.type: Easing.InOutQuad
0219                                     }
0220                                 }
0221                                 SequentialAnimation {
0222                                     loops: Animation.Infinite
0223                                     NumberAnimation {
0224                                         target: cell; property: "scale"
0225                                         from: 0; to: 1
0226                                         duration: 3000;
0227                                         easing.type: Easing.InOutQuad
0228                                     }
0229                                     PauseAnimation { duration: 300 + Math.random() * 300 }
0230                                     NumberAnimation {
0231                                         target: cell
0232                                         property: "scale"
0233                                         from: 1; to: 0
0234                                         duration: 1000;
0235                                         easing.type: Easing.InOutQuad
0236                                     }
0237                                 }
0238                             }
0239                         }
0240                     }
0241                 }
0242 
0243                 function updateScale(zoomDelta, x, y) {
0244                     var xx1 = background.mapFromItem(miningBg, x, y)
0245                     var previousScale = miningBg.scale
0246                     var miningBgScale = miningBg.scale
0247                     var miningBgHOffset = miningBg.anchors.horizontalCenterOffset
0248                     var miningBgVOffset = miningBg.anchors.verticalCenterOffset
0249                     if (zoomDelta > 0 && miningBg.scale < miningBg._MAX_SCALE) {
0250                         if(miningBgScale < miningBg._MAX_SCALE - 0.1)
0251                             miningBgScale += 0.1;
0252                         else
0253                             miningBgScale = miningBg._MAX_SCALE
0254 
0255                         if(gotIt)
0256                             tuto.setState("Unzoom")
0257                         else if(miningBgScale < miningBg._MAX_SCALE)
0258                             tuto.setState(items.nugget.onScreen ? "ZoomOk" : "ZoomBad")
0259                         else
0260                             tuto.setState(items.nugget.onScreen ? "NuggetSeen" : "NuggetNotSeen")
0261 
0262                     } else if (zoomDelta < 0) {
0263                         if(miningBgScale > miningBg._MIN_SCALE) {
0264                             miningBgScale -= 0.1;
0265 
0266                             if(gotIt)
0267                                 tuto.setState("Unzoom")
0268                             else if(miningBgScale > miningBg._MIN_SCALE)
0269                                 tuto.setState(items.nugget.onScreen ? "UnzoomOk" : "UnzoomBad")
0270                             else
0271                                 tuto.setState("Started")
0272                         } else if (gotIt) {
0273                             gotIt = false
0274                             if(miningBg.subLevel == miningBg.maxSubLevel) {
0275                                 bonus.good("lion")
0276                             } else {
0277                                 miningBg.subLevel++
0278                                 miningBgScale = miningBg._MIN_SCALE
0279                                 miningBgHOffset = 0
0280                                 miningBgVOffset = 0
0281                                 Activity.createLevel()
0282                             }
0283                             tuto.setState("Stopped")
0284                         } else {
0285                             miningBgScale = miningBg._MIN_SCALE
0286                             miningBgHOffset = 0
0287                             miningBgVOffset = 0
0288                             if(miningBg.subLevel != items.collectedNuggets)
0289                                 tuto.setState("Started")
0290                         }
0291                     }
0292                     if(miningBgScale <= miningBg._MIN_SCALE) {
0293                         miningBgScale = miningBg._MIN_SCALE
0294                     }
0295                     miningBg.scale = miningBgScale
0296                     if(previousScale != miningBg.scale && miningBg.scale > miningBg._MIN_SCALE) {
0297                         var xx2 = background.mapFromItem(miningBg, x, y)
0298                         miningBgHOffset += xx1.x - xx2.x
0299                         miningBgVOffset += xx1.y - xx2.y
0300                     } else if(miningBg.scale === miningBg._MIN_SCALE) {
0301                         miningBgHOffset = 0
0302                         miningBgVOffset = 0
0303                     }
0304                     miningBg.anchors.horizontalCenterOffset = miningBgHOffset
0305                     miningBg.anchors.verticalCenterOffset = miningBgVOffset
0306                 }
0307 
0308                 MouseArea {
0309                     anchors.fill: parent
0310                     propagateComposedEvents: true
0311                     onWheel: miningBg.updateScale(wheel.angleDelta.y, wheel.x, wheel.y)
0312                 }
0313 
0314                 MultiPointTouchArea {
0315                     anchors.fill: parent
0316                     mouseEnabled: false
0317                     minimumTouchPoints: 1
0318                     maximumTouchPoints: 2
0319                     // To determine if we zoom or unzoom
0320                     property int prevDist: 0
0321                     // To avoid having too many updates or the zoom flickers
0322                      property date dateEvent: new Date()
0323                     touchPoints: [
0324                                TouchPoint { id: point1 },
0325                                TouchPoint { id: point2 }
0326                            ]
0327                     onReleased: prevDist = 0
0328                     onTouchUpdated: {
0329                         if(!point2.pressed) {
0330                             mineObjects.itemAt(point1.x, point1.y).hit(point1.x, point1.y)
0331                             return
0332                         }
0333                         // Calc Distance
0334                         var dist = Math.floor(Math.sqrt(Math.pow(point1.x - point2.x, 2) +
0335                                                         Math.pow(point1.y - point2.y, 2)))
0336                         var newDateEvent = new Date()
0337                         if(prevDist != dist &&
0338                                 newDateEvent.getTime() - dateEvent.getTime() > 50) {
0339                             miningBg.updateScale(dist - prevDist,
0340                                                  (point1.x + point2.x) / 2,
0341                                                  (point1.y + point2.y) / 2)
0342                             dateEvent = newDateEvent
0343                         }
0344                         prevDist = dist
0345                     }
0346                 }
0347         }
0348 
0349         Image {
0350             id: carriage
0351             source: Activity.url + "gold_carriage.svg"
0352             sourceSize.height: background.horizontalLayout ? 120 * ApplicationInfo.ratio : 80 * ApplicationInfo.ratio
0353             anchors {
0354                 right: parent.right
0355                 bottom: background.horizontalLayout ? parent.bottom : bar.top
0356             }
0357 
0358             GCText {
0359                 id: score
0360                 anchors {
0361                     horizontalCenter: parent.horizontalCenter
0362                     verticalCenter: parent.verticalCenter
0363                     horizontalCenterOffset: parent.width / 10
0364                 }
0365                 text: items.collectedNuggets + "/" + miningBg.maxSubLevel
0366                 color: "white"
0367                 font.bold: true
0368                 style: Text.Outline
0369                 styleColor: "black"
0370                 fontSize: 22
0371             }
0372         }
0373 
0374         Rectangle {
0375             id: tutoBackground
0376             color: "#C0b7b353"
0377             border.color: "black"
0378             border.width: 2
0379             radius: 10
0380             anchors {
0381                 left: parent.left
0382                 right: parent.right
0383                 top: parent.top
0384                 margins: 10
0385             }
0386             height: tuto.height + anchors.margins * 2
0387             visible: tuto.state != "Stopped"
0388             Behavior on height { PropertyAnimation { duration: 100 } }
0389 
0390             GCText {
0391                 id: tuto
0392                 fontSize: 13
0393                 anchors {
0394                     left: parent.left
0395                     right: parent.right
0396                     top: parent.top
0397                     margins: 10
0398                 }
0399                 color: "white"
0400                 wrapMode: TextEdit.WordWrap
0401                 horizontalAlignment: TextEdit.AlignHCenter
0402 
0403                 property string newState
0404 
0405                 function setState(nextState) {
0406                     if(bar.level == 1) {
0407                         if(newState != nextState) {
0408                             newState = nextState
0409                             anim.restart()
0410                         }
0411                     } else {
0412                         newState = "Stopped"
0413                         anim.restart()
0414                     }
0415                 }
0416 
0417                 states: [
0418                     State {
0419                         name: "Started"
0420                         PropertyChanges {
0421                             target: tuto;
0422                             text: qsTr("Find the sparkle and zoom in around it. If you have a mouse, point the cursor on the sparkle then use the scroll wheel. If you have a trackpad, point the cursor on the sparkle then drag one finger on the right area or two fingers on the center. On a touch area, drag two fingers away from the sparkle, one in each direction.")
0423                         }
0424                     },
0425                     State {
0426                         name: "Stopped"
0427                         PropertyChanges { target: tuto; text: ""}
0428                     },
0429                     State {
0430                         name: "ZoomOk"
0431                         PropertyChanges {
0432                             target: tuto
0433                             text: qsTr("Perfect you are zooming. Continue until you see the nugget.")}
0434                     },
0435                     State {
0436                         name: "ZoomBad"
0437                         PropertyChanges {
0438                             target: tuto
0439                             text: qsTr("Hum, take care, you are zooming too far from the sparkle.")}
0440                     },
0441                     State {
0442                         name: "NuggetSeen"
0443                         PropertyChanges {
0444                             target: tuto
0445                             text: qsTr("Now you see the nugget, click on it to catch it.")}
0446                     },
0447                     State {
0448                         name: "NuggetNotSeen"
0449                         PropertyChanges {
0450                             target: tuto
0451                             text: qsTr("Hum, you are too far from the nugget to see it. Unzoom then zoom again as close as you can from the sparkle.")}
0452                     },
0453                     State {
0454                         name: "Unzoom"
0455                         PropertyChanges {
0456                             target: tuto
0457                             text: qsTr("Now unzoom and try to find another sparkle.")}
0458                     },
0459                     State {
0460                         name: "UnzoomBad"
0461                         PropertyChanges {
0462                             target: tuto
0463                             text: qsTr("Continue to unzoom until you see the sparkle.")}
0464                     },
0465                     State {
0466                         name: "UnzoomOk"
0467                         PropertyChanges {
0468                             target: tuto
0469                             text: qsTr("Now you see the sparkle, go ahead, you can zoom on it.")}
0470                     }
0471                 ]
0472 
0473                 SequentialAnimation {
0474                     id: anim
0475                     PropertyAnimation {
0476                         target: tuto
0477                         property: "opacity"
0478                         easing.type: Easing.Linear
0479                         from: 1.0; to: 0
0480                         duration: 200
0481                     }
0482                     PropertyAction {
0483                         target: tuto
0484                         property: "state"
0485                         value: tuto.newState
0486                     }
0487                     PropertyAnimation {
0488                         target: tuto
0489                         property: "opacity"
0490                         easing.type: Easing.Linear
0491                         from: 0; to: 1.0
0492                         duration: 200
0493                     }
0494                 }
0495 
0496                 Behavior on opacity { PropertyAnimation { duration: 100 } }
0497                 transitions: Transition {
0498                     PropertyAnimation {
0499                         target: tuto
0500                         property: "opacity"
0501                         to: 1.0
0502                     }
0503                 }
0504             }
0505         }
0506 
0507         DialogHelp {
0508             id: dialogHelp
0509             onClose: home()
0510         }
0511 
0512         Bar {
0513             id: bar
0514             level: items.currentLevel + 1
0515             content: BarEnumContent { value: help | home | level }
0516             onHelpClicked: {
0517                 displayDialog(dialogHelp)
0518             }
0519             onPreviousLevelClicked: Activity.previousLevel()
0520             onNextLevelClicked: Activity.nextLevel()
0521             onHomeClicked: activity.home()
0522 
0523             onLevelChanged: {
0524                 miningBg.subLevel = 1
0525                 miningBg.anchors.horizontalCenterOffset = 0
0526                 miningBg.anchors.verticalCenterOffset = 0
0527                 miningBg.scale = miningBg._MIN_SCALE
0528                 tuto.setState("Started")
0529 
0530                 switch(bar.level) {
0531                 case 1:
0532                     miningBg.maxSubLevel = 2
0533                     break
0534                 case 2:
0535                     miningBg.maxSubLevel = 4
0536                     break
0537                 case 3:
0538                     miningBg.maxSubLevel = 10
0539                     break
0540                 }
0541 
0542             }
0543         }
0544 
0545         Bonus {
0546             id: bonus
0547             Component.onCompleted: win.connect(Activity.nextLevel)
0548         }
0549 
0550     }
0551 
0552 }