Find the Best Demos and Examples

Check out this quick tour to find the best demos and examples for you, and to see how the Felgo SDK can help you to develop your next app or game!

Stack With Friends Demo

 import QtQuick 2.0
 import Felgo 3.0
 import"../common"
 import "dialogs"

 SceneBase {
   id: levelScene

   signal backClicked
   signal levelSelected(variant levelData, bool isAuthorLevel, bool isUserLevel, bool isDownloaded, bool isPublished, bool isLoggedInPlayer)
   signal newLevelClicked
   signal clearSelectedItems
   // is called when the fb connection dialog was shown due to no friends
   signal showProfileView
   signal showHighscoreForLevel(string leaderboard)
   signal showInfoClicked(variant levelData)
   signal unpublishLevelClicked(variant levelData)
   // is emitted from LevelItem if the share level button is clicked
   signal shareLevelClicked(variant levelData)
   signal rateLevelClicked(variant levelData)
   signal downloadLevelClicked(variant levelData)

   // can have the following states: "myLevels", "myDownloadedLevels", "communityLevels", "friendLevels"
   state: "myLevels"

   // either is default "", or "noFriendLevelsAndNotConnectedFb", "noLevelPublished"
   property string dialogState
   property variant unpublishLevelData
   Connections {
     target: nativeUtils
     onMessageBoxFinished: {

       if(accepted) {
         if(dialogState === "noFriendLevelsAndNotConnectedFb") {
           // open profile view; or directly call fb-connection here?
           showProfileView()

         } else if(dialogState === "noLevelPublished") {
           // go to the my levels tab to create a new level
           levelScene.state = "myLevels"
         } else if(dialogState === "unpublishConfirmation") {
           levelEditor.unpublishLevel(unpublishLevelData)
           // no need to reset it here - is newly set the next time unpublishLevelClicked() is called anyway
           //unpublishLevelData = undefined
         }
       }
       // reset the dialogState, no matter if accepted or not
       dialogState = ""
     }

   }

   MultiResolutionImage {
     source: "../../assets/img/menubg.png"
     anchors.centerIn: parent
   }

   MultiResolutionImage {
     id: header
     source: "../../assets/img/levelstore-top.png"
     anchors.top: parent.gameWindowAnchorItem.top
     anchors.horizontalCenter: parent.horizontalCenter
     z: 1

     Item {
       width: 39
       height: 39
       y: -1
       x: 5
       MultiResolutionImage {
         source: "../../assets/img/back-button.png"
         anchors.centerIn: parent
       }
       MouseArea {
         anchors.fill: parent
         onClicked: levelScene.backClicked()
       }
     }

     Row {
       id: headerRow

       z: 1
       spacing: 20
       x: 64

       MenuButton {
         text: "My Levels"
         active: levelScene.state === "myLevels" || levelScene.state === "myDownloadedLevels"
         onClicked: {
           flurry.logEvent("LevelSelection.MyLevels")
           levelScene.state = levelScene.previousMyLevelState
         }
       }

       MenuButton {
         text: "Friend Levels"
         active: levelScene.state === "friendLevels"
         onClicked: {
           flurry.logEvent("LevelSelection.FriendLevels")
           levelScene.state = "friendLevels"
         }
       }

       MenuButton {
         text: "Community"
         active: levelScene.state === "communityLevels"
         onClicked: {
           flurry.logEvent("LevelSelection.CommunityLevels")
           levelScene.state = "communityLevels"
         }
       }

       MenuButton {
         text: "Credits: " + levelStore.playerCredits
         onClicked: {
           buyCreditDialog.opacity = 1
         }
         onPressAndHold: {

           // don't add this functionality in publish builds, just during testing
           if(system.publishBuild)
             return

           // just for testing during development to reset the playerCredits
           levelStore.resetCurrency()
         }
       }
     }// headerRow
   }// header

   MultiResolutionImage {
     id: more
     source: "../../assets/img/levelstore-bot.png"
     anchors.bottom: parent.gameWindowAnchorItem.bottom
     anchors.horizontalCenter: parent.horizontalCenter
     z: 1

     MultiResolutionImage {
       source: "../../assets/img/nextprev.png"
       visible: ((levelScene.state === "friendLevels" && levelEditor.userOrFriendsLevelsPageMetaData.page > 1) ||
                (levelScene.state === "communityLevels" && levelEditor.communityLevelsPageMetaData.page > 1)) &&
                // avoid to show while the level items are created
                !currentLevelSelection.isLoading
       x: 7
       MouseArea {
         anchors.fill: parent
         onClicked: currentLevelSelection.prevPage()
       }
     }

     MultiResolutionImage {
       source: "../../assets/img/nextprev.png"
       visible: (levelScene.state === "friendLevels" || levelScene.state === "communityLevels") &&
                levelEditor.userGeneratedLevelsPageMetaData !== undefined && levelEditor.userGeneratedLevelsPageMetaData.page < levelEditor.userGeneratedLevelsPageMetaData.pageCount &&
                // avoid to show while the level items are created
                !currentLevelSelection.isLoading
       mirror: true
       anchors.right: parent.right
       anchors.rightMargin: 13

       MouseArea {
         anchors.fill: parent
         onClicked: currentLevelSelection.nextPage()
       }
     }

     Row {
       id: moreSubRow
       spacing: 25
       y: 1
       anchors.horizontalCenter: parent.horizontalCenter
       visible: levelScene.state === "friendLevels" || levelScene.state === "communityLevels"

       MenuButton {
         text: "All Time"
         active: levelScene.timeLimit === 0
         onClicked: {
           flurry.logEvent("LevelSelection.AllTime")
           levelScene.timeLimit = 0
         }
       }
       MenuButton {
         text: "This Week"
         active: levelScene.timeLimit === 24*7
         onClicked: {
           flurry.logEvent("LevelSelection.ThisWeek")
           levelScene.timeLimit = 24*7
         }
       }
       MenuButton {
         text: "Today"
         active: levelScene.timeLimit === 24
         onClicked: {
           flurry.logEvent("LevelSelection.Today")
           levelScene.timeLimit = 24
         }
       }
       MenuButton {
         text: levelScene.orderString()
         onClicked: {
           orderLevelsDialog.opacity = 1
         }
       }
     } // moreSubRow

     Row {
       id: moreSubRowMyLevels
       spacing: 25
       y: 1
       anchors.horizontalCenter: parent.horizontalCenter
       visible: levelScene.state === "myLevels" || levelScene.state === "myDownloadedLevels"

       Item {
         width: 39
         height: 39
         y: -1
         visible: levelScene.state === "myLevels"
         MultiResolutionImage {
           source: "../../assets/img/new-level-button.png"
           anchors.centerIn: parent
         }
         MouseArea {
           anchors.fill: parent
           onClicked: newLevelClicked()
         }
       }

       MenuButton {
         text: "Created Levels"
         active: levelScene.state === "myLevels"
         onClicked: {
           levelScene.state = "myLevels"
           previousMyLevelState = levelScene.state
         }
       }
       MenuButton {
         text: "Downloaded Levels"
         active: levelScene.state === "myDownloadedLevels"
         onClicked: {
           levelScene.state = "myDownloadedLevels"
           previousMyLevelState = levelScene.state
         }
         onPressAndHold: {
           // don't add this functionality in publish builds, just during testing
           if(system.publishBuild)
             return

           // this is just during testing, to test the behavior of no downloaded(=bought) levels
           console.debug("clearing all bought levels...")
           levelStore.clearAllBoughtLevels()
         }
       }
     } // moreSubRowMyLevels
   } // more

   // is set in onStateChanged
   property variant currentLevelSelection

   LevelSelection {
     id: myLevelSelection

     visible: levelScene.state === "myLevels"
     levelMetaDataArray: levelEditor.authorGeneratedLevels
   }

   LevelSelection {
     id: downloadedLevelSelection

     visible: levelScene.state === "myDownloadedLevels"
     levelMetaDataArray: levelEditor.downloadedLevels
   }

   LevelSelection {
     id: userOrFriendLevelSelection

     visible: levelScene.state === "friendLevels"
     levelMetaDataArray: levelEditor.userOrFriendsLevels
     pageCount: levelEditor.userOrFriendsLevelsPageMetaData.pageCount

     onLevelMetaDataArrayChanged: {

       // to avoid calling this function at app start (the default state is myLevels)
       if(levelScene.state !== "friendLevels") {
         return
       }

       //
       var friendLevels = new Array
       var myLevels = new Array
       for(var i=0; levelMetaDataArray && i<levelMetaDataArray.length; i++) {
         var level = levelMetaDataArray[i]
         if(level.user.id === gameNetwork.user.userId) {
           myLevels.push(level)
         } else {
           friendLevels.push(level)
         }
       }

       console.debug("LevelScene: onLevelMetaDataArrayChanged: myLevels:", JSON.stringify(myLevels), ", friendLevels:", JSON.stringify(friendLevels))

       if(myLevels.length === 0) {
         dialogState = "noLevelPublished"

         // show this every time, so the user publishes at least one level!
         nativeUtils.displayMessageBox("You do not have published a level yet", "Would you like to create and publish and create a level now?\n\nBy publishing a level you get credits and can then download new community levels.", 2)
         return
       }

       // if the user connected with fb already, no need to inform him about the friend levels
       // if on not fb-supported platforms, also skip the dialog below because he cannot connect!
       if(gameNetwork.facebookConnectionSuccessful || system.desktopPlatform || system.isPlatform(System.BlackBerry) )
         return

       if(friendLevels.length === 0) {
         dialogState = "noFriendLevelsAndNotConnectedFb"

         nativeUtils.displayMessageBox("Connect with Facebook to see Friend Levels", "Would you like to connect with Facebook to see the levels of your friends?\n\n", 2)
       }

     }//onLevelMetaDataArrayChanged

   }

   LevelSelection {
     id: communityLevelSelection

     visible: levelScene.state === "communityLevels"
     levelMetaDataArray: levelEditor.communityLevels
     pageCount: levelEditor.communityLevelsPageMetaData.pageCount
   }

   Connections {
     target: levelStore
     onInsufficientFundsError: {
       flurry.logEvent("Level.InsufficientFunds")
       buyCreditDialog.opacity = 1
     }
     onLevelBoughtSuccessfully: {
       flurry.logEvent("Level.BoughtSucc")
       console.debug("level bought:", JSON.stringify(levelData))
     }
     onLevelDownloadedSuccessfully: {
       flurry.logEvent("Level.Downloaded")
       console.debug("level downloaded:", JSON.stringify(levelData))
     }
   }

   RatingDialog {
     id: ratingDialog
     z: 100
     opacity: 0

     property int levelId

     onLevelRated: {
       flurry.logEvent("Level.Rated",ratingDialog.levelId,rateValue)
       // levelId is required
       levelEditor.rateLevel( {levelId: ratingDialog.levelId, quality: rateValue })
       // to reload the server levels, maybe call another load here; but we don't know what was the last request (friend or all levels, which ordering, filtering etc.)
       // refresh level list after rating so it is visible
       reloadLevels()
     }
   }

   InfoDialog {
     id: infoDialog
     opacity: 0
     z: 100
   }

   BuyCreditDialog {
     id: buyCreditDialog
     opacity: 0
     z: 100
   }

   OrderLevelsDialog {
     id: orderLevelsDialog
     opacity: 0
     z: 100
     onLevelOrderSelected: {
       levelScene.order = levelOrder
     }
   }

   onLevelSelected: {
     if((isUserLevel && isDownloaded) || (isAuthorLevel && isPublished) || levelScene.state === "myDownloadedLevels" || (isUserLevel && isLoggedInPlayer)) {
       levelEditor.loadSingleLevel(levelData)
       gameScene.goToPlayMode()
       gameScene.cameFromScene = levelScene.state
       mainItem.state = "game"
       flurry.logEvent("Level.GoToPlayMode")
     } else if(isAuthorLevel && !isPublished) {
       levelEditor.loadSingleLevel(levelData)
       gameScene.goToLevelEditingMode()
       gameScene.cameFromScene = levelScene.state
       mainItem.state = "game"
       flurry.logEvent("Level.GoToEditMode")
     }
   }

   onShareLevelClicked: {
     console.debug("TODO: open fb wall post")
     // open the native fb wall posting here, if there is a valid fbItem
   }

   onRateLevelClicked: {
     // show a 5 star rating, and then rate with its value
     ratingDialog.opacity = 1
     ratingDialog.levelId = levelData.levelId
     if(levelData && levelData["rating"])
       ratingDialog.currentRating = levelData["rating"]["quality"]
     else
       ratingDialog.currentRating = 0
   }

   onDownloadLevelClicked: {
     // it's up to the developer if he wants to support the LevelStore - if so, then a direct download is not possible but only a buy
     // on iOS & Android, do not open the store yet, as too tedious to set up during development
     // this should be the other way around in the end, or use buyLevel for both platforms, as basic Store functionality is now also supported on desktop
     // NOTE: the supported property does also return FALSE on iOS & Android, thus a bug in Store plugin!
     //if(levelStore.supported) {

     // for testing the purchase process with the build server, by default the "stage" property is set to "test"
     // this means the build server signs the app with the Felgo certificate to allow quick testing & deployment
     // however, in-app-purchases and the Store plugin require a publish build because in-app purchases are not working with the Felgo certificate but require YOUR OWN certificate
     // thus for final testing including in-app purchases on iOS & Android, do change to publish build by changing the config.json "stage" property to "publish"
     // and to simulate the correct purchase process on build server for test builds, we directly download the level without an actual purchase on iOS & Android
     if( (system.isPlatform(System.IOS) || system.isPlatform(System.Android)) && !system.publishBuild ) {
       levelEditor.downloadLevel(levelData)
     } else {
       levelStore.buyLevel(levelData)
     }
   }

   onShowInfoClicked: {
     infoDialog.levelData = levelData
     infoDialog.opacity = 1
   }

   onUnpublishLevelClicked: {
     dialogState = "unpublishConfirmation"
     // must be saved so we know the levelId to unpublish after confirmation
     unpublishLevelData = levelData
     nativeUtils.displayMessageBox("Unpublish Confirmation", "Do you really want to unpublish your level? This removes all ratings and download stats for this level.", 2)
   }

   onStateChanged: {
     if(state === "myLevels") {
       levelEditor.loadAllLevelsFromStorageLocation(levelEditor.authorGeneratedLevelsLocation)
       currentLevelSelection = myLevelSelection
     } else if(state === "myDownloadedLevels") {
       levelEditor.loadAllLevelsFromStorageLocation(levelEditor.downloadedLevelsLocation)
       currentLevelSelection = downloadedLevelSelection
     } else if (state === "friendLevels") {
       // the levelSelection must be set BEFORE reloadLevels() is called, otherwise the old page information would be used!
       currentLevelSelection = userOrFriendLevelSelection
       // this takes into account the current ordering and timeLimit
       levelScene.reloadLevels()
     } else if (state === "communityLevels") {
       // the levelSelection must be set BEFORE reloadLevels() is called, otherwise the old page information would be used!
       currentLevelSelection = communityLevelSelection
       // this takes into account the current ordering and timeLimit
       levelScene.reloadLevels()
     } else {
       console.debug("ERROR: LevelScene: undefined state!", state)
     }
   }

   // is either "myLevels" or "myDownloadedLevels", and is needed to go back to these levels when "My Levels" is selected
   property string previousMyLevelState: "myLevels"

   //order - Order results by fields, newest/highst quality first Has to be one of ["created_at", "average_quality", "average_difficulty", "times_favored", "times_played", "times_downloaded"]. Default: created_at.
   property string order: "created_at"
   onOrderChanged: {
     currentLevelSelection.page = 1
     reloadLevels()
   }
   function orderString() {
     if(order === "created_at")
       return "Newest"
     else if(order === "average_quality")
       return "Highest Rated"
     else if(order === "times_downloaded")
       return "Most Downloaded"

     return "XXX"
   }

   //timeLimit - Only return levels that have been created within time_limit hours (integer).
   property int timeLimit
   onTimeLimitChanged: {
     currentLevelSelection.page = 1
     reloadLevels()
   }

   function reloadLevels() {
     var params = {}
     if(timeLimit > 0) {
       params.timeLimit = timeLimit
     }
     params.order = order
     params.perPage = currentLevelSelection.pageSize
     params.page = currentLevelSelection.page

     if(levelScene.state === "communityLevels") {
       levelEditor.loadCommunityLevels(params)
     } else if(levelScene.state === "friendLevels") {
       // if also the own published levels should be shown, use params.filters = ["created_by_friends", "created_by_user"] - but this information is available in the "My Levels" list anyway
       // it is better to show the own levels as well, so the player can compare with his friends
       params.filters = ["created_by_friends", "created_by_user"]
       levelEditor.loadUserOrFriendsLevels(params)
     }
   }

   function levelArrayFromState() {
     if(state === "myLevels")
       return levelEditor.authorGeneratedLevels
     else if(state === "myDownloadedLevels")
       return levelEditor.downloadedLevels
     else if(state === "friendLevels")
       return levelEditor.userOrFriendsLevels
     else if(state === "communityLevels")
       return levelEditor.communityLevels

     console.debug("ERROR: LevelScene: undefined state!", state)

     return undefined