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

Communication between QML Objects

Introduction

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.

Communicating between Entities

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!

Where to go from here

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:

  1. Getting Started with Felgo and Qt Creator
  2. How to make a simple BalloonPop game with Felgo
  3. How to Make a Flappy Bird Game with Felgo

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.

Useful QML Resources

Finally we gathered some very useful links from the Qt documentation, which have a closer look at the topics that we just covered:

Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded