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

LevelEditor

Allows to create, share & monetize user-generated levels with an in-game level editor. More...

Import Statement: import Felgo 3.0
Inherits:

Item

Properties

Signals

Methods

Detailed Description

The LevelEditor is one of the most valuable and time-saving components in Felgo. It can be used during development to create and modify levels for your game, which you can then bundle in your final publishing build. Additionally, you can also integrate the in-game level editor to your published game and let your gamers create new levels. The gamers can then share their levels with the whole game community and thus drive new installs to your game and continuously provide new content so your game stays interesting and on top of the charts.

So in short it allows you to do the following:

  • Cut development time as level creation, balancing and testing works while your game is running.
  • Customize the look of the level editor to perfectly match your game style, or use the default Felgo skin for quick results.
  • Let your players create their own levels and build a community around your game - in return you get user-generated content which keeps your game interesting and something new to explore for your players.
  • Monetize your user-created levels with a LevelStore and award your best level creators to give them an incentive.

Further Level Editor Resources

This section is updated with further resources about level editor related topics.

Screenshots & Workflow

Squaby - Level Editor Example

The following image shows a screenshot of the level editor in the Squaby Demo: You can drag and drop entities into the level by using the BuildEntityButton and EntityBaseDraggable components.

By pressing on the "Menu" button and selecting the "Save Level" button in the level editing menu, you can then store the level with a custom LevelData::levelName.

In the LevelSelectionList, you can then choose from a customizable list of levels.

Stack With Friends - Level Editor Example

This image shows how the level editor is integrated into the Stack With Friends Demo: You can drag and drop entities into the level, remove them and rotate them in the game.

The levels are then listed in a custom level selection, ordered in a grid based on the level rating, the number of downloads or when the levels were published.

.

Note: These are just examples how the in-game level editor can look like. However, you can fully customize it to your game so it best matches your game's style.

Level Sharing & User-Generated Levels

By using the LevelEditor component, you already have an in-game level editor in place to create levels while the game is running. You can now take it one step further: Give your players the power to create their own levels! Players can then use all of the level editing possibilities like you did while developing the game and so have a powerful tool in their hands.

You will be amazed how creative the gamers who love your game are, and the best thing is you get new content from your community without any effort! Thus your game stays longer on top of the charts as there is always something new to explore for your players.

As gamers love to brag about the new cool levels they made, they are going to tell their friends to play the level and help you with promoting your game, without spending huge budgets on marketing! Instead you get really passionate players and content for free to stay interesting.

Benefits of User-Generated Levels

So to summarize this quickly, here are the benefits for players:

  • Players are more engaged because they can create their own levels and tell their friends about it. You can reward them for great content to further motivate them to build awesome levels.
  • Players get endless levels, made by the game community.

And these are your benefits:

  • Players return more often to your game because there is endless content and always something new to explore.
  • Your game downloads will increase because of word-of-mouth marketing of user-generated levels by your players.
  • No need to create constant level updates after you published your game to keep it interesting - the community does this for you!
  • Earn money with the user-generated levels by adding a LevelStore!

There is a huge potential of user-generated content in mobile games currently unexplored. For a step-by-step tutorial how to add the LevelStore and user-generated content to your game see Felgo Crash Course Lesson 8 - How to benefit from user-generated content in your game with Felgo Level Store.

The way you visualize your LevelStore is up to your game, here is an example how it is done in Stack With Friends Demo:

LevelEditor Dependencies

The LevelEditor is the high-level element that combines many components involved in level editing. The following table shows the dependencies of LevelEditor and how these dependencies work together:

Component Description
EntityManager Stores the entities of a level into a json format, which is used internally by the LevelEditor. This is the only required component so the LevelEditor can work.
FelgoGameNetwork The Felgo Game Network is required if you add user-generated content to your games. Thus set the gameNetworkItem property if you want to allow user-generated levels.
LevelSelectionList Displays all levels from a level location in a vertically flickable list or with a custom delegate.
LevelLoader & LevelBase & LevelData The LevelLoader allows to load different qml level files, each derived from LevelBase. The loaded level data is available with the LevelBase::levelData property.
ItemEditor & EditableComponent The ItemEditor allows to modify properties at runtime that were marked with the EditableComponent. This allows balancing the level and storing the balancing settings.
BuildEntityButton & EntityBaseDraggable The BuildEntityButton is a drag and drop button for placing game entities derived from EntityBaseDraggable within a level.
LevelStore The LevelStore allows to monetize your user-created levels with in-app purchases. It also allows to award your best level creators to give them an incentive to create good levels.

How to Create multiple levels for a Game Efficiently

The following sections describe step-by-step how to create multiple levels for a game. The advantage of this approach is, that you can create and modify levels while the game is running. You can then allow your players to create levels on their devices as well and share their levels with the game community, without any further effort.

1. Define LevelEditor and ItemEditor

To be able to create levels dynamically, the first step is to define the entities that should be create-able. By deriving them from EntityBaseDraggable, they can be dragged around once placed in a level. To create them in a level, use the BuildEntityButton. The level editing mode is usually an own state of your GameScene, with the level editing overlay containing the BuildEntityButtons.

