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

0001 /* GCompris - submarine.qml
0002  *
0003  * SPDX-FileCopyrightText: 2017 RUDRA NIL BASU <rudra.nil.basu.1996@gmail.com>
0004  *
0005  * Authors:
0006  *   Pascal Georges <pascal.georges1@free.fr> (GTK+ version)
0007  *   Rudra Nil Basu <rudra.nil.basu.1996@gmail.com> (Qt Quick port)
0008  *
0009  *   SPDX-License-Identifier: GPL-3.0-or-later
0010  */
0011 import QtQuick 2.12
0012 import QtQuick.Particles 2.12
0013 import Box2D 2.0
0014 import QtGraphicalEffects 1.0
0015 import GCompris 1.0
0016 
0017 import "../../core"
0018 import "submarine.js" as Activity
0019 
0020 ActivityBase {
0021     id: activity
0022 
0023     onStart: focus = true
0024     onStop: {}
0025 
0026     property string url: "qrc:/gcompris/src/activities/submarine/resource/"
0027 
0028     pageComponent: Image {
0029         id: background
0030         source: url + "background.svg"
0031         anchors.fill: parent
0032         sourceSize.height: parent.height
0033         sourceSize.width: parent.width
0034 
0035         onWidthChanged: updateOnWidthReset.start()
0036         onHeightChanged: Activity.resetUpperGate()
0037         onVisibleChanged: visible ? physicalWorld.running = true :
0038                                     physicalWorld.running = false
0039 
0040         property bool hori: background.width >= background.height
0041 
0042         signal start
0043         signal stop
0044 
0045         Component.onCompleted: {
0046             activity.start.connect(start)
0047             activity.stop.connect(stop)
0048         }
0049 
0050         // Needed to get keyboard focus on IntroMessage
0051         Keys.forwardTo: tutorial
0052         
0053         /* Testing purposes, A / Left Key => Reduces velocity, D / Right Key => Increases velocity */
0054         Keys.onPressed: {
0055             if (event.key === Qt.Key_D || event.key === Qt.Key_Right) {
0056                 submarine.increaseHorizontalVelocity(1)
0057             }
0058             if (event.key === Qt.Key_A || event.key === Qt.Key_Left) {
0059                 submarine.decreaseHorizontalVelocity(1)
0060             }
0061             if (event.key === Qt.Key_W || event.key === Qt.Key_Up) {
0062                 centralBallastTank.fillBallastTanks()
0063                 controls.updateVannes(centralBallastTank.waterFilling, controls.rotateCentralFill)
0064             }
0065             if (event.key === Qt.Key_S || event.key === Qt.Key_Down){
0066                 centralBallastTank.flushBallastTanks()
0067                 controls.updateVannes(centralBallastTank.waterFlushing, controls.rotateCentralFlush)
0068             }
0069             if (event.key === Qt.Key_Plus) {
0070                 submarine.increaseWingsAngle(1)
0071             }
0072             if (event.key === Qt.Key_Minus) {
0073                 submarine.decreaseWingsAngle(1)
0074             }
0075 
0076             if (event.key === Qt.Key_R) {
0077                 leftBallastTank.fillBallastTanks()
0078                 controls.updateVannes(leftBallastTank.waterFilling, controls.rotateLeftFill)
0079             }
0080             if (event.key === Qt.Key_F) {
0081                 leftBallastTank.flushBallastTanks()
0082                 controls.updateVannes(leftBallastTank.waterFlushing, controls.rotateLeftFlush)
0083             }
0084 
0085             if (event.key === Qt.Key_T) {
0086                 rightBallastTank.fillBallastTanks()
0087                 controls.updateVannes(rightBallastTank.waterFilling, controls.rotateRightFill)
0088             }
0089             if (event.key === Qt.Key_G) {
0090                 rightBallastTank.flushBallastTanks()
0091                 controls.updateVannes(rightBallastTank.waterFlushing, controls.rotateRightFlush)
0092             }
0093         }
0094 
0095         // Add here the QML items you need to access in javascript
0096         QtObject {
0097             id: items
0098             property Item main: activity.main
0099             property alias background: background
0100             property int currentLevel: activity.currentLevel
0101             property alias bonus: bonus
0102             property alias crown: crown
0103             property alias whale: whale
0104             property var submarineCategory: Fixture.Category1
0105             property var crownCategory: Fixture.Category2
0106             property var whaleCategory: Fixture.Category3
0107             property var upperGatefixerCategory: Fixture.Category4
0108             property var lowerGatefixerCategory: Fixture.Category5
0109             property var shipCategory: Fixture.Category6
0110             property var rockCategory: Fixture.Category7
0111             property var maxDepthCategory: Fixture.Category8
0112             property alias submarine: submarine
0113             property alias tutorial: tutorial
0114             property alias upperGate: upperGate
0115             property alias ship: ship
0116             property alias controls: controls
0117             property alias physicalWorld: physicalWorld
0118             property bool processingAnswer: false
0119         }
0120 
0121         IntroMessage {
0122             id: tutorial
0123             textContainerHeight: 0.5 * parent.height
0124             z: 100
0125             onIntroDone: {
0126                 tutorial.visible = false
0127             }
0128         }
0129 
0130         onStart: { Activity.start(items) }
0131         onStop: {
0132             smoothHorizontalVelocity.stop()
0133             updateVerticalVelocity.stop()
0134             removeSparkleTimer.stop()
0135             updateOnWidthReset.stop()
0136             Activity.stop()
0137         }
0138 
0139         World {
0140             id: physicalWorld
0141             running: !tutorial.visible && !items.processingAnswer
0142             gravity: Qt.point(0,0)
0143             autoClearForces: false
0144         }
0145 
0146         Item {
0147             id: waterLevel
0148             x: 0
0149             y: background.height / 15
0150         }
0151 
0152         Rectangle {
0153             id: maximumWaterDepth
0154 
0155             width: background.width
0156             height: 10
0157             color: "transparent"
0158 
0159             y: background.height * 0.65
0160 
0161             Body {
0162                 id: maxDepthBody
0163                 target: maximumWaterDepth
0164                 bodyType: Body.Static
0165                 sleepingAllowed: true
0166                 linearDamping: 0
0167 
0168                 fixtures: Box {
0169                     categories: items.maxDepthCategory
0170                     collidesWith: items.submarineCategory
0171                     width: maximumWaterDepth.width
0172                     height: maximumWaterDepth.height
0173                     density: 1
0174                     friction: 0
0175                     restitution: 0
0176                 }
0177             }
0178         }
0179 
0180         Item {
0181             id: submarine
0182 
0183             z: 1
0184 
0185             property point initialPosition: Qt.point(0,waterLevel.y - submarineImage.height/2)
0186             property bool isHit: false
0187             property int terminalVelocityIndex: 75
0188             property int maxAbsoluteRotationAngle: 15
0189 
0190             /* Maximum depth the submarine can dive when ballast tank is full */
0191             property real maximumDepthOnFullTanks: maximumWaterDepth.y * 0.45
0192             property real ballastTankDiveSpeed: 10
0193 
0194             /* Engine properties */
0195             property point velocity
0196             property int maximumXVelocity: 5
0197             property int currentFinalVelocity: 0
0198 
0199             /* Wings property */
0200             property int wingsAngle
0201             property int initialWingsAngle: 0
0202             property int maxWingsAngle: 2
0203             property int minWingsAngle: -2
0204 
0205             function destroySubmarine() {
0206                 isHit = true
0207             }
0208 
0209             function resetSubmarine() {
0210                 isHit = false
0211                 submarineImage.reset()
0212 
0213                 leftBallastTank.resetBallastTanks()
0214                 rightBallastTank.resetBallastTanks()
0215                 centralBallastTank.resetBallastTanks()
0216 
0217                 currentFinalVelocity = 0
0218                 velocity = Qt.point(0,0)
0219                 smoothHorizontalVelocity.stop()
0220                 wingsAngle = initialWingsAngle
0221             }
0222 
0223             /* While increasing or decreasing, we can't use submarine.velocity.x since it is interpolating */
0224             function increaseHorizontalVelocity(amount) {
0225                 if (submarine.currentFinalVelocity + amount <= submarine.maximumXVelocity) {
0226                     submarine.currentFinalVelocity += amount
0227                     smoothHorizontalVelocity.stop()
0228                     smoothHorizontalVelocity.setFinalVelocity(submarine.currentFinalVelocity)
0229                     smoothHorizontalVelocity.setIncreaseVelocity(true)
0230                     smoothHorizontalVelocity.start()
0231                 }
0232             }
0233 
0234             function decreaseHorizontalVelocity(amount) {
0235                 if (submarine.currentFinalVelocity - amount >= 0) {
0236                     submarine.currentFinalVelocity -= amount
0237                     smoothHorizontalVelocity.stop()
0238                     smoothHorizontalVelocity.setFinalVelocity(submarine.currentFinalVelocity)
0239                     smoothHorizontalVelocity.setIncreaseVelocity(false)
0240                     smoothHorizontalVelocity.start()
0241                 }
0242             }
0243 
0244             function increaseWingsAngle(amount) {
0245                 if (wingsAngle + amount <= maxWingsAngle) {
0246                     wingsAngle += amount
0247                 } else {
0248                     wingsAngle = maxWingsAngle
0249                 }
0250             }
0251 
0252             function decreaseWingsAngle(amount) {
0253                 if (wingsAngle - amount >= minWingsAngle) {
0254                     wingsAngle -= amount
0255                 } else {
0256                     wingsAngle = minWingsAngle
0257                 }
0258             }
0259 
0260             function changeVerticalVelocity() {
0261                 /* Check if we are currently using diving planes or ballast tanks */
0262                 var isDivingPlanesActive
0263                 if (submarineImage.y > 0 && submarine.velocity.x > 0 && wingsAngle != 0) {
0264                     /*
0265                      * Movement due to planes
0266                      * Movement is affected only when the submarine is moving forward
0267                      * When the submarine is on the surface, the planes cannot be used
0268                      */
0269                     isDivingPlanesActive = true
0270                 } else {
0271                     isDivingPlanesActive = false
0272                 }
0273 
0274                 var yPosition
0275                 if (isDivingPlanesActive) {
0276                     /* Currently using diving planes */
0277                     var multiplier
0278                     if (wingsAngle == 1) {
0279                         multiplier = 0.6
0280                     } else if (wingsAngle == 2) {
0281                         multiplier = 0.8
0282                     } else if (wingsAngle == -1) {
0283                         multiplier = 0.2
0284                     } else if (wingsAngle == -2) {
0285                         multiplier = 0.1
0286                     }
0287                     yPosition = multiplier * maximumWaterDepth.y
0288                 } else {
0289                     /* Currently under the influence of Ballast Tanks */
0290                     yPosition = submarineImage.currentWaterLevel / submarineImage.totalWaterLevel * submarine.maximumDepthOnFullTanks
0291 
0292                     if (bar.level >= 7) {
0293                         var finalAngle = ((rightBallastTank.waterLevel - leftBallastTank.waterLevel) / leftBallastTank.maxWaterLevel) * submarine.maxAbsoluteRotationAngle
0294                         submarineRotation.angle = finalAngle
0295                     }
0296                 }
0297                 var depthToMove
0298                 if (submarineImage.y <= submarine.initialPosition.y && yPosition == 0){
0299                     depthToMove = 0
0300                 }else {
0301                     depthToMove = yPosition - submarineImage.y
0302                 }
0303                 submarine.velocity.y = ballastTankDiveSpeed * (depthToMove / background.width)
0304             }
0305 
0306             Timer {
0307                 id: smoothHorizontalVelocity
0308                 running: false
0309                 repeat: true
0310                 interval: 100
0311 
0312                 property real finalVelocity
0313                 property real smoothRate: 0.1
0314                 property bool increaseVelocity
0315 
0316                 function increaseVelocitySmoothly() {
0317                     if (submarine.velocity.x + smoothRate > finalVelocity) {
0318                         submarine.velocity.x = finalVelocity
0319                         smoothHorizontalVelocity.stop()
0320                     } else {
0321                         submarine.velocity.x += smoothRate
0322                     }
0323                 }
0324 
0325                 function decreaseVelocitySmoothly() {
0326                     if (submarine.velocity.x - smoothRate <= finalVelocity) {
0327                         submarine.velocity.x = finalVelocity
0328                         smoothHorizontalVelocity.stop()
0329                     } else {
0330                         submarine.velocity.x -= smoothRate
0331                     }
0332                 }
0333 
0334                 function setFinalVelocity(_finalVelocity) {
0335                     finalVelocity = _finalVelocity
0336                 }
0337 
0338                 function setIncreaseVelocity(value) {
0339                     increaseVelocity = value
0340                 }
0341 
0342                 onTriggered: {
0343                     if (increaseVelocity) {
0344                         increaseVelocitySmoothly()
0345                     } else {
0346                         decreaseVelocitySmoothly()
0347                     }
0348                 }
0349             }
0350 
0351             BallastTank {
0352                 id: leftBallastTank
0353             }
0354 
0355             BallastTank {
0356                 id: rightBallastTank
0357             }
0358 
0359             BallastTank {
0360                 id: centralBallastTank
0361             }
0362 
0363             Image {
0364                 id: submarineImage
0365                 source: submarine.isHit ? url + "submarine-broken.svg" : url + "submarine.svg"
0366 
0367                 property int currentWaterLevel: bar.level < 7 ? centralBallastTank.waterLevel : leftBallastTank.waterLevel + rightBallastTank.waterLevel
0368                 property int totalWaterLevel: bar.level < 7 ? centralBallastTank.maxWaterLevel : leftBallastTank.maxWaterLevel + rightBallastTank.maxWaterLevel
0369 
0370                 width: background.width / 9
0371                 sourceSize.width: submarineImage.width
0372                 fillMode: Image.PreserveAspectFit
0373 
0374                 function reset() {
0375                     x = submarine.initialPosition.x
0376                     y = submarine.initialPosition.y
0377                 }
0378 
0379                 onXChanged: {
0380                     if (submarineImage.x >= background.width) {
0381                         Activity.finishLevel(true)
0382                     }
0383                 }
0384 
0385                 transform: Rotation {
0386                     id: submarineRotation
0387                     origin.x: submarineImage.width / 2;
0388                     origin.y: 0;
0389                     angle: 0;
0390                     Behavior on angle {
0391                         NumberAnimation {
0392                             duration: 1000
0393                         }
0394                     }
0395                 }
0396 
0397                 Loader {
0398                     anchors.fill: parent
0399                     active: ApplicationInfo.hasShader && submarine.velocity.x > 0 && submarineImage.y > 0 && !submarine.isHit
0400                     sourceComponent: ParticleSystem {
0401                         anchors.fill: parent
0402                         Emitter {
0403                             x: parent.x
0404                             y: parent.y + parent.height / 1.75
0405                             width: 1
0406                             height: 1
0407                             emitRate: 0.8
0408                             lifeSpan: 800
0409                             lifeSpanVariation: 2500
0410                             acceleration: PointDirection {
0411                                 x: -20
0412                                 xVariation: 5
0413                                 y: 0
0414                                 yVariation: 0
0415                             }
0416                             velocity: PointDirection {
0417                                 x: -20
0418                                 xVariation: 10
0419                                 y: 0
0420                                 yVariation: 0
0421                             }
0422                             size: 12
0423                             sizeVariation: 8
0424                         }
0425 
0426                         ImageParticle {
0427                             source: "qrc:/gcompris/src/activities/clickgame/resource/bubble.svg"
0428                         }
0429                     }
0430                 }
0431             }
0432 
0433             Body {
0434                 id: submarineBody
0435                 target: submarineImage
0436                 bodyType: Body.Dynamic
0437                 fixedRotation: true
0438                 linearDamping: 0
0439                 linearVelocity: submarine.isHit ? Qt.point(0,0) : submarine.velocity
0440 
0441                 fixtures: [
0442                     Box {
0443                         id: submarineFixer
0444                         y: submarineImage.height * 0.50
0445                         width: submarineImage.width
0446                         height: submarineImage.height * 0.50
0447                         categories: items.submarineCategory
0448                         collidesWith: Fixture.All
0449                         density: 1
0450                         friction: 0
0451                         restitution: 0
0452                         onBeginContact: {
0453                             var collidedObject = other.getBody().target
0454 
0455                             if (collidedObject == whale) {
0456                                 whale.hit()
0457                             }
0458                             if (collidedObject == crown) {
0459                                 crown.captureCrown()
0460                             } else {
0461                                 Activity.finishLevel(false)
0462                             }
0463                         }
0464                     },
0465                     Box {
0466                         id: submarinePeriscopeFixer
0467                         x: submarineImage.width * 0.5
0468                         width: submarineImage.width * 0.25
0469                         height: submarineImage.height
0470                         categories: items.submarineCategory
0471                         collidesWith: Fixture.All
0472                         density: 1
0473                         friction: 0
0474                         restitution: 0
0475                         onBeginContact: {
0476                             var collidedObject = other.getBody().target
0477 
0478                             if (collidedObject === whale) {
0479                                 whale.hit()
0480                             }
0481                             if (collidedObject === crown) {
0482                                 crown.captureCrown()
0483                             } else {
0484                                 Activity.finishLevel(false)
0485                             }
0486                         }
0487                     }
0488                 ]
0489             }
0490 
0491             Timer {
0492                 id: updateVerticalVelocity
0493                 interval: 50
0494                 running: true
0495                 repeat: true
0496 
0497                 onTriggered: submarine.changeVerticalVelocity()
0498             }
0499         }
0500 
0501         Image {
0502             id: sparkle
0503             source: "qrc:/gcompris/src/activities/mining/resource/sparkle.svg"
0504 
0505             x: crown.x
0506             y: crown.y
0507             z: 1
0508 
0509             width: crown.width
0510             height: width * 0.7
0511 
0512             property bool isCaptured: false
0513 
0514             scale: isCaptured ? 1 : 0
0515 
0516             function createSparkle() {
0517                 isCaptured = true
0518 
0519                 removeSparkleTimer.start()
0520             }
0521 
0522             function removeSparkle() {
0523                 isCaptured = false
0524             }
0525 
0526             Behavior on scale {
0527                 NumberAnimation {
0528                     duration: 100
0529                 }
0530             }
0531 
0532             Timer {
0533                 id: removeSparkleTimer
0534                 interval: 3000
0535                 repeat: false
0536                 running: false
0537 
0538                 onTriggered: sparkle.removeSparkle()
0539             }
0540         }
0541 
0542         Rectangle {
0543             id: upperGate
0544             visible: (bar.level > 1) ? true : false
0545             width: background.width / 18
0546             height: isGateOpen ? background.height * (5 / 36) : background.height * (5 / 12) + 4
0547             y: -2
0548             z: 2
0549             color: "#9E948A"
0550             border.color: "#766C62"
0551             border.width: 2
0552             anchors.right: background.right
0553             anchors.rightMargin: -2
0554 
0555             property bool isGateOpen: false
0556 
0557             Body {
0558                 id: upperGateBody
0559                 target: upperGate
0560                 bodyType: Body.Static
0561                 sleepingAllowed: true
0562                 fixedRotation: true
0563                 linearDamping: 0
0564 
0565                 fixtures: Box {
0566                     id: upperGatefixer
0567                     width: upperGate.width
0568                     height: upperGate.height
0569                     categories: items.upperGatefixerCategory
0570                     collidesWith: upperGate.visible ? items.submarineCategory : Fixture.None
0571                     density: 1
0572                     friction: 0
0573                     restitution: 0
0574                 }
0575             }
0576 
0577             Behavior on height {
0578                 NumberAnimation {
0579                     duration: 1000
0580                 }
0581             }
0582         }
0583 
0584         Rectangle {
0585             id: lowerGate
0586             z: 1
0587             visible: upperGate.visible
0588             width: background.width / 18
0589             height: background.height * (5 / 12) - subSchemaImage.height / 1.4
0590             y: background.height * (5 / 12)
0591             color: "#9E948A"
0592             border.color: "#766C62"
0593             border.width: 2
0594             anchors.right:background.right
0595             anchors.rightMargin: -2
0596 
0597             Body {
0598                 id: lowerGateBody
0599                 target: lowerGate
0600                 bodyType: Body.Static
0601                 sleepingAllowed: true
0602                 fixedRotation: true
0603                 linearDamping: 0
0604 
0605                 fixtures: Box {
0606                     id: lowerGatefixer
0607                     width: lowerGate.width
0608                     height: lowerGate.height
0609                     categories: items.lowerGatefixerCategory
0610                     collidesWith: lowerGate.visible ? items.submarineCategory : Fixture.None
0611                     density: 1
0612                     friction: 0
0613                     restitution: 0
0614                 }
0615             }
0616         }
0617 
0618         Rectangle {
0619             id: subSchemaImage
0620             width: background.width/1.3
0621             height: background.height/4
0622             x: background.width/9
0623             y: background.height/1.5
0624             visible: false
0625         }
0626 
0627         Image {
0628             id: crown
0629 
0630             width: submarineImage.width * 0.85
0631             height: crown.width * 0.5
0632             sourceSize.width: crown.width
0633             sourceSize.height: crown.height
0634             visible: ((bar.level > 2) && !isCaptured) ? true : false
0635             source: url + "crown.svg"
0636 
0637             property bool isCaptured: false
0638 
0639             function captureCrown() {
0640                 upperGate.isGateOpen = true
0641                 isCaptured = true
0642                 sparkle.createSparkle()
0643             }
0644 
0645             function reset() {
0646                 isCaptured = false
0647                 upperGate.isGateOpen = false
0648             }
0649 
0650             x: background.width / 2
0651             y: background.height - (subSchemaImage.height * 2)
0652             z: 1
0653 
0654             Body {
0655                 id: crownbody
0656                 target: crown
0657                 bodyType: Body.Static
0658                 sleepingAllowed: true
0659                 fixedRotation: true
0660                 linearDamping: 0
0661 
0662                 fixtures: Box {
0663                     id: crownfixer
0664                     width: crown.width
0665                     height: crown.height
0666                     sensor: true
0667                     categories: items.crownCategory
0668                     collidesWith: crown.visible ? items.submarineCategory : Fixture.None
0669                     density: 0.1
0670                     friction: 0
0671                     restitution: 0
0672                 }
0673             }
0674         }
0675 
0676         Whale {
0677             id: whale
0678             visible: (bar.level > 5) ? true : false
0679 
0680             y: rock2.y - (rock2.height * 1.15)
0681             z: 1
0682 
0683             leftLimit: 0
0684             rightLimit: background.width - whale.width - (upperGate.visible ? upperGate.width : 0)
0685         }
0686 
0687         Image {
0688             id: ship
0689 
0690             width: background.width / 9
0691             sourceSize.width: ship.width
0692             fillMode: Image.PreserveAspectFit
0693 
0694             visible: (bar.level > 3) ? true : false
0695             source: collided ? url + "boat-hit.svg" : url + "boat.svg"
0696             x: initialXPosition
0697             z: 1
0698 
0699             anchors.bottom: waterLevel.top
0700 
0701             property bool movingLeft: true
0702             property bool collided: false
0703             property real initialXPosition: background.width - ship.width - (upperGate.visible ? upperGate.width : 0)
0704             property real horizontalSpeed: 1
0705 
0706             function reset() {
0707                 ship.collided = false
0708                 ship.x = initialXPosition
0709             }
0710 
0711             function collide() {
0712                 /* Add few visual effects */
0713                 collided = true
0714             }
0715 
0716             transform: Rotation {
0717                 id: rotateShip
0718                 origin.x: ship.width / 2;
0719                 origin.y: 0;
0720                 axis { x: 0; y: 1; z: 0 } angle: 0
0721             }
0722 
0723             SequentialAnimation {
0724                 id: rotateShipLeft
0725                 loops: 1
0726                 PropertyAnimation {
0727                     target: rotateShip
0728                     properties: "angle"
0729                     from: 0
0730                     to: 180
0731                     duration: 500
0732                 }
0733             }
0734 
0735             SequentialAnimation {
0736                 id: rotateShipRight
0737                 loops: 1
0738                 PropertyAnimation {
0739                     target: rotateShip
0740                     properties: "angle"
0741                     from: 180
0742                     to: 0
0743                     duration: 500
0744                 }
0745             }
0746 
0747             onXChanged: {
0748                 if (x <= 0) {
0749                     rotateShipLeft.start()
0750                     movingLeft = false
0751                 } else if (x >= background.width - ship.width - (upperGate.visible ? upperGate.width : 0)) {
0752                     rotateShipRight.start()
0753                     movingLeft = true
0754                 }
0755             }
0756 
0757             Body {
0758                 id: shipbody
0759                 target: ship
0760                 bodyType: Body.Dynamic
0761                 sleepingAllowed: true
0762                 fixedRotation: true
0763                 linearDamping: 0
0764                 linearVelocity: Qt.point( (ship.collided ? 0 : ((ship.movingLeft ? -1 : 1) * ship.horizontalSpeed)), 0)
0765 
0766                 fixtures: Box {
0767                     id: shipfixer
0768                     width: ship.width
0769                     height: ship.height
0770                     categories: items.shipCategory
0771                     collidesWith: ship.visible ? items.submarineCategory : Fixture.None
0772                     density: 1
0773                     friction: 0
0774                     restitution: 0
0775 
0776                     onBeginContact: ship.collide()
0777                 }
0778             }
0779         }
0780 
0781         Image {
0782             id: rock2
0783             width: background.width / 6
0784             height: rock2.width * 0.48
0785             z: 5
0786 
0787             visible: (bar.level > 4) ? true : false
0788             anchors.bottom: crown.bottom
0789             anchors.left: crown.right
0790             source: "qrc:/gcompris/src/activities/mining/resource/stone2.svg"
0791 
0792             transform: Rotation {
0793                 origin.x: rock2.width / 2;
0794                 origin.y: rock2.height / 2
0795                 axis { x: 0; y: 0; z: 1 } angle: 180
0796             }
0797 
0798             Body {
0799                 id: rock2Body
0800                 target: rock2
0801                 bodyType: Body.Static
0802                 sleepingAllowed: true
0803                 linearDamping: 0
0804 
0805                 fixtures: Box {
0806                     id: rock2Fixer
0807                     categories: items.rockCategory
0808                     collidesWith: rock2.visible ? items.submarineCategory : Fixture.None
0809                     x: rock2.width / 8
0810                     y: rock2.height / 12
0811                     width: rock2.width / 1.2
0812                     height: rock2.height / 1.5
0813                     density: 1
0814                     friction: 0
0815                     restitution: 0
0816                 }
0817             }
0818         }
0819 
0820         /* Just a space */
0821         Rectangle {
0822             id: space
0823             width: bar.level < 8 ? rock1.width : rock1.width * (1 - (Math.random() * 0.5))
0824             height: rock1.height
0825 
0826             color: "transparent"
0827             anchors {
0828                 right: crown.left
0829                 bottom: crown.bottom
0830             }
0831         }
0832 
0833         Image {
0834             id: rock1
0835             width: rock2.width
0836             height: rock2.width * 0.46
0837             z: 5
0838             visible: (bar.level > 6) ? true : false
0839             anchors.bottom: crown.bottom
0840             anchors.right: space.left
0841             source: "qrc:/gcompris/src/activities/mining/resource/stone1.svg"
0842 
0843             Body {
0844                 id: rock1Body
0845                 target: rock1
0846                 bodyType: Body.Static
0847                 sleepingAllowed: true
0848                 linearDamping: 0
0849 
0850                 fixtures: [
0851                     Circle {
0852                         id: rock1FixerLeft
0853                         categories: items.rockCategory
0854                         collidesWith: rock1.visible ? items.submarineCategory : Fixture.None
0855                         x: rock1.width / 10
0856                         radius: rock1.width / 4
0857                         density: 1
0858                         friction: 0
0859                         restitution: 0
0860                     },Circle {
0861                         id: rock1FixerRight
0862                         categories: items.rockCategory
0863                         collidesWith: rock1.visible ? items.submarineCategory : Fixture.None
0864                         x: rock1.width / 1.6
0865                         y: rock1.height / 4
0866                         radius: rock1.width / 6
0867                         density: 1
0868                         friction: 0
0869                         restitution: 0
0870                     }
0871                 ]
0872             }
0873         }
0874 
0875         Image {
0876             id: rock3
0877             width: background.width 
0878             height: background.height * 0.25
0879             sourceSize.width: rock3.width
0880             sourceSize.height: rock3.height
0881 
0882             visible: (bar.level > 2) ? true : false
0883             anchors.top: crown.top
0884             anchors.horizontalCenter: crown.left
0885 //             anchors.topMargin: height * 0.5
0886             source: url + "rocks.svg"
0887         }
0888         
0889         Timer {
0890             /*
0891              * A delay is used since on setting fullscreen on/off
0892              * first the onWidthChanged is executed, followed by
0893              * the width change
0894              */
0895             id: updateOnWidthReset
0896             repeat: false
0897             interval: 100
0898             running: false
0899             onTriggered: {
0900                 whale.reset()
0901                 ship.reset()
0902             }
0903         }
0904 
0905         Controls {
0906             id: controls
0907             z: 10
0908             enginePosition.x: background.width * 0.1
0909             enginePosition.y: buttonPlusY + buttonSize * 0.2
0910             engineWidth: background.width / 8
0911             engineHeight: hori ? buttonSize * 1.8 : buttonSize * 2.5
0912             submarineHorizontalSpeed: submarine.currentFinalVelocity * 1000
0913 
0914             leftTankVisible: bar.level >= 7 ? true : false
0915             leftBallastTankPosition.x: background.width * 0.35
0916             leftBallastTankPosition.y: enginePosition.y
0917             leftBallastTankWidth: background.width / 8
0918             leftBallastTankHeight: engineHeight
0919 
0920             centralTankVisible:  bar.level < 7 ? true : false
0921             centralBallastTankPosition.x: background.width * 0.45
0922             centralBallastTankPosition.y: enginePosition.y
0923             centralBallastTankWidth: background.width / 8
0924             centralBallastTankHeight: engineHeight
0925 
0926             rightTankVisible:  bar.level >= 7 ? true : false
0927             rightBallastTankPosition.x: background.width * 0.6
0928             rightBallastTankPosition.y: enginePosition.y
0929             rightBallastTankWidth: background.width / 8
0930             rightBallastTankHeight: engineHeight
0931 
0932             divingPlaneVisible: true
0933             divingPlanePosition.x: background.width * 0.8
0934             divingPlanePosition.y: enginePosition.y + (engineHeight * 0.5) - (divingPlaneHeight * 0.5)
0935             divingPlaneWidth: hori ? background.width * 0.08 : background.width * 0.12
0936             divingPlaneHeight: divingPlaneWidth * 0.33
0937             buttonSize: hori ? subSchemaImage.height * 0.3 : subSchemaImage.height * 0.2
0938             buttonPlusY: hori ? background.height * 0.61 : background.height * 0.63
0939             buttonMinusY: enginePosition.y + engineHeight - buttonSize * 0.8
0940         }
0941 
0942         DialogHelp {
0943             id: dialogHelp
0944             onClose: home()
0945         }
0946 
0947         Bar {
0948             id: bar
0949             level: items.currentLevel + 1
0950             content: BarEnumContent { value: help | home | reload | level }
0951             onHelpClicked: {
0952                 displayDialog(dialogHelp)
0953             }
0954             onReloadClicked: Activity.initLevel()
0955             onPreviousLevelClicked: Activity.previousLevel()
0956             onNextLevelClicked: Activity.nextLevel()
0957             onHomeClicked: home()
0958         }
0959 
0960         Bonus {
0961             id: bonus
0962             onLoose: Activity.initLevel()
0963             Component.onCompleted: win.connect(Activity.nextLevel)
0964         }
0965         /*
0966         DebugDraw {
0967             id: debugDraw
0968             world: physicalWorld
0969             anchors.fill: parent
0970             opacity: 0.75
0971             visible: false
0972         }
0973 
0974         MouseArea {
0975             id: debugMouseArea
0976             anchors.fill: parent
0977             onPressed: debugDraw.visible = !debugDraw.visible
0978         }
0979         */
0980     }
0981 
0982 }