Multiple scenes, like menu, credits or preferences, and multiple levels are essential to nearly any good game. We will take a look at how easy it is to cover those requirements and set up a well-structured project with Felgo.
The code, that we will build step by step, is also available as a template for new Felgo 2 projects. Click File/New Project
in Qt Creator and then select Template - Multi Scene Multi Levels
to
create a new project based on this template.
This tutorial assumes you already had a look at Getting Started with Felgo and Qt Creator. They provide you with the very basics which won't be fully explained in this tutorial. Furthermore our project will support different screen sizes and resolutions. You can learn more about that here: How to create mobile games for different screen sizes and resolutions
Resources for this project are available for you to download right here: Download Resources
Create a new Empty Felgo 3 Project with a name of your choice. Then extract the resource files that you just downloaded into the
assets
folder of your project.
Let's quickly summarize what we are about to create:
First, we cut down the Code in the main.qml
to the minimum, like this:
import Felgo 4.0 import QtQuick 2.0 GameWindow { id: gameWindow // create and remove entities at runtime EntityManager { id: entityManager } }
We won't need the functionality of the EntityManager in this tutorial, but you will most likely need it in a real game, so adding the EntityManager won't hurt nobody.
Now the GameWindow is ready to carry our scenes, so let's create some.
There could be a couple of characteristics that are exactly the same in each of the scenes, so smart people (like you and me are!) plan ahead and create a SceneBase
as a base component for all our scenes.
Create a folder with the name common
inside the qml folder of your project. Then add a SceneBase.qml
file to your common
folder
import Felgo 4.0 import QtQuick 2.0 Scene { id: sceneBase }
We will add more code later, as we encounter things that will fit in this base component.
Now we use the SceneBase
to create our scenes and add different background rectangles to each of them plus a "logo" for the menu scene. Create a folder with the name scenes
inside the qml folder of
your project. Add the following files, each containing the code below it, to your scenes
folder:
MenuScene.qml
import Felgo 4.0 import QtQuick 2.0 import "../common" SceneBase { id:menuScene // background Rectangle { anchors.fill: parent.gameWindowAnchorItem color: "#47688e" } // the "logo" Text { anchors.horizontalCenter: parent.horizontalCenter y: 30 font.pixelSize: 30 color: "#e9e9e9" text: "MultiSceneMultiLevel" } }
Note that we have to import the common
folder at the top of the code, because the SceneBase.qml
file is located in that directory, while our MenuScene
is in the scenes
directory.
CreditsScene.qml
import Felgo 4.0 import QtQuick 2.0 import "../common" SceneBase { id:creditsScene // background Rectangle { anchors.fill: parent.gameWindowAnchorItem color: "#49a349" } }
SelectLevelScene.qml
import Felgo 4.0 import QtQuick 2.0 import "../common" SceneBase { id:selectLevelScene // background Rectangle { anchors.fill: parent.gameWindowAnchorItem color: "#ece468" } }
GameScene.qml
import Felgo 4.0 import QtQuick 2.0 import "../common" SceneBase { id:gameScene // background Rectangle { anchors.fill: parent.gameWindowAnchorItem color: "#dd94da" } }
The next step is to add all those scenes to our main.qml
, which should then look like this
import Felgo 4.0 import QtQuick 2.0 import "../scenes" GameWindow { id: gameWindow // menu scene MenuScene { id: menuScene } // scene for selecting levels SelectLevelScene { id: selectLevelScene } // credits scene CreditsScene { id: creditsScene } // game scene to play a level GameScene { id: gameScene } }
Awesome, if we run the project we got 4 scenes, overlaying each other, so effectively we only see the last one added, which is the GameScene
. Although that's a very nice pink, it needs some improvement!
The easiest way to only show one scene is to hide all scenes by default, and only display the scene we currently need. Wait what do I read there, hide ALL scenes? Now that should be no problem, thanks to our
SceneBase
.
Add one line to SceneBase.qml
and all our scenes are hidden by default
Scene { id: sceneBase // by default, set the opacity to 0 - this will be changed from the main.qml with PropertyChanges opacity: 0 // we set the visible property to false if opacity is 0 because the renderer skips invisible items, this is an performance improvement visible: opacity > 0 // if the scene is invisible, we disable it. In Qt 5, components are also enabled if they are invisible. This means any MouseArea in the Scene would still be active even we hide the Scene, since we do not want this to happen, we disable the Scene (and therefore also its children) if it is hidden enabled: visible }
But how do I set the current scene visible? And what is that first comment in the code talking about? PropertyChanges?
Add this at the end of your main.qml
//... GameWindow { //... // default state is menu -> default scene is menuScene state: "menu" // state machine, takes care reversing the PropertyChanges when changing the state like changing the opacity back to 0 states: [ State { name: "menu" PropertyChanges {target: menuScene; opacity: 1} PropertyChanges {target: gameWindow; activeScene: menuScene} }, State { name: "selectLevel" PropertyChanges {target: selectLevelScene; opacity: 1} PropertyChanges {target: gameWindow; activeScene: selectLevelScene} }, State { name: "credits" PropertyChanges {target: creditsScene; opacity: 1} PropertyChanges {target: gameWindow; activeScene: creditsScene} }, State { name: "game" PropertyChanges {target: gameScene; opacity: 1} PropertyChanges {target: gameWindow; activeScene: gameScene} } ] }
There is our answer. We use a state machine. The GameWindow has a property state
which we use to define our current scene.
Our default scene is the MenuScene
, so we write state: "menu"
. We just changed the value of the state
property and that triggers our state machine. It will browse through the states we
defined, and execute the corresponding PropertyChanges. In our case, we set the opacity
of the MenuScene
to 1, making it visible
while the other scenes stay hidden.
If we change the state again, the state machine will take care that the PropertyChanges of the old state will be reversed. So e.g. if we would now
change the state to "credits", the opacity
of the MenuScene
will be automatically changed to 0 again, and the CreditsScene
will have its opacity
changed to 1.
We are also changing the activeScene
property of the GameWindow to set the focus on the current scene, you will learn why we do this later in this tutorial.
If we run the project now, we see the right home scene, but that's about it. Time to add some navigation.
We will create a small reusable button for all our menu items.
Add a MenuButton.qml
file to the common
folder, with this content:
import QtQuick 2.0 Rectangle { id: button // this will be the default size, it is same size as the contained text + some padding width: buttonText.width+ paddingHorizontal*2 height: buttonText.height+ paddingVertical*2 color: "#e9e9e9" // round edges radius: 10 // the horizontal margin from the Text element to the Rectangle at both the left and the right side. property int paddingHorizontal: 10 // the vertical margin from the Text element to the Rectangle at both the top and the bottom side. property int paddingVertical: 5 // access the text of the Text component property alias text: buttonText.text // this handler is called when the button is clicked. signal clicked Text { id: buttonText anchors.centerIn: parent font.pixelSize: 18 color: "black" } MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true onClicked: button.clicked() onPressed: button.opacity = 0.5 onReleased: button.opacity = 1 } }
Our MenuScene
will have 2 buttons. One to go to the selectLevelScene
, and the other one to go to the CreditsScene
.
Add this to the MenuScene.qml
//... SceneBase { id: menuScene // signal indicating that the selectLevelScene should be displayed signal selectLevelPressed // signal indicating that the creditsScene should be displayed signal creditsPressed //... // menu Column { anchors.centerIn: parent MenuButton { text: "Levels" onClicked: selectLevelPressed() } MenuButton { text: "Credits" onClicked: creditsPressed() } } }
To make our code cleaner and easier to maintain, we will put all the logic for changing the scenes in our GameWindow in the main.qml
. The scenes will only emit a signal which
button has been pressed, and the GameWindow will listen to those signals and change the states (and scenes).
What we are missing now is the listener for these signals.
Add this to your main.qml
, more precisely the MenuScene
//... MenuScene { id: menuScene // listen to the button signals of the scene and change the state according to it onSelectLevelPressed: gameWindow.state = "selectLevel" onCreditsPressed: gameWindow.state = "credits" } //...
If we run the project, we can switch from the MenuScene
to other scenes, but we can't go back, that's not very handy. Every scene will have some kind of back functionality, even the MenuScene
which
we will take care of at the very end of this tutorial. Luckily, the Scene already support back button support with Scene::backButtonPressed.
Thanks to that, every scene can send a request to go back. All we need is a simple back button and listen to that signal.
Add this to CreditsScene.qml
, the SelectLevelScene.qml
and the GameScene.qml
// back button to leave scene MenuButton { text: "Back" anchors.right: selectLevelScene.gameWindowAnchorItem.right anchors.rightMargin: 10 anchors.top: selectLevelScene.gameWindowAnchorItem.top anchors.topMargin: 10 onClicked: backButtonPressed() }
And then add listeners to main.qml
like this
//... SelectLevelScene { id: selectLevelScene onBackButtonPressed: gameWindow.state = "menu" } //...
//... CreditsScene { id: creditsScene onBackButtonPressed: gameWindow.state = "menu" } //...
//... GameScene{ id: gameScene onBackButtonPressed: gameWindow.state = "selectLevel" } //...
Go ahead, run the project and enjoy jumping around between the scenes, what a pleasure!
Before we can talk about the levels, we gotta figure out what our game actually is about. We will keep it as simple as it gets, since this tutorial is not primarily about creating a game. But I will use the simple game mechanics to show you some stuff that could be useful to you as well.
The game will be about having a simple rectangle, that moves or jumps around, and you score a point for each successful tap on it. Again, we will try to separate the components as good as possible, to make the code easier to
understand and maintain. The Level
will only handle how the rectangle behaves and moves, and will emit a signal if the rectangle is tapped successfully. The GameScene
will listen to this signal and
increase the score.
Since all of our levels will need the signal that is emitted when the rectangle is pressed, we will create a LevelBase
and use it as the base component for our levels, just like we did it with the scenes.
Furthermore, we will load the levels dynamically, having only the one we currently play consume memory.
Create a Levelbase.qml
file in the common
folder and add this content:
import QtQuick 2.0 Item { // this will be displayed in the GameScene property string levelName // this is emitted whenever the rectangle has been tapped successfully, the GameScene will listen to this signal and increase the score signal rectanglePressed }
Now we will create 3 levels and I will add a bit of explanation to each one of them.
Create a levels
folder in your qml
folder and add a Level1.qml
file to it. Then add this to your Level1.qml
file:
import QtQuick 2.0 import Felgo 4.0 import "../common" as Common Common.LevelBase { levelName: "Level1" Rectangle { color: "orange" width: 100 height: 100 radius: 10 anchors.centerIn: parent MouseArea { anchors.fill: parent // since the level is loaded in the gameScene, and is therefore a child of the gameScene, you could also access gameScene.score here and modify it. But we want to keep the logic in the gameScene rather than spreading it all over the place onPressed: rectanglePressed() } } }
Important thing to note, Felgo already has a LevelBase component, for use with the LevelLoader and the LevelEditor. Since we created our own one, and want to use this one, we need to add a qualifier (pretty much like a namespace) to it. We are doing this by adding as Common
to the
import of the common
folder. And then use Common.LevelBase
to make sure the right one is used.
The rest is pretty straightforward. Just a rectangle with a MouseArea, and if it is pressed, we call our signal to indicate that the rectangle is pressed successfully.
Now create a Level2.qml
file to the levels
folder and add this code:
import QtQuick 2.0 import Felgo 4.0 import "../common" as Common Common.LevelBase { levelName: "Level2" Rectangle { id: rectangle color: "cyan" width: 100 height: 100 radius: 10 property bool togglePosition: false anchors.horizontalCenter: parent.horizontalCenter // this property binding changes the horizontal offset from the center each time togglePosition changes anchors.horizontalCenterOffset: togglePosition ? -100 : 100 anchors.verticalCenter: parent.verticalCenter MouseArea { anchors.fill: parent onPressed: { // every time the rectangle is pressed, we toggle its position by changing the horizontal offset from the center rectangle.togglePosition = !rectangle.togglePosition rectanglePressed() } } } }
That one is a bit more interesting. We want the rectangle to jump from left to right and vice versa each time we tap it. We are using a custom property togglePosition
which is either true or false to indicate if
the rectangle is left or right. First of all we center the rectangle in the level, and then we add a property binding on the horizontalCenterOffset
property to move it 100 pixel to the left or right of the
center.
Next create a Level3.qml
file to the levels
folder and add this code:
import QtQuick 2.0 import Felgo 4.0 import "../common" as Common Common.LevelBase { levelName: "Level3" Rectangle { id: rectangle color: "blue" width: 100 height: 100 radius: 10 anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenterOffset: 120 anchors.verticalCenter: parent.verticalCenter MouseArea { anchors.fill: parent onPressed: rectanglePressed() } } // SequentialAnimation plays all its child animations one after the other // we are moving the rectangle by changing its horizontal offset from the center SequentialAnimation { running: true // let it run forever loops: Animation.Infinite // move the rectangle left by changing the offset from current (120) to -120 NumberAnimation { target: rectangle duration: 1500 property: "anchors.horizontalCenterOffset" easing.type: Easing.InOutQuad to: -120 } // after moving left has finished, we move the rectangle right by changing the offset from current (-120) to 120 NumberAnimation { target: rectangle duration: 1500 property: "anchors.horizontalCenterOffset" easing.type: Easing.InOutQuad to: 120 } } }
Animation time! We are using the SequentialAnimation component, that will play all the child animations one after the other. Like in the 2nd level,
we are using the horizontalCenterOffset
property to change the position of the rectangle relative to the center of the level. The start offset is set to 120 pixel. The first animation will change this to -120
pixel, the second one back to 120 pixel. Then the first animation is played again since we have set the SequentialAnimation to loops:
Animation.Infinite
.
Time to select and play a level.
We start with adding some code to SelectLevelScene.qml
// ... SceneBase { id: selectLevelScene // ... // signal indicating that a level has been selected signal levelPressed(string selectedLevel) // levels to be selected Grid { anchors.centerIn: parent spacing: 10 columns: 5 MenuButton { text: "1" width: 50 height: 50 onClicked: { levelPressed("Level1.qml") } } MenuButton { text: "2" width: 50 height: 50 onClicked: { levelPressed("Level2.qml") } } MenuButton { text: "3" width: 50 height: 50 onClicked: { levelPressed("Level3.qml") } } Repeater { model: 10 MenuButton { text: " " width: 50 height: 50 } } } }
We added a signal that indicates that a level has been selected, and pass the filename of the selected level as a parameter. The level selection is a Grid where we
added 3 MenuButton
s for our levels and some empty ones with a Repeater, just to have some content.
Go to the main.qml
file and change the code of the LevelSelectionScene
component like this:
// scene for selecting levels SelectLevelScene { id: selectLevelScene onLevelPressed: { // selectedLevel is the parameter of the levelPressed signal gameScene.setLevel(selectedLevel) gameWindow.state = "game" } onBackButtonPressed: gameWindow.state = "menu" }
Now if a level is selected, we pass the selected level to the GameScene
and switch the state to "game", which will cause the scenes to change. Before we can run this code without any errors, we need to add the
setLevel
function to our GameScene
.
I explain the code part by part as we add it, at the end of this section I will also post the full source code of the GameScene
for you to copy and paste.
Go to the GameScene.qml
file and change the content to this:
import Felgo 4.0 import QtQuick 2.0 import "../common" SceneBase { id:gameScene // the filename of the current level gets stored here, it is used for loading the property string activeLevelFileName // the currently loaded level gets stored here property variant activeLevel // set the name of the current level, this will cause the Loader to load the corresponding level function setLevel(fileName) { activeLevelFileName = fileName } // background Rectangle { anchors.fill: parent.gameWindowAnchorItem color: "#dd94da" } // back button to leave scene MenuButton { text: "Back to menu" // anchor the button to the gameWindowAnchorItem to be on the edge of the screen on any device anchors.right: gameScene.gameWindowAnchorItem.right anchors.rightMargin: 10 anchors.top: gameScene.gameWindowAnchorItem.top anchors.topMargin: 10 onClicked: { backButtonPressed() activeLevel = undefined activeLevelFileName = "" } } // load levels at runtime Loader { id: loader source: activeLevelFileName !== "" ? "../levels/" + activeLevelFileName : "" onLoaded: { // since we did not define a width and height in the level item itself, we are doing it here item.width = gameScene.width item.height = gameScene.height // store the loaded level as activeLevel for easier access activeLevel = item } } }
There you go, we got the function to set the level filename. The real magic happens in the Loader element though. It loads the component that is defined in the
source
property. Setting the source to "" will cause the Loader element to unload the level. So if we are passing a level filename via the
setLevel
function, we are changing the activeLevelFileName
to something different than "" and this will make our Loader element load the
level. Once it is loaded, we can access it with item
in the onLoaded
handler. Note that we are reseting (and therefore unloading) the level when pressing the "Back" button.
Since we defined a levelName
for each level, why not display it?! Add this:
// name of the current level Text { anchors.left: gameScene.gameWindowAnchorItem.left anchors.leftMargin: 10 anchors.top: gameScene.gameWindowAnchorItem.top anchors.topMargin: 10 color: "white" font.pixelSize: 20 text: activeLevel !== undefined ? activeLevel.levelName : "" }
What we are missing now is some game logic, so change your code like this:
// ... SceneBase { id:gameScene // the filename of the current level gets stored here, it is used for loading the property string activeLevelFileName // the currently loaded level gets stored here property variant activeLevel // score property int score: 0 // ... // load levels at runtime Loader { id: loader source: activeLevelFileName !== "" ? "../levels/" + activeLevelFileName : "" onLoaded: { // reset the score score = 0 // since we did not define a width and height in the level item itself, we are doing it here item.width = gameScene.width item.height = gameScene.height // store the loaded level as activeLevel for easier access activeLevel = item } } // we connect the gameScene to the loaded level Connections { // only connect if a level is loaded, to prevent errors target: activeLevel !== undefined ? activeLevel : null // increase the score when the rectangle is clicked onRectanglePressed: { score++ } } // display the current score Text { anchors.horizontalCenter: parent.horizontalCenter anchors.top: gameScene.gameWindowAnchorItem.top anchors.topMargin: 30 color: "white" font.pixelSize: 40 text: score } }
If a level is loaded, we connect to it and listen to the rectanglePressed
signal. If it is emitted, we increase our score. Additionally we display the score on the screen. That was way too easy, right? We will
just add a little more to make the "game" feel better. A countdown at the start of the game, so the player can mentally prepare for the upcoming tap tap
tap tap tap ...
Just a little more modification:
// ... SceneBase { id:gameScene // the filename of the current level gets stored here, it is used for loading the property string activeLevelFileName // the currently loaded level gets stored here property variant activeLevel // score property int score: 0 // countdown shown at level start property int countdown: 0 // flag indicating if game is running property bool gameRunning: countdown === 0 // ... // load levels at runtime Loader { id: loader source: activeLevelFileName !== "" ? "../levels/" + activeLevelFileName : "" onLoaded: { // reset the score score = 0 // since we did not define a width and height in the level item itself, we are doing it here item.width = gameScene.width item.height = gameScene.height // store the loaded level as activeLevel for easier access activeLevel = item // restarts the countdown countdown = 3 } } // we connect the gameScene to the loaded level Connections { // only connect if a level is loaded, to prevent errors target: activeLevel !== undefined ? activeLevel : null // increase the score when the rectangle is clicked onRectanglePressed: { // only increase score when game is running if(gameRunning) { score++ } } } // ... // text displaying either the countdown or "tap!" Text { anchors.centerIn: parent color: "white" font.pixelSize: countdown > 0 ? 160 : 18 text: countdown > 0 ? countdown : "tap!" } // if the countdown is greater than 0, this timer is triggered every second, decreasing the countdown (until it hits 0 again) Timer { repeat: true running: countdown > 0 onTriggered: { countdown-- } } }
We make heavy use of property bindings here. First we have a gameRunning
property that only becomes true if the countdown
property is 0. Then we got a Timer that is triggered every second (1000ms is the default interval) but is only running if the countdown is greater than 0. And then we got a Text element that displays the countdown if it is bigger then 0, or shows "tap!" once the countdown becomes 0. And to start this whole countdown machine, all we have to do is
set the countdown
property to anything bigger than 0, in our case we set it to 3 when the level is loaded. Our score will only get increased if the game is running.
The whole source code of the GameScene.qml
file should now look something like this:
import Felgo 4.0 import QtQuick 2.0 import "../common" SceneBase { id:gameScene // the filename of the current level gets stored here, it is used for loading the property string activeLevelFileName // the currently loaded level gets stored here property variant activeLevel // score property int score: 0 // countdown shown at level start property int countdown: 0 // flag indicating if game is running property bool gameRunning: countdown === 0 // set the name of the current level, this will cause the Loader to load the corresponding level function setLevel(fileName) { activeLevelFileName = fileName } // background Rectangle { anchors.fill: parent.gameWindowAnchorItem color: "#dd94da" } // back button to leave scene MenuButton { text: "Back to menu" // anchor the button to the gameWindowAnchorItem to be on the edge of the screen on any device anchors.right: gameScene.gameWindowAnchorItem.right anchors.rightMargin: 10 anchors.top: gameScene.gameWindowAnchorItem.top anchors.topMargin: 10 onClicked: { backButtonPressed() activeLevel = undefined activeLevelFileName = "" } } // name of the current level Text { anchors.left: gameScene.gameWindowAnchorItem.left anchors.leftMargin: 10 anchors.top: gameScene.gameWindowAnchorItem.top anchors.topMargin: 10 color: "white" font.pixelSize: 20 text: activeLevel !== undefined ? activeLevel.levelName : "" } // load levels at runtime Loader { id: loader source: activeLevelFileName !== "" ? "../levels/" + activeLevelFileName : "" onLoaded: { // reset the score score = 0 // since we did not define a width and height in the level item itself, we are doing it here item.width = gameScene.width item.height = gameScene.height // store the loaded level as activeLevel for easier access activeLevel = item // restarts the countdown countdown = 3 } } // we connect the gameScene to the loaded level Connections { // only connect if a level is loaded, to prevent errors target: activeLevel !== undefined ? activeLevel : null // increase the score when the rectangle is clicked onRectanglePressed: { // only increase score when game is running if(gameRunning) { score++ } } } // name of the current level Text { anchors.horizontalCenter: parent.horizontalCenter anchors.top: gameScene.gameWindowAnchorItem.top anchors.topMargin: 30 color: "white" font.pixelSize: 40 text: score } // text displaying either the countdown or "tap!" Text { anchors.centerIn: parent color: "white" font.pixelSize: countdown > 0 ? 160 : 18 text: countdown > 0 ? countdown : "tap!" } // if the countdown is greater than 0, this timer is triggered every second, decreasing the countdown (until it hits 0 again) Timer { repeat: true running: countdown > 0 onTriggered: { countdown-- } } }
Sweet, the core functionality is finished. Time to get some rest? NOPE, we ain't no lazy people. We add just a little more features.
We are using the opacity
property to set the scenes visible and invisible. Since the opacity is a value of the QML type real (which is also known as float or double in other languages) within the range between 0
and 1, we can create a fade effect when switching scenes just by animating it.
All you have to do is add this to the SceneBase.qml
file:
// ... Scene { id: sceneBase // ... // every change in opacity will be done with an animation Behavior on opacity { NumberAnimation {property: "opacity"; easing.type: Easing.InOutQuad} } }
Oh boy, thats so smooooooth!
For Android users, the hardware back button is the common way to navigate backwards in applications. Luckily, the Scene already supports this with Scene::backButtonPressed.
An important thing to know is that any hardware button press only gets handled in the scene that is focused. Being displayed doesn't automatically mean that something is focused, so we got to take care of that.
This is the main reason why we set the activeScene
property of the GameWindow in our state machine in the main.qml
because it will automatically call
forceActiveFocus()
on that scene.
If we change a scene, we set the new one as activeScene
, that's all the magic.
What if we press the hardware back button in our home scene (MenuScene
)? Normally that should cause the game to be closed on Android. So let's add this, including a message box, asking the user if he really
wants to quit the game.
Add this to the MenuScene
in main.qml
// menu scene MenuScene { id: menuScene // listen to the button signals of the scene and change the state according to it onSelectLevelPressed: gameWindow.state = "selectLevel" onCreditsPressed: gameWindow.state = "credits" // the menu scene is our start scene, so if back is pressed there we ask the user if he wants to quit the application onBackButtonPressed: { NativeUtils.displayMessageBox("Really quit the game?", "", 2); } // listen to the return value of the MessageBox Connections { target: NativeUtils onMessageBoxFinished: { // only quit, if the activeScene is menuScene - the messageBox might also get opened from other scenes in your code if(accepted && window.activeScene === menuScene) Qt.quit() } } }
If the signal backPressed
gets called in the MenuScene
, we display the message box. With the Connections element we check if the
player pressed yes. In this case we close the game with Qt.quit()
.
That's it for now! If you have any questions regarding this tutorial, don't hesitate to visit the support forums.
Visit Felgo Games Examples and Demos to gain more information about game creation with Felgo and to see the source code of existing apps in the app stores.