Learn what Felgo offers to help your business succeed. Start your free evaluation today! Felgo for Your Business

ChickenOutbreak2 Demo

 import QtQuick 2.0
 import Felgo 4.0
 import "entities"
 import "scripts/levelLogic.js" as LevelLogic

 // the level gets moved in the negative y direction (so upwards)
 Item {
   id: level
   // use the logical size as the level size
   width: scene.width

   state: "stopped"

   property alias movementAnimation: levelMovementAnimation

   // just as an abbreviation of typing, so instead of scene.gridSize just gridSize can be written in this file
   property real gridSize: scene.gridSize

   // available columns for creating roosts - the current logical scene width is 320, gridSize is 48, so 6 and a half roosts can be displayed horizontally
   property int roostColumns: width/gridSize

   // gets used to measure how much the level was moved downwards in the last frame - if this is bigger than gridSize, a new row will be created in onYChanged
   property real lastY: 0

   // how many new rows were created, it starts with 0 if the level has y position 0, and then gets increased with every gridSize
   // gets initialized in onCompleted
   property real currentRow: 0

   // this is needed so an alias can be created from the main window!
   property alias player: player

   // specifies the px/second how much the level moves
   property real levelMovementSpeedMinimum: 20
   property real levelMovementSpeedMaximum: getLevelMovementSpeedMaximum()
   function getLevelMovementSpeedMaximum() {
     switch(difficulty) {
     case 0: return diff0MaxSpeed
     case 1: return diff1MaxSpeed
     case 2: return diff2MaxSpeed
     case 3: return diff3MaxSpeed
     case 4: return diff4MaxSpeed
     case 5: return diff5MaxSpeed
     case 6: return diff6MaxSpeed
     }
   }
   onLevelMovementSpeedMaximumChanged: console.debug("levelMovementSpeedMaximum changed to " + levelMovementSpeedMaximum)

   property real currentLevelMovementSpeed
   // after 30seconds, the maximum speed will be reached - if you set this too high, also increase the gravity so the player falls faster than the level moves
   property int levelMovementDurationTillMaximum: 15

   // with 9% probability, a roost will get created in a row for any column
   // if it gets set too low, the game will be unplayable because too few roosts are created, so balance this with care!
   property real platformCreationProbability: getPlatformCreationProbability()
   function getPlatformCreationProbability() {
     switch(difficulty) {
     case 0: return diff0PlatformCreation
     case 1: return diff1PlatformCreation
     case 2: return diff2PlatformCreation
     case 3: return diff3PlatformCreation
     case 4: return diff4PlatformCreation
     case 5: return diff5PlatformCreation
     case 6: return diff6PlatformCreation
     }
   }
   onPlatformCreationProbabilityChanged: console.debug("platformCreationProbability changed to " + platformCreationProbability)

   property real platformRotationProbability: getPlatformRotationProbability()
   function getPlatformRotationProbability(){
     switch(difficulty) {
     case 0: return diff0PlatformRot
     case 1: return diff1PlatformRot
     case 2: return diff2PlatformRot
     case 3: return diff3PlatformRot
     case 4: return diff4PlatformRot
     case 5: return diff5PlatformRot
     case 6: return diff6PlatformRot
     }
   }
   onPlatformRotationProbabilityChanged: console.debug("platformRotationProbability changed to " + platformRotationProbability)

   property int gravity: getGravity()
   function getGravity(){
     switch(difficulty) {
     case 0: return diff0Gravity
     case 1: return diff1Gravity
     case 2: return diff2Gravity
     case 3: return diff3Gravity
     case 4: return diff4Gravity
     case 5: return diff5Gravity
     case 6: return diff6Gravity
     }
   }

   onGravityChanged: console.debug("gravity changed to " + gravity)

   property real wheelCreationProbability: 0.007
   property real minimumWheelHeightDifference: 100
   property int lastWheelY: 0
   // probability of 40% to create a corn on top of the roost, so in 3 of 10 roosts there will be a corn created
   property real coinCreationPropability: 0.4
   // probability of 15% that a coin will be a BadCoin, worth negative points
   property real badCoinCreationPropability: 0.15
   // probability of 20% that a coin will be a TrippleCoin, worth three times more
   property real trippleCoinCreationPropability: 0.2
   // probability of 4% that a coin will be a Parachute
   property real parachuteCreationPropability: 0.013
   // probability of 5% that a coin will be a DoublePoints
   property real doublePointsCreationPropability: 0.05
   // windows get created randomly as well - they only have visual effect, but don't set too high because then it looks boring
   property real windowCreationProbability: 0.10
   // this avoids creating too many windows, so not possible to have more than 2 on a scene with this code!
   property real minimumWindowHeightDifference: 300

   property bool noDeath: false
   property bool noFont: false
   property bool noManualGC: true
   property bool useScheduling: false
   property bool background: true

   onUseSchedulingChanged: {
     if(useScheduling) {
       vplayScheduler.schedulingMethod = VPlayScheduler.Accumulated
     } else {
       vplayScheduler.schedulingMethod = VPlayScheduler.None
     }
   }

   onBackgroundChanged: {
     levelBackground.visible = background
     levelBackground.running = levelMovementAnimation.running
   }

   EditableComponent {
       editableType: "chickenData"
       properties: {
         "Level" : {
           "levelMovementSpeedMinimum":               {"min": 0, "max": 1000, "label": "Min"},
           "levelMovementSpeedMaximum":               {"min": 0, "max": 1000, "label": "Max"},
           "levelMovementDurationTillMaximum":        {"min": 0, "max": 200, "label": "Speedup"},
           "noDeath":        {"min": 0, "max": 1, "label": "No Death"},
           "platformCreationProbability":        {"min": 0, "max": 1.0, "stepsize": 0.01, "label": "Platforms"},
           "coinCreationPropability":        {"min": 0, "max": 1.0, "stepsize": 0.01, "label": "Coins"},
           "windowCreationProbability":        {"min": 0, "max": 1.0, "stepsize": 0.01, "label": "Window"},
           "wheelCreationProbability":        {"min": 0, "max": 1.0, "stepsize": 0.01, "label": "Wheel"},

         },
         "Performance": {
           "noFont":        {"min": 0, "max": 1, "label": "No Font"},
           "noManualGC":        {"min": 0, "max": 1, "label": "No GC"},
           "useScheduling": {"min": 0, "max": 1, "label": "Scheduling"},
           "background":        {"min": 0, "max": 1, "label": "Background"},
         }
       }
   }

   // Create 15 rows in complete
   property int rowCount: 15
   // current store dependent on the level progress - to avoid textupdate each frame
   property int currentScore: 0

   property int bonusScoreForCoin: 50
   // this gets displayed above the player if he picks up any collectible
   // amount of double point time the player gets when picking up the DoublePoints collectible
   property int doublePointsDuration: 10
   // velocity multiplier for hen movement
   property real rightValue: 250
   property real leftValue: -rightValue
   // collider properties for balancing with the ItemEditor
   property real henLinearDamping : 5.0
   property real henFriction : 0.2
   // when the parachute is used, the gravity scale of the player is reduced, resulting in slower falling
   property real parachuteGravityScale : 0.10
   // if the accelerometer reading is below this value, the hen doesn't move, this helps the player to stay on a roost
   property real accelerometerOffset : 0.25
   // the reading of the accelerometer gets multiplied by this value to recieve the linear velocity of the hen
   property real accelerometerMultiplier : 0.5
   // is needed internally to avoid creating too many windows close to each other

   property int lastWindowY: 0

   property int difficulty : 0
   onDifficultyChanged: {
     if(difficulty != 0) {
       newLevelMessage.newLevelReached()
     }
   }

   property bool balancingMode : itemEditor.visible

   // the background images are moved up by this offset so on widescreen devices the full background is visible
   property real __yOffsetForWindow: scene.fullWindowAnchorItem.y

   // gets emitted when a BorderRegion.onPlayerCollision() is received
   signal gameLost

   property int diff0MaxSpeed: 110
   property real diff0PlatformRot: 0
   property real diff0PlatformCreation: 0.09
   property real diff0Gravity: 60

   property int diff1MaxSpeed: 125
   property real diff1PlatformRot: 0.2
   property real diff1PlatformCreation: 0.09
   property int diff1Points: 1000
   property real diff1Gravity: 60

   property int diff2MaxSpeed: 140
   property real diff2PlatformRot: 0.3
   property real diff2PlatformCreation: 0.09
   property int diff2Points: 2000
   property real diff2Gravity: 60

   property int diff3MaxSpeed: 160
   property real diff3PlatformRot: 0.45
   property real diff3PlatformCreation: 0.08
   property int diff3Points: 3000
   property real diff3Gravity: 60

   property int diff4MaxSpeed: 180
   property real diff4PlatformRot: 0.6
   property real diff4PlatformCreation: 0.06
   property int diff4Points: 4000
   property real diff4Gravity: 65

   property int diff5MaxSpeed: 200
   property real diff5PlatformRot: 1
   property real diff5PlatformCreation: 0.05
   property int diff5Points: 5000
   property real diff5Gravity: 70

   property int diff6MaxSpeed: 230
   property real diff6PlatformRot: 1
   property real diff6PlatformCreation: 0.04
   property int diff6Points: 6000
   property real diff6Gravity: 75

   property real scoreFromItemEditor: 0

   EditableComponent {
     editableType: "Level"
     properties: {
       "Collectibles": {
         "coinCreationPropability": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Coin"},
         "badCoinCreationPropability": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Bad Coin"},
         "trippleCoinCreationPropability": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Tripple Coin"},
         "parachuteCreationPropability": {"min": 0, "max": 0.5, "stepsize": 0.001, "label": "Parachute"},
         "doublePointsCreationPropability": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Double Points"}
       },
       "Terrain": {
         "wheelCreationProbability": {"min": 0, "max": 0.5, "stepsize": 0.001, "label": "Wheel creation"},
         "windowCreationProbability": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Window creation"},
         "minimumWindowHeightDifference": {"min": 0, "max": 500, "stepsize": 1, "label": "Min window height diff"},
         "minimumWheelHeightDifference": {"min": 0, "max": 500, "stepsize": 1, "label": "Min wheel height diff"}
       },
       "Speed": {
         "levelMovementSpeedMinimum": {"min": 0, "max": 100, "stepsize": 1, "label": "Minimum level speed"},
         "levelMovementDurationTillMaximum": {"min": 1, "max": 60, "stepsize": 1, "label": "Level acceleration duration"}
       },
       "Difficulty 0": {
         "diff0MaxSpeed": {"min": 0, "max": 500, "stepsize": 1, "label": "Maximum level speed"},
         "diff0PlatformRot": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform rotation"},
         "diff0PlatformCreation": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform creation"},
         "diff0Gravity": {"min": 30, "max": 150, "stepsize": 1, "label": "Gravity"}
       },
       "Difficulty 1": {
         "diff1MaxSpeed": {"min": 0, "max": 500, "stepsize": 1, "label": "Maximum level speed"},
         "diff1PlatformRot": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform rotation"},
         "diff1PlatformCreation": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform creation"},
         "diff1Points": {"min": 0, "max": 300000, "stepsize": 100, "label": "Points needed"},
         "diff1Gravity": {"min": 30, "max": 150, "stepsize": 1, "label": "Gravity"}
       },
       "Difficulty 2": {
         "diff2MaxSpeed": {"min": 0, "max": 500, "stepsize": 1, "label": "Maximum level speed"},
         "diff2PlatformRot": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform rotation"},
         "diff2PlatformCreation": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform creation"},
         "diff2Points": {"min": 0, "max": 300000, "stepsize": 100, "label": "Points needed"},
         "diff2Gravity": {"min": 30, "max": 150, "stepsize": 1, "label": "Gravity"}
       },
       "Difficulty 3": {
         "diff3MaxSpeed": {"min": 0, "max": 500, "stepsize": 1, "label": "Maximum level speed"},
         "diff3PlatformRot": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform rotation"},
         "diff3PlatformCreation": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform creation"},
         "diff3Points": {"min": 0, "max": 300000, "stepsize": 100, "label": "Points needed"}
       },
       "Difficulty 4": {
         "diff4MaxSpeed": {"min": 0, "max": 500, "stepsize": 1, "label": "Maximum level speed"},
         "diff4PlatformRot": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform rotation"},
         "diff4PlatformCreation": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform creation"},
         "diff4Points": {"min": 0, "max": 300000, "stepsize": 100, "label": "Points needed"},
         "diff4Gravity": {"min": 30, "max": 150, "stepsize": 1, "label": "Gravity"}
       },
       "Difficulty 5": {
         "diff5MaxSpeed": {"min": 0, "max": 500, "stepsize": 1, "label": "Maximum level speed"},
         "diff5PlatformRot": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform rotation"},
         "diff5PlatformCreation": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform creation"},
         "diff5Points": {"min": 0, "max": 300000, "stepsize": 100, "label": "Points needed"},
         "diff5Gravity": {"min": 30, "max": 150, "stepsize": 1, "label": "Gravity"}
       },
       "Difficulty 6": {
         "diff6MaxSpeed": {"min": 0, "max": 500, "stepsize": 1, "label": "Maximum level speed"},
         "diff6PlatformRot": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform rotation"},
         "diff6PlatformCreation": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Platform creation"},
         "diff6Points": {"min": 0, "max": 300000, "stepsize": 100, "label": "Points needed"},
         "diff6Gravity": {"min": 30, "max": 150, "stepsize": 1, "label": "Gravity"}
       }
     }
   }

   // this values can be changed at runtime with the ItemEditor
   EditableComponent {
     editableType: "Player"
     properties: {
       "General": {
         "bonusScoreForCoin": {"min": 100, "max": 1000, "stepsize": 1, "label": "Coin Score"},
         "doublePointsDuration": {"min": 1, "max": 30, "stepsize": 1, "label": "Double Points duration"},
         "rightValue": {"min": 50, "max": 500, "stepsize": 5, "label": "Velocity multiplier"},
         "henLinearDamping": {"min": 0.0, "max": 25.0, "stepsize": 0.1, "label": "Linear damping"},
         "henFriction": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Friction"},
         "parachuteGravityScale": {"min": 0, "max": 1, "stepsize": 0.01, "label": "Parachute gravity scale"},
         "scoreFromItemEditor": {"min": 0, "max": 300000, "stepsize": 1000, "label": "Add Test Score"}
       },
       "Accelerometer Settings": {
         "accelerometerOffset": {"min": 0, "max": 0.3, "stepsize": 0.001, "label": "Offset"},
         "accelerometerMultiplier": {"min": 0, "max": 1, "stepsize": 0.05, "label": "Multiplier"}
       }
     }
   }

   Component.onCompleted: {

     // this creates some roosts, coins and windows beforehand, so they don't need to be created at runtime
     preCreateEntityPool();

     // startGame() is called in ChickenOutbreakScene.enterScene()
   }

   function preCreateEntityPool() {
     entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/Roost.qml"), 30);
     entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/Wheel.qml"), 5);
     entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/HenhouseWindow.qml"), 5);
     entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/Coin.qml"), 10);
     entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/TrippleCoin.qml"), 5);
     entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/BadCoin.qml"), 5);
     entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/Parachute.qml"), 1);
     entityManager.createPooledEntitiesFromUrl(Qt.resolvedUrl("entities/DoublePoints.qml"), 1);
   }

   function stopGame() {
     //resumeGame()
     levelMovementAnimation.stop();

     // this function automatically pools all entities which have poolingEnabled set to true
     // and it ignores the entities that have preventFromRemovalFromEntityManager set to true
     entityManager.removeAllEntities();
     //entityManager.removeAllPooledEntities()
     state = "stopped"
   }

   // initialize level data - this function can be called multiple times, so every time a new game gets started
   // it is called from ChickenOutbreakScene.enterScene()
   function startGame() {
     console.debug("Level: startGame()");

     // ensure game over scenen is invisible
     levelBackground.resetBackgrounds()

     // it is important that lastY is set first, so the dy in onYChanged will be 0 and no new row is created
     currentRow = 0;
     lastY = 0;

     level.y = 0;
     player.start()
     player.x = scene.width/2;
     player.y = 2*gridSize;
     player.score = 0;
     player.bonusScore = 0;
     player.beams = 0;
     player.collectedBadGrains = 0
     player.collectedGrains = 0
     player.parachutes = 0;
     difficulty = 0
     player.bonusTextScore = 0;
     player.parachute = false;
     player.blockCollisions = 0;
     player.doublePointsTime = 0;
     player.collider.body.linearVelocity.x = 0

     // this is required, otherwise after the game the player would still navigate left or right if no mouse release happened before, or when coming from the main scene it might still have the old direction
     player.controller.xAxis = 0;

     // if it was active before.
     player.teleportGlowParticle.stop()

     // this must be set BEFORE createRandomRowForRowNumber() is called!
     lastWindowY = 0;
     lastWheelY = 0;

     for(var i=5; i<rowCount; i++) {
       LevelLogic.createRandomRowForRowNumber(i);
     }
     levelMovementAnimation.velocity = -levelMovementSpeedMinimum;
     levelMovementAnimation.start();
     state = "running"
   }

   Image {
     id: overlay
     source: Qt.resolvedUrl("../assets/blackbg.png")
     width: scene.gameWindowAnchorItem.width
     height: scene.gameWindowAnchorItem.height*1.5
     opacity: 0
     x: scene.gameWindowAnchorItem.x
     y: scene.gameWindowAnchorItem.y
   }

   // start in the center of the scene, and a little bit below the top
   // the player will fall to the playerInitialBlock below at start
   Player {
     id: player

     x: scene.width/2
     y: gridSize/2

     // this guarantees the player is in front of the henhouseWindows
     z: 5
     onTotalScoreChanged: {
       if(player.totalScore<diff1Points) {
         return
       } else if(player.totalScore>diff6Points && difficulty === 5) {
         difficulty = 6
       } else if(player.totalScore>diff5Points && difficulty === 4) {
         difficulty = 5
       } else if(player.totalScore>diff4Points && difficulty === 3) {
         difficulty = 4
       } else if(player.totalScore>diff3Points && difficulty === 2) {
         difficulty = 3
       } else if(player.totalScore>diff2Points && difficulty === 1) {
         difficulty = 2
       } else if(player.totalScore>diff1Points && difficulty === 0) {
         difficulty = 1
       }
     }

     onDeathAnimationFinished: {
       stopGame()
       window.state = "gameOver"
     }
   }

   // this guarantees the player doesn't fall through in the beginning
   Roost {
     id: lowerBlock
     // this id is used in BorderRegion to prevent this block from being removed!
     entityId: "playerInitialBlock"
     x: scene.width/2
     y: 3.5*gridSize // just a random position a little bit below the player

     // this keeps the entity from removeAllEntities()
     preventFromRemovalFromEntityManager: true
   }

     // the 2 BorderRegion entities (one on top and one on bottom of the screen) are not visible because they are offscreen
     // if the topRegion collides with a roost, a coin or a window, they get removed and used for pooling
     // if the topRegion collides with the player, that means the game is lost as the player got out of the scene on the top
     // the bottomRegion is only for detecting collision with the player, so if he falls through and cant stand on a roost, the game is lost
     BorderRegion {
       width: scene.gameWindowAnchorItem.width*2 // make bigger than the window, because the roost can stand out of the scene on the right side when the gridSize is not a multiple of the scene.width (which it currently is: 320/48=6.6) and thus if the player would stand on the right side no collision would be detected!
       anchors.horizontalCenter: parent.horizontalCenter
       variationType: "topRegion"

       // this height is not important, could also be set to 1 or anything else
       height: 20

       property real defaultOffsety: __yOffsetForWindow + height + 120 // use 120 so bigger items like window and wheels get destroyed when not visible anymore.
       // this is important: the topRegion moves with the level, because the positions of the physics bodies do not move with the level position!
       // so the topRegion is always on the top of the scene + the height of the highest item (the window)
       // add 60 pixels (which is the height of the window), so it doesn't get removed while it is still visible!
       y: - defaultOffsety-level.y

       onPlayerCollision: {
         console.debug("PLAYER COLLIDED WITH topRegion, level.y:", level.y, ", player.y:", player.y)
         // emit the gameLost signal, which is handled in ChickenOutbreakScene
         if(!noDeath)
           gameLost();
         else
           player.y = player.y+scene.height/2
       }
     }
     BorderRegion {
       // make it so big that the player will still loose if he navigates to the right or left of the screen and then falls down
       width: scene.gameWindowAnchorItem.width*2
       anchors.horizontalCenter: parent.horizontalCenter

       height: 20
       // the BorderRegion is always out of the visual scene, so it is never visible
       // it moves with the level like the topRegion
       y: scene.gameWindowAnchorItem.height-level.y

       variationType: "bottomRegion"

       onPlayerCollision: {
         console.debug("PLAYER COLLIDED WITH BorderRegion, level.y:", level.y, ", player.y:", player.y)
         // emit the gameLost signal, which is handled in ChickenOutbreakScene
         if(!noDeath)
           gameLost();
         else
           player.y = player.y-scene.height
       }
     }

     BorderRegion {
       x: scene.gameWindowAnchorItem.x-80-width
       height: scene.gameWindowAnchorItem.height*2
       width: 20
       // this is important: the topRegion moves with the level, because the positions of the physics bodies do not move with the level position!
       // so the topRegion is always on the top of the scene + the height of the highest item (the window)
       y: -level.y-defaultOffsety

       property real defaultOffsety: height/4

       variationType: "bottomRegion"

       onPlayerCollision: {
         gameLost();
       }
     }
     BorderRegion {
       x: scene.gameWindowAnchorItem.x+scene.gameWindowAnchorItem.width+80+width
       height: scene.gameWindowAnchorItem.height*2
       width: 20
       // this is important: the topRegion moves with the level, because the positions of the physics bodies do not move with the level position!
       // so the topRegion is always on the top of the scene + the height of the highest item (the window)
       y: -level.y-defaultOffsety

       property real defaultOffsety: height/4
       variationType: "bottomRegion"

       onPlayerCollision: {
         gameLost();
       }
     }

   MovementAnimation {
     id: levelMovementAnimation
     property: "y"
     // this is the movement in px per second, start with very slow movement, 10 px per second
     velocity: 0-levelMovementSpeedMinimum
     // running is set to false by default - start() is called in startGame()
     // increase the velocity by this amount of pixels per second, so it lasts minVelocity/acceleration seconds until the maximum is reached!
     acceleration:0 -(levelMovementSpeedMaximum-levelMovementSpeedMinimum) / levelMovementDurationTillMaximum
     target: level

     // limit the maximum v to 100 px per second - it must not be faster than the gravity! this is the absolute maximum, so the chicken falls almost as fast as the background moves by! so rather set it to -90, or increase the gravity
     minVelocity: 0-levelMovementSpeedMaximum

     onVelocityChanged: {
       levelBackground.movementVelocity = Qt.point(0, levelMovementAnimation.velocity)
     }

     //onRunningChanged: {
     //  levelBackground.running = levelMovementAnimation.running
     //}
   }

   // when the level gets moved down, check if the difference between last level y position and the current one is greater than gridSize - if so, create a new row
   onYChanged: {
     // y gets more and more negative, so e.g. -40 - (-25) = -15
     var dy = y - lastY;
     if(-dy > gridSize) {

       var amountNewRows = (-dy/gridSize).toFixed();
       console.debug(amountNewRows, "new rows are getting created...")

       // if y changes a lot within the last frame, multiple rows might get created
       // this doesn't happen with fixed time delta, but it could happen with varying time delta where more than 1 row might need to be created because of such a big y delta
       for(var i=0; i<amountNewRows; i++) {
         currentRow++;
         // this guarantees it is created outside of the visual screen
         LevelLogic.createRandomRowForRowNumber(currentRow+rowCount);
         // it's important to decrease lastY like that, not setting it to y!
         lastY -= gridSize
       }
     }

     // bitmap font for text updating is much faster -> this feature is not supported by Felgo yet, contact us if you would need it at support@felgo.com
     currentScore = -(level.y/40).toFixed()
     if(currentScore > player.score+4 && !noFont) {
         player.score = currentScore
     }

     if(!noManualGC)
         gc()
   }

   function pauseGame() {
     if(state !== "running") return
     console.debug("pauseGame()")
     levelMovementAnimation.stop()
     player.stop()
     state = "paused"
   }
   function resumeGame() {
     if(state !== "paused" && state !== "teleporting") return
     console.debug("resumeGame()")
     levelMovementAnimation.start()
     player.start()
     state = "running"
   }

   function toggleTeleport() {
     console.debug("toggleTeleport with state " + state)
     if(state === "running") {
       player.beams++
       pauseGame()
       state = "teleporting"
     } else if(state === "teleporting") {
       resumeGame()
     }
   }

   function saveIt() {
     pauseGame()
     state = "teleporting"
     player.saveIt()
     player.teleportGlowParticle.start()
   }

   onStateChanged: console.debug("state changed to " + state)
   states: [
     State {
       name: "running"
       PropertyChanges { target: overlay; opacity: 0; y: scene.gameWindowAnchorItem.y-level.y  -__yOffsetForWindow}
     },
     State {
       name: "stopped"
       PropertyChanges { target: overlay; opacity: 0; y: scene.gameWindowAnchorItem.y-level.y  -__yOffsetForWindow}
     },
     State {
       name: "paused"
       PropertyChanges { target: overlay; opacity: 1; y: scene.gameWindowAnchorItem.y-level.y  -__yOffsetForWindow}
     },
     State {
       name: "teleporting"
       PropertyChanges { target: overlay; opacity: 1; y: scene.gameWindowAnchorItem.y-level.y  -__yOffsetForWindow}
     }
   ]

   transitions: [
     Transition {
       NumberAnimation {property: "opacity"; easing.type: Easing.InOutQuad}
Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded