Evgenii Legotckoi
Evgenii LegotckoiJuly 14, 2016, 3:57 p.m.

Game on QML - Lesson 1. Games arena and dynamic objects

After the first experience of writing games on Qt for Android, I want to share this experience together and offer to write a simple game in the style of "kill the mole." This is a game in which you need to have time to hit the moles, which climbs out of their holes, but considering that this is a simplified game, instead of moles using the circular target, which will appear on the playing field. As the playing field will use the net 6 6 cells. But to create a field will not be used to some special object of type GridLayout . In the game board will be formed of a grid of rows, columns and the side length of a square cell. Data on occupancy cells to be stored in a two-dimensional array, which will be formed in javascript component (to forget that QML - a declarative JSON-like language with javascript enabled).

Project structure

The project consists of the following files:

  • TargetGame.pro - the profile of the project;
  • deployment.pri - build file and project deploya;
  • main.cpp - the file with the main function of the project;
  • main.qml - basic QML-layer file with the object of the main application window;
  • Target.qml - QML file with the description of the target object;
  • Target.png - the appearance of the target pattern is png;
  • GameArea.qml - gaming arena with the grid to accommodate the targets;
  • logic.js - file with javascript logic games.

We will study the contents of only those files that are different from the default content when creating the project.


main.qml

The main application window is an object of type GameArea , which is described in GameArea.qml . Since the width and height of the playing area is calculated automatically depending on the mesh size and mesh, we simply arrange the gaming arena in the middle of the application window.

A distinctive aspect of this file is to connect logic.js file as Logic type that will meet with the logic of the game and in the file, after the creation of the object of the main application window with the gaming arena, we will give a pointer to the gaming arena in the core logic of the game to remember the current state of the playing field and carry the primary initialization of the playing field, as well as the playing field of the array, which will be responsible the content of grid cells. This is done by calling function newGameState() , and transfer to it as an argument id gaming arena. In this tutorial, we do not track the state of the game, that is, if the game is started or stopped, so the gaming arena timer start immediately after the application starts.

import QtQuick 2.7
import QtQuick.Controls 1.5
import "logic.js" as Logic

ApplicationWindow {
    visible: true
    width: 420
    height: 480
    title: qsTr("Target")

    GameArea {
        id: gameArea
        anchors.centerIn: parent
    }

    // After creating a window initialize the state of the playing field
    Component.onCompleted: {
        Logic.newGameState(gameArea)
    }
}

GameArea.qml

Since the core logic in javascript figures we have in all aspects of the game, then connect the file here.

Games Arena is a rectangle with properties from are preset rows and columns, as well as the size of one side of the cell. Depending on these properties and the calculated width and height of the game arena. Also in the gaming arena, there is a timer which is triggered by the target will be created.

Creating targets accompanied by checking the availability of the randomly selected cell. The choice of the cell is carried out by selecting random rows and columns, by obtaining a random integer in the selected range from minimum to maximum, inclusive using getRandomRound(min, max) function, which is also described in logic.js.

checkEmptyField(row, column) function checks whether there is any object in a given cell, and if the cell is empty, then the target is created using createTarget(parent, row, column) function.

import QtQuick 2.7
import "logic.js" as Logic

Rectangle {
    id: grid
    property int squareSize: 64 // The size of the game grid cell
    property int rows: 6        // The number of grid lines
    property int cols: 6        // The number of grid columns

    width: cols * squareSize    // The width and height of the playing area
    height: rows * squareSize   // It will depend on the number of columns, rows, and the size of one cell

    // Timer to create a target
    Timer {
        id: createTargetsTimer
        interval: 350; running: true; repeat: true;
        // Every second, choose a random cell,
        // check the presence of a target in it, and if the cell is empty,
        // then create a target
        onTriggered: {
            var targetRow = Logic.getRandomRound(0, rows - 1);
            var targetColumns = Logic.getRandomRound(0, cols - 1);
            if (Logic.checkEmptyField(targetRow, targetColumns)) {
                Logic.createTarget(grid ,targetRow, targetColumns)
            }
        }
    }
}

Target.qml

Before studying the contents of the logical core javascript game, read the description of the target object.

The logic of the behavior of the target Is following. Once created, the target should disappear after a random period of time. And not just disappear, that is, changing the level of transparency, and self-destruct. For this is the destroy() method, which will be applied to the root of the object, its id: root. You can also see destroyTarget(row, column) function in javascript core games. This function is used to clear the cell array of two-dimensional information grid.

Since cell size is 64 pixels, and the target size of 56 pixels, then using some simple calculations, we determine the position of the target on the playing field, depending on the columns and rows that it should occupy.

import QtQuick 2.7
import "logic.js" as Logic

