File indexing completed on 2024-05-19 07:29:47
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 }