This tutorial covers the possible ways to implement the communication between the QML objects in your application. While it's mostly up to the developer to choose which way you prefer, we will try to highlight the possibly good or bad consequences.
The setup: We got a little shooter game, where the player runs around and shoots at monsters. Now we are at the point where our player needs to tell the monster "Hey, I just shot you, your are dead!"
Given there is an entity in our game, a Monster.qml
, that looks something like this:
import Felgo 4.0 import QtQuick 2.0 EntityBase { // some monster stuff }
Also we got a Player.qml
:
import Felgo 4.0 import QtQuick 2.0 EntityBase { // some player stuff function shootMonster() { } }
And a GameScene.qml
with only one monster, declared statically like this:
import Felgo 4.0 import QtQuick 2.0 Scene { id: gameScene Player { id: player } Monster{ id: monster } // much other game scene stuff }
At the moment we only want to hide the the monster if it is shot, so why not just do something like this in the Player.qml
:
import Felgo 4.0 import QtQuick 2.0 EntityBase { // some player stuff function shootMonster() { monster.visible = false } }
Well, this works. Since the Player
and the Monster
are instantiated in the same QML file, they can access each others id
. But only changing the visibility seems like a pretty bad death
animation. So this most probably will grow to several other lines of code, so better move that logic to the monster itself. Also, when you are coming from an OOP background, you might get goose bumps anyway when you see a
property being changed directly from outside the object.
We are giving the Monster.qml
a function which the player can call instead:
import Felgo 4.0 import QtQuick 2.0 EntityBase { // some monster stuff function getShot() { visible = false } }
Player.qml
import Felgo 4.0 import QtQuick 2.0 EntityBase { // some player stuff function shootMonster() { monster.getShot() } }
Turns out a game with only one monster is not the most fun, at least that's what I heard! We need several monsters, so referring directly to the id
of our single monster won't work. If you are using the EntityManager to dynamically create monsters at runtime every created monster has a unique EntityBase::entityId. With this entityId
you could get a reference to the entity that you want to shoot, and call its getShot() function.
This would change the Player.qml
to something like this:
import Felgo 4.0 import QtQuick 2.0 EntityBase { // some player stuff function shootMonster(entityId) { var entity = entityManager.getEntityById(entityId) entity.getShot() } }
Pretty okay, I guess, but shooting a monster might also increase your score or trigger some other actions. And in a later development stage, the list of actions that we need to trigger might grow and grow. Wouldn't it be
nice if the Player.qml
just shouts "Jo guys, I shot something, you know what to do!", and can take a rest after his glorious accomplishment?
That's where signals come in very handy: GameScene.qml
import Felgo 4.0 import QtQuick 2.0 Scene { id: gameScene signal playerShotMonster(string entityId) Player { id: player } // monsters are created dynamically at runtime now //Monster{ // id: monster //} // much other game scene stuff }
Player.qml
import Felgo 4.0 import QtQuick 2.0 EntityBase { // some player stuff function shootMonster(entityId) { gameScene.playerShotMonster(entityId) } }
Monster.qml
import Felgo 4.0 import QtQuick 2.0 EntityBase { id: monster // some monster stuff Connection { target: gameScene onPlayerShotMonster: { // compare the monsters entityId with the on that is passed from the signal if(monster.entityId == entityId) { getShot() } } } function getShot() { visible = false } }
Now every other object, e.g. your score logic, can also connect to this signal and perform their actions if a monster got shot. The Player.qml
doesn't need to know anything about it. And also the monster only
knows that it's time to say goodbye.
Of course if you have a very large number of monsters, connecting each monster to the signal might be a bit overkill. In this case having some kind of manager that connects to it instead and searches for the right monster to shoot will be better.
A possibly bad side effect is, that your application may get a little hard to debug if you are not keeping track of all the connections between your objects, so use it wisely!
Also have a look at these other short QML Language Tutorials:
Go through these essential tutorials that help you learning QML & Felgo, by making simple games:
Visit Felgo Games Examples and Demos to gain more information about game creation with Felgo and to learn from the source code of existing apps in the app stores.
Finally we gathered some very useful links from the Qt documentation, which have a closer look at the topics that we just covered: