File indexing completed on 2024-04-28 15:07:53

0001 /* GCompris - land_safe.js
0002  *
0003  * SPDX-FileCopyrightText: 2016 Holger Kaelberer <holger.k@elberer.de>
0004  *
0005  * Authors:
0006  *   Matilda Bernard <serah4291@gmail.com> (GTK+ version)
0007  *   Holger Kaelberer <holger.k@elberer.de> (Qt Quick port)
0008  *
0009  *   SPDX-License-Identifier: GPL-3.0-or-later
0010  */
0011 
0012 /* ToDo:
0013  * - check for shader availability
0014  * - test more generic on-screen controls
0015  * (- use polygon fixture for rocket)
0016  *
0017  * Some gravitational forces:
0018  * !- Ceres 0,27
0019  * !- Pluto: 0,62 m/s²
0020  * !- Titan: 1,352 m/s²
0021  * - Ganymed: 1,428
0022  * !- Moon: 1,622 m/s²
0023  * - Io: 1,796 m/s²
0024  * !- Mars: 3,711 m/s²
0025  * - Merkur: 3,7 m/s²
0026  * !- Venus: 8,87 m/s²
0027  * !- Earth: 9,807 m/s²
0028  * - Jupiter: 24,79 m/s²
0029  */
0030 
0031 .pragma library
0032 .import QtQuick 2.12 as Quick
0033 .import GCompris 1.0 as GCompris
0034 .import "qrc:/gcompris/src/core/core.js" as Core
0035 
0036 var levels;
0037 var numberOfLevel;
0038 var items = null;
0039 var baseUrl = "qrc:/gcompris/src/activities/land_safe/resource";
0040 var startingAltitudeReal = 100.0;
0041 var startingOffsetPx = 10;  // y-value for setting rocket initially
0042 var maxLandingVelocity = 10;
0043 var leftRightAccel = 0.1;   // accel force set on horizontal accel
0044 //var minAccel = 0.1;
0045 var maxAccel = 0.15;
0046 var accelSteps = 3;
0047 var dAccel = maxAccel / accelSteps;//- minAccel;
0048 var barAtStart;
0049 var maxFuel = 100.0;
0050 var currentFuel = 0.0;
0051 var lastLevel = -1;
0052 var debugDraw = false;
0053 var zoomStack = new Array;
0054 
0055 function start(items_) {
0056     items = items_;
0057     lastLevel = -1;
0058     levels = items_.levels;
0059     numberOfLevel = levels.length;
0060     items.currentLevel = Core.getInitialLevel(numberOfLevel);
0061 
0062     barAtStart = GCompris.ApplicationSettings.isBarHidden;
0063     GCompris.ApplicationSettings.isBarHidden = true;
0064     initLevel();
0065 }
0066 
0067 function stop() {
0068     GCompris.ApplicationSettings.isBarHidden = barAtStart;
0069 }
0070 
0071 function initLevel() {
0072     if (items === null)
0073         return;
0074 
0075 
0076     items.zoom = 1;
0077     zoomStack = [];
0078     // init level:
0079     items.accelerometer.min = -levels[items.currentLevel].gravity;
0080     items.accelerometer.max = levels[items.currentLevel].maxAccel*10-levels[items.currentLevel].gravity;
0081     maxAccel = levels[items.currentLevel].maxAccel;
0082     accelSteps = levels[items.currentLevel].accelSteps;
0083     dAccel = maxAccel / accelSteps;//- minAccel;
0084     startingAltitudeReal = levels[items.currentLevel].alt;
0085     items.gravity = levels[items.currentLevel].gravity;
0086     items.mode = levels[items.currentLevel].mode;
0087     maxFuel = levels[items.currentLevel].fuel;
0088     currentFuel = (maxFuel == -1 ? 1 : maxFuel); // -1 means unlimited fuel
0089 
0090     // reset everything:
0091     items.explosion.hide();
0092     items.rocket.show();
0093     // place rocket randomly:
0094     var max = items.background.width - items.accelerometer.width - items.landing.width - items.rocket.width;
0095     var min = 20;
0096     items.rocket.x = Math.random() * (max- min) + min;
0097     items.rocket.y = startingOffsetPx;
0098     items.rocket.rotation = 0;
0099     items.rocket.accel = 0;
0100     items.rocket.leftAccel = 0;
0101     items.rocket.rightAccel = 0;
0102     items.rocket.body.linearVelocity = Qt.point(0,0)
0103     // for landing random placement shall not intersect with bar -- or osd
0104     // controls on mobile:
0105     min = items.onScreenControls ? items.leftRightControl.width : items.bar.fullButton * items.bar.barZoom;
0106     max = items.onScreenControls ? items.background.width - items.upDownControl.width - items.landing.width : max;
0107     items.landing.anchors.leftMargin = Math.random() * (max- min) + min;
0108     items.landing.overlayColor = "-g";
0109     items.leftEngine.reset();
0110     items.rightEngine.reset();
0111     items.bottomEngine.reset();
0112 
0113     // initialize world:
0114     items.world.pixelsPerMeter = pxYToAltitude(items.rocket.y) / startingAltitudeReal;
0115     items.world.gravity = Qt.point(0, items.gravity)
0116     items.world.running = false;
0117 
0118 //    console.log("Starting level (surfaceOff=" + items.ground.surfaceOffset + ", ppm=" + items.world.pixelsPerMeter + ")");
0119 
0120     if (levels[items.currentLevel].intro !== undefined) {
0121         items.ok.visible = false;
0122         items.intro.intro = [levels[items.currentLevel].intro];
0123         items.intro.index = 0;
0124     } else {
0125         // go
0126         items.intro.intro = [];
0127         items.intro.index = -1;
0128         items.ok.visible = true;
0129     }
0130     lastLevel = items.currentLevel;
0131 }
0132 
0133 function pxAltitudeToY(alt)
0134 {
0135     var y = items.background.height - items.ground.height + items.ground.surfaceOffset
0136             - items.rocket.height - 1 - alt;
0137     return y;
0138 }
0139 
0140 function pxYToAltitude(y)
0141 {
0142     var altPx = items.background.height - items.ground.height + items.ground.surfaceOffset
0143             - y - items.rocket.height
0144             - 1;  // landing is 1 pixel above ground surface
0145     return altPx;
0146 }
0147 
0148 // calc real height of rocket in meters above surface
0149 function getAltitudeReal()
0150 {
0151     var altPx = pxYToAltitude(items.rocket.y);
0152     var altReal = altPx / items.world.pixelsPerMeter;
0153     return altReal;
0154 }
0155 
0156 function nextLevel() {
0157     items.currentLevel = Core.getNextLevel(items.currentLevel, numberOfLevel);
0158     initLevel();
0159 }
0160 
0161 function previousLevel() {
0162     items.currentLevel = Core.getPreviousLevel(items.currentLevel, numberOfLevel);
0163     initLevel();
0164 }
0165 
0166 function processKeyPress(event)
0167 {
0168     var key = event.key;
0169     event.accepted = true;
0170     if(!items.world.running) {
0171         if(key === Qt.Key_Enter || key === Qt.Key_Return || key == Qt.Key_Space)
0172             items.ok.clicked();
0173         else
0174             return;
0175     }
0176 
0177     if(items.bonus.isPlaying) {
0178         return;
0179     }
0180     var newAccel = 0;
0181     if(key === Qt.Key_Up || key === Qt.Key_Down) {
0182         if (key === Qt.Key_Up) {
0183             if(items.rocket.accel === 0)
0184                 newAccel = dAccel;
0185             else
0186                 newAccel = items.rocket.accel + dAccel;
0187         } else if(key === Qt.Key_Down)
0188             newAccel = items.rocket.accel - dAccel;
0189 
0190         if (newAccel < 0)
0191             newAccel = 0;
0192         if (newAccel > maxAccel)
0193             newAccel = maxAccel;
0194 
0195         if(newAccel !== items.rocket.accel && currentFuel > 0)
0196             items.rocket.accel = newAccel;
0197     } else if(key === Qt.Key_Right || key === Qt.Key_Left) {
0198         if (items.mode === "simple") {
0199             if(key === Qt.Key_Right && !event.isAutoRepeat && currentFuel > 0) {
0200                 items.rocket.leftAccel = leftRightAccel;
0201                 items.rocket.rightAccel = 0.0;
0202             } else if(key === Qt.Key_Left && !event.isAutoRepeat && currentFuel > 0) {
0203                 items.rocket.rightAccel = leftRightAccel;
0204                 items.rocket.leftAccel = 0.0;
0205             }
0206         } else { // "rotation"
0207             if(key === Qt.Key_Right)
0208                 items.rocket.rotation += 10;
0209             else if(key === Qt.Key_Left)
0210                 items.rocket.rotation -= 10;
0211             //console.log("XXX rotation=" + items.rocket.rotation + " bodyRot=" + items.rocket.body.rotation);
0212         }
0213     }
0214 }
0215 
0216 function processKeyRelease(event)
0217 {
0218     if (!items.world.running) {
0219         event.accepted = false;
0220         return;
0221     }
0222     if(items.bonus.isPlaying) {
0223         event.accepted = false;
0224         return;
0225     }
0226 
0227     var key = event.key;
0228     event.accepted = true;
0229     //console.log("XXX release " + key + " = " + event.isAutoRepeat + " = " + Qt.Key_Right);
0230     if (key === Qt.Key_Right && !event.isAutoRepeat) {
0231         items.rocket.leftAccel = 0;
0232     } else if (key === Qt.Key_Left && !event.isAutoRepeat) {
0233         items.rocket.rightAccel = 0;
0234     } else
0235         event.accepted = false;
0236 }
0237 
0238 function finishLevel(success)
0239 {
0240     items.rocket.accel = 0;
0241     if (success) {
0242         items.rocket.leftAccel = 0;
0243         items.rocket.rightAccel = 0;
0244         items.rocket.body.linearVelocity = Qt.point(0,0)
0245 
0246         items.bonus.good("lion");
0247     } else {
0248         // don't reset physics on a crash so the explosion rolls along landscape.
0249 
0250         items.explosion.show();
0251         items.rocket.hide();
0252         items.bonus.bad("lion");
0253     }
0254 }
0255 
0256 function degToRad(degrees) {
0257   return degrees * Math.PI / 180;
0258 }
0259 
0260 //note: using 0 with transparent font color instead of space to keep consistent spacing
0261 //simple function for the fuel and altitude values
0262 function minimum3Chars(number_) {
0263     var numberTxt = number_.toString();
0264     if(number_ < 100 && number_ >= 10)
0265         numberTxt = "<font color=\"#00FFFFFF\">0</font>" + numberTxt;
0266     else if(number_ < 10)
0267         numberTxt = "<font color=\"#00FFFFFF\">00</font>" + numberTxt;
0268     return numberTxt;
0269 }
0270 
0271 //function for the velocity and acceleration values
0272 function fixedSizeString(number_, multiplier_, chars_, emptyDecimal_) {
0273     var numberRound = Math.round(number_ * multiplier_) / multiplier_;
0274     var numberTxt = numberRound.toString();
0275     if(numberRound % 1 === 0)
0276         numberTxt = numberTxt + emptyDecimal_;
0277     var charsToAdd = chars_ - numberTxt.length;
0278     if(numberRound >= 0) {
0279         numberTxt = "<font color=\"#00FFFFFF\">-</font>" + numberTxt;
0280         charsToAdd--;
0281     }
0282     for(; charsToAdd > 0; charsToAdd--)
0283         numberTxt = "<font color=\"#00FFFFFF\">0</font>" + numberTxt;
0284     return numberTxt;
0285 }