This is the high-level code structure:

 import Felgo 3.0
 import QtQuick 2.0

 GameWindow {

   EntityManager {
     // required for LevelEditor
     id: entityManager
     entityContainer: gameScene // in here the dynamic entities will be created
   }

   LevelEditor {
     // .. the usage is explained in the next step number 2.)
   }

   Scene {
     id: mainMenuScene
     // put code in here to show the gameScene
   }

   Scene {
     id: gameScene
     visible: false // make invisible initially, gets visible when play is clicked in MainMenu

     // makes a row of entities to be dragged into the level
     Row {
       id: buildEntityButtons
       visible: false // only gets visible when in state levelEditing

       // in the entities folder, there is a Choco and a Teddy entity which can be placed on the scene by dragging them in
       // they are derived from EntityBaseDraggable
       BuildEntityButton {
         anchors.fill: image1
         toCreateEntityType: "entities/Choco.qml"
         Image { id: image1; source: "../assets/img/choco.png"}
       }
       BuildEntityButton {
         anchors.fill: image2
         toCreateEntityType: "entities/Teddy.qml"
         Image { id: image2; source: "../assets/img/teddy.png"}
       }
     }// end of Row

     states: [
       State {
         // when the state is changed to levelEditing, the buildEntityButtons get visible and can be added to the level
         name: "levelEditing"
         PropertyChanges { target: buildEntityButtons; visible: true}
       }
     ]

   }// end of Scene
 }// end of GameWindow

ItemEditor Usage

The ItemEditor can be used as part of the level editing process: it allows to create any properties of a game while it is running, which is great for balancing and testing different settings to maximize the fun of the game.

To use the ItemEditor, just add it to the GameScene and mark the properties you would like to edit with EditableComponent. The following example adds the ItemEditor to the GameScene, and marks the width and height properties as editable:

 import Felgo 3.0
 import QtQuick 2.0

 Scene {
   id: gameScene

   // .. here the Row is placed ..

   ItemEditor {
     visible: gameWindow.state === "levelEditing"
     width: 150
     height: parent.height
   }

   // contents of Choco.qml:
   EntityBaseDraggable {

     entityType: "choco"

     Rectangle {
       width: 30
       height: 20

       EditableComponent {
         editableType: "Choco"
         properties: {
           // these properties can be changed at runtime
           "width": {"min": 0, "max": 200},
           "height": {"min": 0, "max": 200}
         }
       }
     }
   }// end of Choco.qml

 }// end of gameScene

Note: The UI of the LevelEditor, i.e. of the BuildEntityButton and the ItemEditor can be modified to match your game design. So you can create a level editor that looks just "right" for your game, or use the default design by Felgo.

2. Create, Test and Balance Levels

As the level editor functionality is in place, you can now store new levels, change the balancing settings of EditableComponent and ItemEditor and load different levels from a list. The list is displayed after pressing the "Levels" button in the GameScene, together with a button to create a new level.

   import Felgo 3.0
   import QtQuick 2.0

   GameWindow {

     EntityManager {
       id: entityManager
       entityContainer: gameScene

       // required for LevelEditor, so the entities can be created by entityType
       dynamicCreationEntityList: [ Qt.resolvedUrl("entities/Choco.qml"), Qt.resolvedUrl("entities/Teddy.qml")]

     }

     LevelEditor {
       id: levelEditor
     }

     Scene {
       id: gameScene

       // .. here the ItemEditor is placed ..

       Row {
         anchors.bottom: parent.bottom

         SimpleButton {
           text: "New Level"
           onClicked: levelEditor.createNewLevel()
         }

         SimpleButton {
           text: "Save Level"
           onClicked: levelEditor.saveCurrentLevel()
         }

         SimpleButton {
           text: "Show All Levels"
           onClicked: {
             levelEditor.loadAllLevelsFromStorageLocation(levelEditor.authorGeneratedLevelsLocation)
             levelSelectionList.visible = true
             }
         }
       }

       LevelSelectionList {
         id: levelSelectionList
         // at the beginning it is invisible, only gets visible after a click on the Levels button
         visible: false
         anchors.right: parent.right // position on the right

         // this connects the stored levels from the player with the level list
         levelMetaDataArray: levelEditor.authorGeneratedLevels

         onLevelSelected: {
           levelEditor.loadSingleLevel(levelData)
           // make invisible afterwards
           levelSelectionList.visible = false
         }
       }
     }// end of Scene
 }

3. Export Levels to Bundle Them with the Application

After you created the levels and balanced them, they are ready for distribution with your game. Thus you need to export the levels as JSON files and bundle them with your application binary.

Call the exportLevelAsFile() method to write the JSON file to the Documents directory. Exporting only makes sense on the desktop, as you sometimes do not have direct access to the Documents directory on some mobile platforms.

After exporting the file, you can copy it for example to a folder called jsonLevels in your application.

 import Felgo 3.0
 import QtQuick 2.0

 Row {
   // .. previous buttons from step 2 are here

   SimpleButton {
     text: "Export Level"
     onClicked: levelEditor.exportLevelAsFile()
   }
 }

Note: The LevelEditor also simplifies loading of different levels defined as QML files. However, the suggested approach is to create the levels dynamically while the game is running and only put the static elements that do not change into the LevelBase. As such, you can create the level during development by drag-and-dropping new entities with the BuildEntityButton, and also allow this your gamers.

4. Integrate the Exported Levels

Initialize the exported levels from step 3 by setting the applicationJSONLevelsDirectory to "jsonLevels/", which is the folder where you copied the level files from the Documents directory.

To display these levels now in a LevelSelectionList, all you need to do is setting the LevelSelectionList::levelMetaDataArray property to applicationJSONLevels. This list can be shown when the play button is clicked in the main menu:

 import Felgo 3.0
 import QtQuick 2.0

 GameWindow {

   LevelEditor {
     id: levelEditor
     applicationJSONLevelsDirectory: "jsonLevels/"
   }

   Scene {
     id: mainMenuScene

     onPlayClicked: {
       levelEditor.loadAllLevelsFromStorageLocation(levelEditor.applicationJSONLevelsLocation)
       applicationLevelSelectionList.visible = true
     }

     LevelSelectionList {
       // this list shows all exported json levels
       id: applicationLevelSelectionList
       visible: false // make visible when clicked on play
       levelMetaDataArray: levelEditor.applicationJSONLevels
       onLevelSelected: {
         levelEditor.loadSingleLevel(levelData)
         // make invisible afterwards
         applicationLevelSelectionList.visible = false
       }
     }

   }// end of Scene
 }// end of GameWindow

Different Level Locations

The LevelEditor contains 5 different locations how levels are stored:

The level locations are loaded with a call of loadAllLevelsFromStorageLocation(), and are then available as an array with one of the authorGeneratedLevels, userGeneratedLevels, downloadedLevels, applicationJSONLevels or applicationQMLLevels properties. These can be connected to the LevelSelectionList::levelMetaDataArray property so they are displayed.

Loading of userGeneratedLevels can be done with loadCommunityLevels() or loadUserOrFriendsLevels().

For an example how to connect these properties, see step 4. Integrate the Exported Levels above.

Accessing Loaded Level Data

You will often need to use the loaded level data in any form, for example to display the currently loaded level name or any other level data. The loaded data is accessible through the currentLevelNameString or the full data with the currentLevelData property.

The data of the loaded level is also accessible from the LevelBase::levelData property.

Example Usage

For a step-by-step introduction how to use the LevelEditor see the 4 steps starting with 1. Define LevelEditor and ItemEditor above and Felgo Crash Course Lesson 7 - How to boost level creation and balancing of your game with Felgo Level Editor.

For a complete example of the LevelEditor functionality in a real project, see the LevelEditor Example. The StackTheBoxWithEditor Demo, and Squaby Demo are sample games that contain the full LevelEditor functionality. The Stack With Friends Demo is a published game that contains the LevelEditor functionality and a LevelStore.

For more tutorials, videos and more see Further Level Editor Resources.

Property Documentation

applicationJSONLevels : alias

An array of LevelData::levelMetaData entries for exported JSON levels bundled within the application. These levels are read-only. Connect this property with the LevelSelectionList::levelMetaDataArray to display the available levels in a list.

Example how to connect the 2 properties:

 import Felgo 3.0

 GameWindow {

   LevelEditor { id: levelEditor }

   Scene {

     LevelSelectionList {
       levelMetaDataArray: levelEditor.applicationJSONLevels
     }
   }
 }

For an example value of a single entry see LevelData::levelMetaData.

See also applicationQMLLevels and authorGeneratedLevels.


applicationJSONLevelsDirectory : url

Specifies the directory to look for applicationJSONLevels, when loadAllLevelsFromStorageLocation(applicationJSONLevelsLocation) is called. No subdirectories are used.

Note: To search a directory, add a trailing "/" to the url so the intended folder is searched. For example, "levels/jsonLevels" would search for JSON files in the "levels" directory, whereas "levels/jsonLevels/" will look in the "levels/jsonLevels" directory.

See also applicationJSONLevels.


applicationJSONLevelsLocation : string

Use this property as parameter for loadAllLevelsFromStorageLocation().

See also Different Level Locations.


applicationQMLLevels : alias

An array of LevelData::levelMetaData entries for QML levels bundled within the application. These levels are read-only. Connect this property with the LevelSelectionList::levelMetaDataArray to display the available levels in a list.

Example how to connect the 2 properties:

 import Felgo 3.0

 GameWindow {

   LevelEditor { id: levelEditor }

   Scene {

     LevelSelectionList {
       levelMetaDataArray: levelEditor.applicationQMLLevels
     }
   }
 }

For an example value of a single entry see LevelData::levelMetaData.

See also applicationJSONLevels and authorGeneratedLevels.


applicationQMLLevelsLocation : string

Use this property as parameter for loadAllLevelsFromStorageLocation().

See also Different Level Locations.


authorGeneratedLevels : alias

An array of LevelData::levelMetaData entries for JSON levels stored by the user. These levels are read-only. Connect this property with the LevelSelectionList::levelMetaDataArray to display the available levels in a list.

Example how to connect the 2 properties:

 import Felgo 3.0

 GameWindow {

   LevelEditor { id: levelEditor }

   Scene {

     LevelSelectionList {
       levelMetaDataArray: levelEditor.authorGeneratedLevels
     }
   }
 }

With the above connection of the levelMetaDataArray property, the levels in LevelSelectionList will automatically update when the authorGeneratedLevels change.

For an example value of a single entry see LevelData::levelMetaData.

See also Different Level Locations.


authorGeneratedLevelsLocation : string

Use this property as parameter for loadAllLevelsFromStorageLocation().

See also Different Level Locations.


communityLevelFilters : variant

This property helps filter the user-generated levels returned from loadCommunityLevels().

The levels can be sorted to show the newest (default), highest rated or most downloaded levels. Set the order key either to ["created_at", "average_quality", "average_difficulty", "times_favored", "times_played"].

Furthermore, you can filter the levels to only show levels created in the last day, last week or all time (default). Set the timeLimit key to an integer value to the time frame within that hours the levels are returned. Do not set the key to return all time levels.

With the page and perPage parameters you can define how many levels should be shown. By default, the first 30 levels of the first page are shown, so the default value for page is 1 and for perPage 30. To avoid loading lots of data with a single request (as there can potentially be thousands user-generated levels), add a page counter to your LevelSelectionList. The total count of levels is then available in userGeneratedLevelsPageMetaData with the totalCount property.

By default, the first 30 all time levels are shown, ordered by the newest levels.

See also loadCommunityLevels().


communityLevels : variant

An array of LevelData::levelMetaData entries for JSON levels published by users of this game. These levels are read-only and get updated when you call loadCommunityLevels(). Connect this property with the LevelSelectionList::levelMetaDataArray to display the available levels in a list.

Example how to connect the 2 properties:

 import Felgo 3.0

 GameWindow {

   LevelEditor { id: levelEditor }

   Scene {

     LevelSelectionList {
       levelMetaDataArray: levelEditor.communityLevels
     }
   }
 }

With the above connection of the levelMetaDataArray property, the levels in LevelSelectionList will automatically update when the communityLevels change.

For an example value of a single entry see LevelData::levelMetaData.

See also Different Level Locations, loadCommunityLevels(), communityLevelsPageMetaData, communityLevelFilters, userGeneratedLevels, and userOrFriendsLevels.


communityLevelsPageMetaData : variant

Gets set by loadCommunityLevels() and contains information which page of the levels is shown and how many pages and levels there are in total.

Example value:

 {"page":1,"perPage":10,"totalCount":34,"pageCount":4}

If no levels are loaded the default value is -1 for all properties.

For the default paging parameters see the communityLevelFilters.

See also communityLevels, loadCommunityLevels(), communityLevelFilters, userGeneratedLevels, and userOrFriendsLevels.


currentLevelData : variant

Holds the current LevelData of a loaded level. This property is read-only and is updated with every level operation like saving, loading or creating a new level.

You can also access the data of the current level with LevelBase::levelData.


currentLevelNameString : string

Holds the levelName of the currently loaded level. If no level is set it has the value UndefinedLevel.


currentLevelStorageLocation : string


downloadedLevels : alias

An array of LevelData::levelMetaData entries for JSON levels downloaded by this user. These levels are read-only. Connect this property with the LevelSelectionList::levelMetaDataArray to display the available levels in a list.

Example how to connect the 2 properties:

 import Felgo 3.0

 GameWindow {

   LevelEditor { id: levelEditor }

   Scene {

     LevelSelectionList {
       levelMetaDataArray: levelEditor.userGeneratedLevels
     }
   }
 }

With the above connection of the levelMetaDataArray property, the levels in LevelSelectionList will automatically update when the authorGeneratedLevels change.

For an example value of a single entry see LevelData::levelMetaData.

See also Different Level Locations.


downloadedLevelsLocation : string

Use this property as parameter for loadAllLevelsFromStorageLocation().

See also Different Level Locations.


entityManagerItem : variant

Set this property to the EntityManager in your game. This is a required property to store and load entities with a level.

By default, it will be set to the id entityManager if one is found in the main qml file, or it is null if no such id is found.


gameNetworkItem : variant

Set this property to the id of FelgoGameNetwork.

By default, it will be set to the id gameNetwork if one is found in the project, or it is undefined if no such id is found.

Note: It is required that a FelgoGameNetwork component exists for user-generated levels. If you only use the LevelEditor to create your levels locally during development and do not want to allow user-generated levels, you can leave this property undefined.

By default, it is looking for an id with gameNetwork. So if you set your FelgoGameNetwork id to gameNetwork, you can leave this property at its default value.

This is an example how to use it:

 // ...

 FelgoGameNetwork {
   id: myGameNetwork

   // other gameNetwork code here
 }

 LevelEditor {
   id: myGameNetworkView

   gameNetworkItem: myGameNetwork
 }

 // ...

itemEditorItem : variant

Set this optional property if you use an ItemEditor and EditableComponent to change properties of a level at runtime for balancing. By default, it will be set to the id itemEditor if one is found in the main qml file, or it is null if no such id is found. It is not required to use one though and can be left at the default null value.

If you use an ItemEditor, the LevelEditor stores the current values of the balancing settings with the level and applies it when it is loaded.


levelBaseNameToUrlMap : variant

Specifies a map of qml files that derive from LevelBase to an internal levelBaseName. The levelBaseName needs to be a unique key in this map. The levelBaseName is then stored with the authorGeneratedLevels or applicationJSONLevels. This indirection is preferred over storing the url directly, because then you may also change the location of your qml files later in the project lifecycle while your previously stored levels will still work.

Note: The provided levelBaseUrls are relative to the folder of your LevelEditor object. Use Qt.resolvedUrl() to get an absolute path relative to this file.

This example shows 2 dynamic LevelBase files that can be loaded with dynamically created levels.

 {
   // the url is relative to the folder that contains the LevelEditor item in your game
   // you can set the levelBaseName to any value you like, just make it unique in the map
   // you will probably define an own qml file that should trigger a LevelLoader.createNewLevel() when clicked
   "DynamicLevel01": {url: Qt.resolvedUrl("levels/DynamicLevel01.qml")},
   "DynamicLevel02": {url: Qt.resolvedUrl("levels/DynamicLevel02.qml")}
 }

See also authorGeneratedLevels, applicationJSONLevels, LevelLoader, and LevelBase.


levelLoaderItem : variant

Set this optional property if you use the LevelLoader component to load different levels derived from LevelBase. If you do not have a static QML level to load, you may also leave this property undefined.

Here is an example how to set it:

 import Felgo 3.0
 import QtQuick 2.0

 GameWindow {

   LevelEditor {
     // set the levelLoaderItem property here, so levels derived from LevelBase are loaded automatically by calling loadSingleLevel()
     levelLoaderItem: myLevelLoader
   }

   Scene {

     LevelLoader {
       id: myLevelLoader
     }

   }
 }

By default, it will be set to the id levelLoader if one is found in the main qml file, or it is null if no such id is found.

This property was introduced in Felgo 2.3.0.


qmlLevelList : variant

Specifies an array of levelMetaData for static QML levels that are loaded with loadAllLevelsFromStorageLocation(applicationQMLLevelsLocation). Add all levelMetaData properties you want to display in the LevelSelectionList::levelItemDelegate. This example shows the minimum required properties:

 [
   {levelMetaData: {levelId: 1, levelName: "Level 1", levelBaseUrl: "levels/Level01.qml", .. other metadata like description could be added here .. }},
   {levelMetaData: {levelId: 2, levelName: "Level 2", levelBaseUrl: "levels/Level02.qml"}}
 ]

Note: The provided levelBaseUrls are relative to the LevelLoader item, not to the LevelEditor item.