Image {
    id: root
    property int row: 0
    property int col: 0

    width: 56
    height: 56
    x: (col * (width + 8)) + 4
    y: (row * (height + 8)) + 4

    source: "Target.png"  // Load the target image

    Timer {
        interval: Logic.getRandomRound(350, 1500); running: true; repeat: false
        onTriggered: root.opacity = 0.0
    }

    // When the image is clear. we will destroy the object itself
    onOpacityChanged: {
        if (opacity == 0.0) {
            Logic.destroyTarget(row, col)
            root.destroy()
        }
    }

    // Set the behavior of the animation properties of the object transparency
    Behavior on opacity { PropertyAnimation { duration: 250 } }
}

logic.js

This file has define .pragma library .

.pragma library

This is due to the need to be able to access the games of ( var gameState ) from any location where the attached file in QML layer. In fact, the variables are shared resources for the various objects in the game. And the most important resource is gameState (aka play arena GameArea ). The fact is that if we can refer to the playing arena directly id of various objects which are declared statically in the game arena, or in the file where the arena declared itself, the dynamic resources, such as in Target.qml , have such a the method does not work. For this and used gameState of logic.js , which allows you to check the condition of the playing area regardless of whether the object is declared statically (under the condition I understand, whether the game or put on pause, as will be discussed in the following articles in the running).

Now let us turn to the content of logic.js file. It features two of the most interesting points:

  1. This is creating a two-dimensional array to javascript, which serves as an information model of the objects contained in the grid, and checking for the existence of the object in the cell.
  2. It is the creation of dynamic targets.

If the first all is clear enough from the code, then about the second to say a few words. To dynamically create a target, in this case, a component of the workpiece, which is created from Target.qml file. Moreover, such a workpiece needs only one set even for the same elements of the game.

var targetComponent = Qt.createComponent("Target.qml");

A creation of the object directly on the playing arena is carried out below the next function.

function createTarget(parent, row, column)
{
    var target = targetComponent.createObject(parent, {"row": row, "col": column})
    gameField[row][column] = target;
}

In this case it is sufficient to create an object, using createObject method for harvesting a target component indicating the parent object, i.e. the object which is placed a target (in this case it will be the game arena) and listing the parameters that must be set when an object, in this case is the row and column, which will be located a target.

Full file listing

// We declare as a library to have access to shared resources, such as state of game
.pragma library

var gameState       // Local state of the game
                    // in our case it will be a play area - gameArea
function getGameState() { return gameState; }

var gameField;      // The playing field, the game grid
// Create a template for the targets
var targetComponent = Qt.createComponent("Target.qml");

// Initialize a new state of the game
function newGameState(gameArea)
{
    gameState = gameArea;
    // The game grid will serve a two-dimensional array 
    // that will store information about the presence of objects in the cells
    gameField = create2DArray(gameState.rows, gameState.cols);
    return gameState;
}
// Function get a random integer in the range of numbers inclusive
function getRandomRound(min, max)
{
    return Math.round(Math.random() * (max - min) + min);
}

// Create the target component from the template
function createTarget(parent, row, column)
{
    var target = targetComponent.createObject(parent, {"row": row, "col": column})
    gameField[row][column] = target;
}

// The target is removed from the grid array
function destroyTarget(row, column)
{
    gameField[row][column] = null;
}

// The option to create a two-dimensional array of grid
function create2DArray(rows, columns)
{
  var arr = [];

  for (var i=0;i<rows;i++) {
     arr[i] = [];
  }

  return arr;
}

// Checking for the presence of any object in the selected cell
function checkEmptyField(row, column)
{
    if (gameField[row][column] == null) {
        return true;
    } else {
        return false;
    }
}

Conclusion

As a result, we get the program to the board 6 by 6, which will be generated when you start disappearing targets.

Download the source of Game sample on QML from GitHub

The entire series of lessons

Video

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

Comments

Only authorized users can post comments.
Please, Log in or Sign up
B

C++ - Test 002. Constants

  • Result:16points,
  • Rating points-10
B

C++ - Test 001. The first program and data types

  • Result:46points,
  • Rating points-6
FL

C++ - Test 006. Enumerations

  • Result:80points,
  • Rating points4
Last comments
k
kmssrFeb. 9, 2024, 5:43 a.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 9:30 p.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 7:38 p.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 19, 2023, 8:01 a.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
AC
Alexandru CodreanuJan. 19, 2024, 10:57 p.m.
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
BlinCT
BlinCTDec. 27, 2023, 7:57 p.m.
Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
Дмитрий
ДмитрийJan. 10, 2024, 3:18 p.m.
Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
Evgenii Legotckoi
Evgenii LegotckoiDec. 12, 2023, 5:48 p.m.
Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

Follow us in social networks