File indexing completed on 2024-05-05 15:53:18

0001 /*
0002  gcompris - planegame.js
0003 
0004  Copyright (C)
0005  2003, 2014: Bruno Coudoin: initial version
0006  2014: Johnny Jazeix: Qt port
0007  2014: Bruno Coudoin: Added support for dataset, smooth plane anim
0008 
0009  SPDX-License-Identifier: GPL-3.0-or-later
0010 */
0011 
0012 .pragma library
0013 .import QtQuick 2.12 as Quick
0014 .import GCompris 1.0 as GCompris //for ApplicationInfo
0015 .import "qrc:/gcompris/src/core/core.js" as Core
0016 
0017 var url = "qrc:/gcompris/src/activities/planegame/"
0018 
0019 var max_velocity = 500 * GCompris.ApplicationInfo.ratio
0020 var numberOfLevel
0021 var currentSubLevel
0022 var numberOfSubLevels
0023 
0024 var upPressed
0025 var downPressed
0026 var leftPressed
0027 var rightPressed
0028 
0029 var items
0030 var dataset
0031 
0032 var cloudComponent = Qt.createComponent(url + "Cloud.qml");
0033 var clouds = new Array;
0034 var cloudsErased = new Array;
0035 
0036 var audioFileToPlay;
0037 var levelComplete = false;
0038 
0039 function start(items_, dataset_) {
0040     Core.checkForVoices(items_.activityPage);
0041 
0042     items = items_
0043     dataset = dataset_
0044     numberOfLevel = dataset.length
0045     items.currentLevel = Core.getInitialLevel(numberOfLevel)
0046     if(items.showTutorial === false) {
0047       initLevel()
0048     }
0049 }
0050 
0051 function stop() {
0052     cloudDestroy(clouds)
0053     cloudDestroy(cloudsErased)
0054     items.movePlaneTimer.stop()
0055     items.cloudCreation.stop()
0056 }
0057 
0058 function cloudDestroy(clouds) {
0059     for(var i = clouds.length - 1; i >= 0 ; --i) {
0060         var cloud = clouds[i];
0061         // Remove the cloud
0062         cloud.destroy()
0063         // Remove the element from the list
0064         clouds.splice(i, 1)
0065     }
0066 }
0067 
0068 function initLevel() {
0069     currentSubLevel = 0
0070     numberOfSubLevels = dataset[items.currentLevel].data.length
0071 
0072     items.movePlaneTimer.stop();
0073     items.cloudCreation.stop()
0074 
0075     items.score.message = dataset[items.currentLevel].data[currentSubLevel]
0076     items.score.visible = dataset[items.currentLevel].showNext
0077 
0078     upPressed = false
0079     downPressed = false
0080     leftPressed = false
0081     rightPressed = false
0082 
0083     cloudDestroy(clouds)
0084     cloudDestroy(cloudsErased)
0085 
0086     // Tend towards 0.5 ratio
0087     items.plane.state = "init"
0088     items.movePlaneTimer.interval = 1000
0089     items.movePlaneTimer.start();
0090     items.cloudCreation.start()
0091 
0092     levelComplete = false
0093 
0094     //Inject the first cloud now
0095     createCloud()
0096 }
0097 
0098 function nextLevel() {
0099     items.currentLevel = Core.getNextLevel(items.currentLevel, numberOfLevel);
0100     initLevel();
0101 }
0102 
0103 function previousLevel() {
0104     items.currentLevel = Core.getPreviousLevel(items.currentLevel, numberOfLevel);
0105     initLevel();
0106 }
0107 
0108 function repositionObjectsOnWidthChanged(factor) {
0109     if(items && items.plane) {
0110         items.movePlaneTimer.interval = 1000
0111         items.plane.state = "init"
0112     }
0113     for(var i = clouds.length - 1; i >= 0 ; --i) {
0114         var cloud = clouds[i];
0115     }
0116 }
0117 
0118 function repositionObjectsOnHeightChanged(factor) {
0119     if(items && items.plane) {
0120         items.movePlaneTimer.interval = 1000
0121         items.plane.state = "init"
0122     }
0123     for(var i = clouds.length - 1; i >= 0 ; --i) {
0124         var cloud = clouds[i];
0125         cloud.y *= factor
0126     }
0127 }
0128 
0129 var cloudCounter = 1
0130 function createCloud() {
0131     if(levelComplete) {
0132         return
0133     }
0134     var cloud = cloudComponent.createObject(
0135                 items.background, {
0136                     "background": items.background,
0137                     "x": items.background.width,
0138                     "heightRatio": 1.0 - 0.5 * items.currentLevel / 10
0139                 });
0140 
0141     /* Random cloud number but at least one in 3 */
0142     if(cloudCounter++ % 3 == 0 || getRandomInt(0, 1) === 0) {
0143         /* Put the target */
0144         cloud.text = dataset[items.currentLevel].data[currentSubLevel];
0145         cloudCounter = 1
0146     } else {
0147         var min = Math.max(1, currentSubLevel - 1);
0148         var index = Math.min(min + getRandomInt(0, currentSubLevel - min + 3),
0149                              numberOfSubLevels - 1)
0150         cloud.text = dataset[items.currentLevel].data[index]
0151     }
0152 
0153     clouds.push(cloud);
0154 }
0155 
0156 function getRandomInt(min, max) {
0157     return Math.floor(Math.random() * (max - min + 1) + min);
0158 }
0159 
0160 function processPressedKey(event) {
0161     switch(event.key) {
0162     case Qt.Key_Right:
0163         rightPressed = true;
0164         event.accepted = true;
0165         break;
0166     case Qt.Key_Left:
0167         leftPressed = true;
0168         event.accepted = true;
0169         break;
0170     case Qt.Key_Up:
0171         upPressed = true;
0172         event.accepted = true;
0173         break;
0174     case Qt.Key_Down:
0175         downPressed = true;
0176         event.accepted = true;
0177     }
0178 }
0179 
0180 function processReleasedKey(event) {
0181     switch(event.key) {
0182     case Qt.Key_Right:
0183         rightPressed = false;
0184         event.accepted = true;
0185         break;
0186     case Qt.Key_Left:
0187         leftPressed = false;
0188         event.accepted = true;
0189         break;
0190     case Qt.Key_Up:
0191         upPressed = false;
0192         event.accepted = true;
0193         break;
0194     case Qt.Key_Down:
0195         downPressed = false;
0196         event.accepted = true;
0197     }
0198 }
0199 
0200 var speedX = 0
0201 var speedY = 0
0202 var speedFactor = 20
0203 
0204 function computeVelocity() {
0205 
0206     if(rightPressed && speedX < 300)
0207         speedX += speedFactor
0208 
0209     if(leftPressed && speedX > -300)
0210         speedX -= speedFactor
0211 
0212     if(!rightPressed && speedX > 0)
0213         speedX = 0
0214     else if(!leftPressed && speedX < 0)
0215         speedX = 0
0216     else if(leftPressed || rightPressed)
0217         items.plane.x += speedX
0218 
0219     if(upPressed && speedY > -300)
0220         speedY -= speedFactor
0221     if(downPressed && speedY < 300)
0222         speedY += speedFactor
0223 
0224     if(!upPressed && speedY < 0)
0225         speedY = 0
0226     else if(!downPressed && speedY > 0)
0227         speedY = 0
0228     else if(upPressed || downPressed)
0229         items.plane.y += speedY
0230 
0231     items.plane.rotation = speedX * 10 / max_velocity
0232 }
0233 
0234 /* We move x/y of the plane to let its smooth animation track it */
0235 function planeMove() {
0236 
0237     if(items.plane.x + items.plane.width > items.background.width) {
0238         items.plane.x = items.background.width - items.plane.width;
0239     }
0240     if(items.plane.x < 0) {
0241         items.plane.x = 0;
0242     }
0243 
0244     if(items.plane.y < 0) {
0245         items.plane.y = 0;
0246     }
0247     if(items.plane.y + items.plane.height > items.background.height - items.bar.height) {
0248         items.plane.y = items.background.height - (items.plane.height + items.bar.height);
0249     }
0250 
0251 }
0252 
0253 function isIn(x1, y1, px1, py1, px2, py2) {
0254     return (x1>px1 && x1<px2 && y1>py1 && y1<py2)
0255 }
0256 
0257 function handleCollisionsWithCloud() {
0258     var planeX1 = items.plane.x
0259     var planeX2 = items.plane.x + items.plane.width
0260     var planeY1 = items.plane.y
0261     var planeY2 = items.plane.y + items.plane.height
0262 
0263     var gotOne = false
0264     if(clouds !== undefined) {
0265         for(var i = clouds.length - 1; i >= 0 ; --i) {
0266             var cloud = clouds[i];
0267             var x1 = cloud.x
0268             var x2 = cloud.x + cloud.width
0269             var y1 = cloud.y
0270             var y2 = cloud.y + cloud.height
0271 
0272             if(x2 < 0) {
0273                 // Remove the cloud
0274                 cloud.destroy()
0275                 clouds.splice(i, 1)
0276             }
0277             else if(isIn(x1, y1, planeX1, planeY1, planeX2, planeY2) ||
0278                     isIn(x2, y1, planeX1, planeY1, planeX2, planeY2) ||
0279                     isIn(x1, y2, planeX1, planeY1, planeX2, planeY2) ||
0280                     isIn(x2, y2, planeX1, planeY1, planeX2, planeY2)) {
0281 
0282                 gotOne = true
0283                 // Collision, look for id
0284                 if(cloud.text === dataset[items.currentLevel].data[currentSubLevel]) {
0285                     playLetterSound(cloud.text)
0286                     // Move the cloud to the erased list
0287                     cloud.done()
0288                     cloudsErased.push(cloud)
0289                     clouds.splice(i, 1)
0290                     currentSubLevel++
0291 
0292                     if(currentSubLevel === numberOfSubLevels) {
0293                         levelComplete = true
0294                         /* Try the next level */
0295                         if(items.audioVoices.hasAudio && items.fileChecker.exists(audioFileToPlay)) {
0296                             items.goToNextLevel = true
0297                         } else {
0298                             items.bonus.good("flower")
0299                         }
0300                     } else {
0301                         items.score.message = dataset[items.currentLevel].data[currentSubLevel]
0302                     }
0303                 } else {
0304                     /* Touched the wrong cloud */
0305                     if(!cloud.touched)
0306                         items.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/crash.wav")
0307                     cloud.touch()
0308                 }
0309                 break;
0310             }
0311         }
0312 
0313         // Reset the touched state on the clouds
0314         if(!gotOne) {
0315             for(var i = clouds.length - 1; i >= 0 ; --i) {
0316                 clouds[i].touched = false
0317             }
0318         }
0319     }
0320 }
0321 
0322 function playLetterSound(number) {
0323     if(number > 9) {
0324         audioFileToPlay = GCompris.ApplicationInfo.getAudioFilePath("voices-$CA/$LOCALE/alphabet/" + number + ".$CA")
0325     } else {
0326         audioFileToPlay = GCompris.ApplicationInfo.getAudioFilePath("voices-$CA/$LOCALE/alphabet/" + Core.getSoundFilenamForChar(number))
0327     }
0328     items.audioVoices.play(audioFileToPlay)
0329 }