Note: The levelId must be unique, so the level progress for this level can be stored.

See also applicationQMLLevels.


toRemoveEntityTypes : variant

An array of the entities that should be removed. This property is used for EntityManager::removeEntitiesByFilter() when a new level is loaded and the old remaining entities are removed. By default all entities are removed. An example value is ["squaby", "obstacle"] and is usually the same as toStoreEntityTypes.

See also toStoreEntityTypes.


toStoreEntityTypes : variant

This optional property holds an array of entityTypes or variationTypes to filter the entities that are stored in the level. By default, all entities will be stored. This property is used internally for EntityManager::storeEntitiesAsJson(). An example value is ["squaby", "obstacle"].

See also toRemoveEntityTypes.


userBestLevelStats : variant

Contains information about the player's best published levels in terms of downloads and rating values.

You can use this property to reward players for reaching a certain download number of their published level as described in Motivate Players to Create Levels.

If the logged in user has not published any level for this game yet the default value is . If none of the published levels was downloaded yet, the most_downloaded key is null. If none of the levels was rated yet, the best_quality key is null.

This is an example how you can reward the player with achievements based on the downloaded levels and best rating values:

 import Felgo 3.0

 LevelEditor {

   onUserBestLevelStatsChanged: {

     // if no level was ever downloaded or rated, userBestLevelStats is an empty {}
     console.debug("__new bestLevelStats:", JSON.stringify(userBestLevelStats))

     if(userBestLevelStats["best_quality"]) {

       var bestQuality = userBestLevelStats["best_quality"]["average_quality"]

       if(bestQuality >= 3)
         gameNetwork.unlockAchievement("reachLevelQuality3")
       if(bestQuality >= 4)
         gameNetwork.unlockAchievement("reachLevelQuality4")

     }
     if(userBestLevelStats["most_downloaded"]) {
       var mostDownloads = ["most_downloaded"]["times_downloaded"]

       if(mostDownloads >= 10)
         gameNetwork.unlockAchievement("reachLevelDownloads10")
       if(mostDownloads >= 100)
         gameNetwork.unlockAchievement("reachLevelDownloads100")
     }
   }

 }

With this example you can unlock the achievement and then call for example LevelStore::giveCurrency() with the amount of credits you want to give away for this unlocked achievement. See this example how to do the rewarding based on the Achievement::points you have defined.

 import Felgo 3.0

 FelgoGameNetwork {
   id: gameNetwork

   onAchievementUnlockedAfterServerApproval: {
     // getAchievementFromKey() is a GameNetwork function to return the Achievement object from the achievements list
     var ach = getAchievementFromKey(key)
     levelStore.giveCurrency(ach.points)

     nativeUtils.displayMessageBox("Achievement Unlocked!", "Congratulations! You just unlocked the achievement\n\n" + ach.name + "\n" + ach.description + "\n\nYou earned " + ach.points + " new credits! Keep on unlocking new achievements to get even more credits...")

   }

 }

For a full sample game how to reward players for user-generated levels see the Stack With Friends Demo.

See also loadBestLevelStats().


userGeneratedLevels : alias

An array of LevelData::levelMetaData entries for JSON levels stored by users of this game. These levels are read-only. Connect this property with the LevelSelectionList::levelMetaDataArray to display the available levels in a list.

Example how to connect the 2 properties:

 import Felgo 3.0

 GameWindow {

   LevelEditor { id: levelEditor }

   Scene {

     LevelSelectionList {
       levelMetaDataArray: levelEditor.userGeneratedLevels
     }
   }
 }

With the above connection of the levelMetaDataArray property, the levels in LevelSelectionList will automatically update when the userGeneratedLevels change.

For an example value of a single entry see LevelData::levelMetaData.

See also Different Level Locations, loadCommunityLevels(), loadUserOrFriendsLevels(), and userGeneratedLevelsPageMetaData.


userGeneratedLevelsLocation : string

Use this property as parameter for loadAllLevelsFromStorageLocation(). Preferably, user-generated levels should be loaded with loadCommunityLevels() or loadUserOrFriendsLevels().

See also Different Level Locations.


userGeneratedLevelsPageMetaData : variant

Gets set by loadCommunityLevels() or loadUserOrFriendsLevels() and contains information which page of the levels is shown and how many pages and levels there are in total.

Example value:

 {"page":1,"perPage":10,"totalCount":34,"pageCount":4}

If no levels are loaded the default value is -1 for all properties.

For the default paging parameters see the communityLevelFilters and userOrFriendLevelsFilters.

See also userGeneratedLevels, loadCommunityLevels(), loadUserOrFriendsLevels(), communityLevelFilters, and userOrFriendLevelsFilters.


userOrFriendLevelsFilters : variant

This property helps filter the user-generated levels returned from loadUserOrFriendsLevels().

The levels can be sorted to show the newest (default), highest rated or most downloaded levels. Set the order key either to ["created_at", "average_quality", "average_difficulty", "times_favored", "times_played"].

Furthermore, you can filter the levels to only show levels created in the last day, last week or all time (default). Set the timeLimit key to an integer value to the time frame within that hours the levels are returned. Do not set the key to return all time levels.

To only show levels created by the player, set the filters key to ["created_by_user"]. To only show the levels created by friends of the player, set it to ["created_by_friends"]. To show both levels from the player and his friends set the filters key to ["created_by_user", "created_by_friends"].

With the page and perPage parameters you can define how many levels should be shown. By default, the first 30 levels of the first page are shown, so the default value for page is 1 and for perPage 30. To avoid loading lots of data with a single request (as there can potentially be thousands user-generated levels), add a page counter to your LevelSelectionList. The total count of levels is then available in userGeneratedLevelsPageMetaData with the totalCount property.

By default, the first 30 all time levels created by friends of the player are shown, ordered by the newest levels.

See also loadUserOrFriendsLevels().


userOrFriendsLevels : variant

An array of LevelData::levelMetaData entries for JSON levels published by users of this game. These levels are read-only and get updated when you call loadUserOrFriendsLevels(). Connect this property with the LevelSelectionList::levelMetaDataArray to display the available levels in a list.

Example how to connect the 2 properties:

 import Felgo 3.0

 GameWindow {

   LevelEditor { id: levelEditor }

   Scene {

     LevelSelectionList {
       levelMetaDataArray: levelEditor.userOrFriendsLevels
     }
   }
 }

With the above connection of the levelMetaDataArray property, the levels in LevelSelectionList will automatically update when the communityLevels change.

For an example value of a single entry see LevelData::levelMetaData.

See also Different Level Locations, loadUserOrFriendsLevels(), userOrFriendsLevelsPageMetaData, userOrFriendLevelsFilters, userGeneratedLevels, and communityLevels.


userOrFriendsLevelsPageMetaData : variant

Gets set by loadUserOrFriendsLevels() and contains information which page of the levels is shown and how many pages and levels there are in total.

Example value:

 {"page":1,"perPage":10,"totalCount":34,"pageCount":4}

If no levels are loaded the default value is -1 for all properties.

For the default paging parameters see the userOrFriendLevelsFilters.

See also userOrFriendsLevels, loadUserOrFriendsLevels(), userOrFriendLevelsFilters, userGeneratedLevels, and communityLevels.


Signal Documentation

exportLevelAsFileFinished()

This handler is called when a level was exported successfully with exportLevelAsFile().

Note: The corresponding handler is onExportLevelAsFileFinished.


levelDownloadedError(variant = levelData, variant = errorData)

This handler is called when a level was downloaded with an error with downloadLevel() or downloadLevelFromId(). It contains the levelData of the failed level and errorData about the download error.

Note: The corresponding handler is onLevelDownloadedError.


levelDownloadedSuccessfully(variant = levelData)

This handler is called when a level was downloaded successfully with downloadLevel() or downloadLevelFromId(). It contains the levelData of the downloaded level.

Note: The corresponding handler is onLevelDownloadedSuccessfully.


levelPlayed(int = levelId)

This handler is called when a level with levelId was played with playLevel().

Note: The corresponding handler is onLevelPlayed.


levelPublished(int = levelId)

This handler is called when a level with levelId was published with publishLevel().

Note: The corresponding handler is onLevelPublished.


levelRated(int = levelId)

This handler is called when a level with levelId was rated with rateLevel().

Note: The corresponding handler is onLevelRated.


levelUnpublished(int = levelId)

This handler is called when a level with levelId was unpublished with unpublishLevel().

Note: The corresponding handler is onLevelUnpublished.


loadAllLevelsFromStorageLocationFinished(string = storageLocation, variant = allLevelsData)

This handler is called when a level was loaded successfully with loadAllLevelsFromStorageLocation(). The string parameter storageLocation contains the storageLocation that got specified in loadAllLevelsFromStorageLocation(). The variant parameter allLevelsData contains the loaded level data array of levelMetaData entries for each level.

Note: The corresponding handler is onLoadAllLevelsFromStorageLocationFinished.


loadLevelFinished()

This handler is called when a level was loaded successfully with loadSingleLevel().

Note: The corresponding handler is onLoadLevelFinished.


newLevelFinished(bool = createEmptyLevel)

This handler is called when a level was created successfully with createNewLevel() or duplicateCurrentLevel(). The bool parameter createEmptyLevel is true if createNewLevel() was called or false if duplicateCurrentLevel() was called.

Note: The corresponding handler is onNewLevelFinished.


removeLevelFinished(string = removedLevelName)

This handler is called when a level was removed successfully with removeCurrentLevel().

Note: The corresponding handler is onRemoveLevelFinished.


saveLevelFinished()

This handler is called when a level was saved successfully with saveCurrentLevel() or duplicateCurrentLevel().

Note: The corresponding handler is onSaveLevelFinished.


Method Documentation

clearAllDownloadedLevels()

Deletes all downloaded levels from the downloadedLevels WebStorage.

This function is mainly useful during testing and development if you want to reset all your downloaded levels. If you are using the LevelStore, use LevelStore::clearAllBoughtLevels() which calls this function internally.

See also downloadLevel() and downloadLevelFromId().


clearAllLevels()

Removes all levels from the authorGeneratedLevels. This is useful during development if many levels were created temporarily.

Note: You should not provide this functionality to end users, or at least add a security check with a NativeUtils::displayMessageBox() to assure the user is aware of deleting all the created levels.


createNewLevel(newLevelProperties)

Creates a new level with optional newLevelProperties to authorGeneratedLevels. These can contain the levelMetaData containing the levelName or a levelBaseName from the levelBaseNameToUrlMap. It can also contain customData, if you want to add some customData already at creating a new level.

The new level is not stored immediately after a call to createNewLevel(), but only after an explicit call of saveCurrentLevel().

An example value for newLevelProperties is: {levelMetaData:{ levelName: "newLevelName", levelBaseName: "level1" }, customData: {anyKey: "anyValue"} }

Note: It is possible to create multiple levels with the same levelName. After a call of createNewLevel(), a new levelId is created automatically which acts as the unique identifier amongst levels. However, the levelId is only used internally and may change if the level is stored in a different level location. Instead of using the levelId directly, for loading a level the whole levelMetaData should be used which is a single entry of the applicationJSONLevels, applicationQMLLevels or authorGeneratedLevels array.

See also saveCurrentLevel() and loadSingleLevel().


downloadLevel(levelMetaData)

Downloads a level with levelMetaData to the downloadedLevels. The levels are then available offline in an internal WebStorage, so the user can play them without internet connection and the levels are synced across multiple devices.

It is suggested to use the downloading functionality if you do not use a LevelStore. If you use a LevelStore, rather call LevelStore::buyLevel() which downloads the level if the player has sufficient credits.

The levelMetaData contains the levelId property, which is used to search the level in the userGeneratedLevels.

After downloading, the signal onLevelDownloadedSuccessfully is emitted. You can then call loadSingleLevel() with the levelMetaData to set this downloaded level as the current level.

This is an example to download a level inside a LevelListItem of a LevelSelectionList:

 import Felgo 3.0

 SimpleButton {
   text: levelEditor.isLevelDownloaded(modelData.levelId) ? "Play" : "Download"
   visible: modelData["storageLocation"] === levelEditor.userGeneratedLevelsLocation
   onClicked: {

     if(levelEditor.isLevelDownloaded(modelData.levelId)) {

       // if this level is already downloaded, this loads the level and sets it as the current one
       levelEditor.loadSingleLevel(modelData)
     } else {

       // this downloads the level
       levelEditor.downloadLevel(modelData)
     }
   }
 }

See also downloadLevelFromId() and isLevelDownloaded().


downloadLevelFromId(levelId)

Call this function if an explicit levelId is entered by the user. This happens for example when searching for a specific id of a level created by a friend.

After downloading, the signal onLevelDownloadedSuccessfully is emitted. You can then call loadSingleLevel() with the levelMetaData to set this downloaded level as the current level.

See also downloadLevel().


duplicateCurrentLevel(newLevelProperties)

Duplicates the current level and creates a new levelId for it. Thus it is useful to define another levelName for the newLevelProperties.

Use this function after you modified a level but want to save it as a different levelName without saving the old level. Thus this method automatically calls saveCurrentLevel() and uses all the existing entities or customData in the level, with the addition that a new levelId is created.

This is an example value for newLevelProperties: { levelMetaData:{ levelName: "newLevelName"} }

See also createNewLevel().


exportLevelAsFile(filename)

Exports the last stored level called with saveCurrentLevel() to a JSON file. This file can then be used to bundle it with the application, to be available to all players when they download the app.

This method is only useful during development and should not be available for end users, because they can use the share level mechanism by publishing levels to the whole gaming community.

The filename is optional: if none is provided, the currentLevelNameString is used. The file will be called filename ".json" and is stored in the Documents directory.

Calling this method only makes sense on desktop platforms, because you do not have direct access to the Documents directory on some mobile platforms.


isCurrentLevelOfLocation(storageLocation)

Call this convenience function to avoid writing levelEditor.currentLevelStorageLocation === levelEditor.authorGeneratedLevelLocation, but instead you can write levelEditor.isCurrentLevelOfLocation(levelEditor.authorGeneratedLevelsLocation.

You can also bind this function to a property, as it gets re-evaluated when currentLevelStorageLocation changes.

See also currentLevelStorageLocation.


isLevelDownloaded(levelId)

Use this function to check if the level was already downloaded with downloadLevel() before.

You can then change the look of your LevelListItem and show for example a Download button only if the level was not downloaded before, and if it was downloaded show a Play button.

This is an example of a single LevelListItem of a LevelSelectionList:

 SimpleButton {
   text: levelEditor.isLevelDownloaded(modelData.levelId) ? "Play" : "Download"

   onClicked: {

     if(levelEditor.isLevelDownloaded(modelData.levelId)) {
       levelSelectionList.levelSelected(modelData)
     } else {
       levelSelectionList.downloadLevelClicked(modelData)
     }
   }
 }// end of SimpleButton

loadAllLevelsFromStorageLocation(storageLocation)

Loads all the metadata of the levels for a single storageLocation. It can either be authorGeneratedLevelsLocation, applicationJSONLevelsLocation, applicationQMLLevelsLocation, userGeneratedLevelsLocation or downloadedLevelsLocation.

See Different Level Locations for more information about the different locations.

To load user-generated levels, you can also call loadCommunityLevels() or loadUserOrFriendsLevels(). A call of loadAllLevelsFromStorageLocation(userGeneratedLevelsLocation) is the same as loadUserOrFriendsLevels(). If you call loadCommunityLevels() and afterwards loadAllLevelsFromStorageLocation(userGeneratedLevelsLocation), the community level request with the same parameters will be sent.


loadBestLevelStats(params)

This function updates the userBestLevelStats from the server.

The optional params can contain a timeLimit key as integer, which specifies to only consider levels created within the mentioned hours. If none is provided, the all-time stats are returned.

You can call this function when the FelgoGameNetwork was initially synced by listening to a change of FelgoGameNetwork::userInitiallyInSync like in this example:

 import Felgo 3.0

 FelgoGameNetwork {
   id: gameNetwork

   onUserInitiallyInSyncChanged: {

     if(userInitiallyInSync) {
       levelEditor.loadBestLevelStats()
     }
   }
 }

See also userBestLevelStats.


loadCommunityLevels(params)

Call this function to load the community levels. These are levels published by all the players of the game, including the own levels published by the player.

After the levels are loaded, they are available with the userGeneratedLevels property. So to connect the userGeneratedLevels with a LevelSelectionList, set the LevelSelectionList::levelMetaDataArray to userGeneratedLevels as described in Integrate the Exported Levels.

See communityLevelFilters what the params can look like to filter the level results.

By default, all time levels are shown, ordered by the newest levels.

See also communityLevelFilters and loadUserOrFriendsLevels().


loadSingleLevel(levelMetaData)

Loads the level based on its levelMetaData. The levelMetaData is a single entry either from the authorGeneratedLevels, applicationQMLLevels or the applicationJSONLevels array.

The LevelSelectionList automatically handles forwarding the levelMetaData from a single entry to the LevelEditor with the following example code when authorGeneratedLevels are used:

 import Felgo 3.0

 GameWindow {

   LevelEditor {
     id: levelEditor

     Component.onCompleted: levelEditor.loadAllLevelsFromStorageLocation(authorGeneratedLevelsLocation)
   }

   Scene {

     LevelSelectionList {
       levelMetaDataArray: levelEditor.authorGeneratedLevels

       onLevelSelected: {
         // the LevelSelectionList passes the currently selected level information containing the levelMetaData as levelData parameter
         levelEditor.loadSingleLevel(levelData)
       }
     }
   }
 }

loadUserOrFriendsLevels(params)

Call this function to load levels created by friends of the player or from the player. Players become friends after they both connect their player account with Facebook and play the same game. This is similar to the Leaderboards view of FelgoGameNetwork where players can compare each other in the friends section after connecting with Facebook.

After the levels are loaded, they are available with the userGeneratedLevels property. So to connect the userGeneratedLevels with a LevelSelectionList, set the LevelSelectionList::levelMetaDataArray to userGeneratedLevels as described in Integrate the Exported Levels.

See userOrFriendLevelsFilters what the params can look like to filter the level results.

By default, all time levels created by friends of the player are shown, ordered by the newest levels.

See also userOrFriendLevelsFilters and loadCommunityLevels().


playLevel(levelId)

Call this function to increase the times_played counter in the LevelData::levelMetaData for userGeneratedLevels. The levelId is required so the correct level play counter is increased.

You can then order the levels in loadCommunityLevels() or loadUserOrFriendsLevels() based on the order key "times_played", which returns the levels with the highest play count on the top.


publishLevel()

Publish a level from the local device (the authorGeneratedLevels) to the game community so it is usable by all other players.

It is also possible to call publishLevel() for an already published level - in that case the published level is updated. You may want to restrict that in your game, because then previous level ratings would not be correct anymore, because it back then contained earlier balancing settings of ItemEditor or different entity positions. It is up to you if you want to allow an updating of already published levels - if you want to restrict it you can use the publishedLevelId property to check if the level was published already.

Note: Calling publishLevel() for a level selected from the userGeneratedLevels does not work yet. Updating a published level only works if selected from the authorGeneratedLevels.

After the level was published, onLevelPublished is emitted.

To unpublish a level (and also delete its rating and download stats), call unpublishLevel().

The Stack With Friends Demo shows an example how a UI for user-generated levels can look like.

An already published level has the LevelData::levelMetaData property publishedLevelId set to a valid integer. So you can use this property to determine if a level was already published in your LevelSelectionList. This example shows how to determine if a level was already published in a LevelSelectionList:

 // this is code of a LevelListItem in a LevelSelectionList

 SimpleButton {

   // if the level was already published, it has the publishedLevelId set
   // if it is set, show "Share: <levelId>", otherwise show "Unpublished" in the Button
   text: modelData["publishedLevelId"] !== undefined ? "Share LevelId: " + modelData["publishedLevelId"] : "Unpublished"

   onClicked: {
     if(modelData["publishedLevelId"] !== undefined) {

       // this is the level id users can search for
       nativeUtils.displayMessageBox("Share Your Level","Your friends can download your published level from the 'Friend Levels' section, if they enter this LevelId:\n\n" +modelData["publishedLevelId"]+ "\n\nIf you are connected with Facebook, all your levels are accessible to your friends. Would you like to share your new level on your Facebook Timeline?", 2)
     } else {

       // the level was not published, show the user he should first publish it in the level editor mode
       nativeUtils.displayMessageBox("Level Not Published Yet","This level is not published yet. After you publish it in the level editor, it will be available to all players", 1)
     }
   }
 }

See also levelPublished and unpublishLevel.


rateLevel(params)

Call this function to change for example the avg_quality rating value in the LevelData::levelMetaData for userGeneratedLevels.

You can then order the levels in loadCommunityLevels() or loadUserOrFriendsLevels() based on the order string "avg_quality", which returns the levels with the highest quality rating on the top.

The params require a key levelId and one or multiple of these rating values:

  • quality - Integer quality rating for the level, usually between 1 and 5. This is similar to the star rating in the app store. To order levels based on this key use "avg_quality".
  • difficulty - Integer difficulty rating for the level, usually between 1 and 5. You can use it to list easier levels on top. To order levels based on this key use "avg_difficulty".
  • favored - Boolean value if the level is favored by the player. To order levels based on this key use "times_favored".

This is an example how to give a level a quality rating of 3 (stars):

 levelEditor.rateLevel( { levelId: <idFromLevelSelectionList, quality: 3 } )

removeCurrentLevel()

Removes the currently loaded level from authorGeneratedLevels.


saveCurrentLevel(saveProperties)

Stores the current level to the authorGeneratedLevels. You can add custom saveProperties containing levelMetaData and customData to overwrite the existing LevelData. An example for saveProperties is: { levelMetaData: { levelName: "myNewLevelName", description: "myDescription" }, customData: { anyKey: "anyValue", ...} }


unpublishLevel(levelMetaData)

Deletes the published level from the online community levels and removes the publishedLevelId key from the authorGeneratedLevels.

Note: Use this function with care, because once unpublished all level ratings and level stats like download count are lost. Thus show a confirmation dialog to the player before unpublishing it. Also, if the level creator unpublishes a level, it will no longer be listed in the userGeneratedLevels for the game community. For players who already downloaded this level, they will still be able to play the unpublished level (otherwise if the player has bought it and you take it away from him this will not make a positive impact). The players already downloaded or purchased the unpublished level can also still access the leaderboards, if you added Leaderboards support for user-generated levels.

Unpublishing a level only works for the user who published it before (so only for the author).

After the level was unpublished, onLevelUnpublished is emitted.

See also levelUnpublished and publishLevel.


Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded