Evgenii Legotckoi
Evgenii Legotckoi14. Juli 2016 05:57

Game on QML - Lektion 1. Spielarena und dynamische Objekte

Nach den ersten Erfahrungen beim Schreiben eines Spiels in Qt für Android möchte ich diese Erfahrung teilen und vorschlagen, gemeinsam ein einfaches Spiel im „Kill the Mole“-Stil zu schreiben. Dies ist ein Spiel, bei dem Sie Zeit haben müssen, um die Maulwürfe zu treffen, die aus ihren Löchern klettern, aber wenn man bedenkt, dass dies ein vereinfachtes Spiel sein wird, verwenden wir anstelle von Maulwürfen runde Ziele, die auf dem Spielfeld erscheinen. Als Spielfeld wird ein Raster von 6 mal 6 Zellen verwendet. Einige spezielle Objekte wie GridLayout werden jedoch nicht zum Erstellen des Felds verwendet. Auf dem Spielfeld wird das Raster aus der Anzahl der Reihen, Spalten und der Seitenlänge der quadratischen Zelle gebildet. Daten zur Zellfülle werden in einem zweidimensionalen Array gespeichert, das in der Javascript-Komponente gebildet wird (vergessen Sie nicht, dass QML eine deklarative JSON-ähnliche Sprache mit Javascript-Unterstützung ist).

Projektstruktur

Das Projekt besteht aus folgenden Dateien:

  • TargetGame.pro - Projektprofil;
  • deployment.pri - Projektdatei erstellen und bereitstellen;
  • main.cpp - Datei mit der Hauptfunktion des Projekts;
  • main.qml - die Hauptdatei der QML-Schicht mit dem Objekt des Hauptanwendungsfensters;
  • Target.qml - QML-Datei mit einer Beschreibung des Zielobjekts;
  • Target.png - das Erscheinungsbild des Ziels ist ein PNG-Bild;
  • GameArea.qml - Spielarena mit einem Gitter zum Platzieren von Zielen;
  • logic.js - Datei mit Javascript-Spiellogik.

Lassen Sie uns beim Erstellen des Projekts nur den Inhalt der Dateien untersuchen, die sich vom Standardinhalt unterscheiden.


main.qml

Das Hauptanwendungsfenster enthält ein Objekt vom Typ GameArea, das in GameArea.qml. beschrieben wird. Da die Breite und Höhe der Spielarena abhängig von der Größe des Rasters und der Rasterzellen automatisch berechnet werden, werden wir einfach platzieren die Spielarena in der Mitte des Anwendungsfensters.

Eine Besonderheit dieser Datei ist die Aufnahme der Datei logic.js als Typ Logic , die auf die Spiellogik reagiert und in dieser Datei nach dem Erstellen des Objekts das Hauptfenster der Anwendung enthält der Spielarena übergeben wir einen Zeiger auf die Spielarena an den Kern der Spiellogik, um uns den aktuellen Zustand des Spielfeldes zu merken und die Erstinitialisierung des Spielfeldes sowie des Spielfeldarrays durchzuführen , die dem Inhalt der Rasterzellen entsprechen. Dazu wird die Funktion newGameState(), aufgerufen und ihr die ID der Spielarena als Argument übergeben. In diesem Tutorial verfolgen wir nicht den Status des Spiels, d. h. ob das Spiel läuft oder angehalten wurde, sodass der Arena-Spiel-Timer sofort nach dem Start der Anwendung gestartet wird.

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
    }

    // По окончании создания окна инициализируем состояние игрового поля
    Component.onCompleted: {
        Logic.newGameState(gameArea)
    }
}

GameArea.qml

Da der logische Kern in Javascript in allen Aspekten des Spiels vorkommt, fügen wir diese Datei auch hier ein.

Die Spielarena ist ein Rechteck mit den Eigenschaften vordefinierter Zeilen und Spalten sowie der Größe einer Seite der Zelle. Abhängig von diesen Eigenschaften werden Breite und Höhe der Spielfläche berechnet. Auch in der Spielarena gibt es einen Timer, bei dessen Betätigung Ziele erstellt werden.

Die Erstellung von Zielen wird begleitet von der Überprüfung der Verfügbarkeit einer zufällig ausgewählten Zelle. Die Zellenauswahl erfolgt durch Auswahl einer zufälligen Zeile und Spalte, indem eine zufällige Ganzzahl im ausgewählten Bereich vom Minimum bis zum Maximum einschließlich mithilfe der Funktion getRandomRound(min, max) erhalten wird, die auch in beschrieben wird. logic.js.

Die Funktion checkEmptyField(row, column) prüft, ob ein Objekt in der angegebenen Zelle vorhanden ist, und wenn die Zelle leer ist, wird mithilfe der Funktion createTarget(parent, row, column) ein Ziel erstellt.**

import QtQuick 2.7
import "logic.js" as Logic

Rectangle {
    id: grid
    property int squareSize: 64 // Размер ячейки игровой сетки
    property int rows: 6        // Количество строк сетки
    property int cols: 6        // Количество колонок сетки

    width: cols * squareSize    // Ширина и высота игровой арены
    height: rows * squareSize   // Будет зависеть от количества колонок, строк и размера одной ячейки

    // Таймер для создания мишеней
    Timer {
        id: createTargetsTimer
        interval: 350; running: true; repeat: true;
        // Раз в секунду выбираем случайную ячейку,
        // проверяем наличие мишени в ней, и если ячейка пустая,
        // то создаём мишень
        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

Bevor wir den Inhalt des logischen Javascript-Kerns des Spiels untersuchen, wollen wir die Beschreibung des Zielobjekts untersuchen.

Die Zielverhaltenslogik ist wie folgt. Einmal erstellt, sollte das Ziel nach einer zufälligen Zeitspanne verschwinden. Und nicht einfach verschwinden, das heißt, indem sie den Grad der Transparenz ändern, sondern sich selbst zerstören. Dazu wird die Methode destroy(), verwendet, die auf das Root-Objekt mit der ID: root angewendet wird. Sie können auch die Funktion destroyTarget(row, column) im Javascript-Kern des Spiels sehen. Diese Funktion wird verwendet, um eine Zelle eines zweidimensionalen Gitterinformationsarrays zu löschen.

Da die Größe der Zelle 64 Pixel und die Größe des Ziels 56 Pixel beträgt, bestimmen wir mit einfachen Berechnungen die Position des Ziels auf dem Spielfeld, abhängig von der Spalte und Zeile, die es einnehmen soll.

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"  // Загружаем изображение мишени

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

    // Когда изображение станет прозрачным. мы уничтожим сам объект
    onOpacityChanged: {
        if (opacity == 0.0) {
            Logic.destroyTarget(row, col)
            root.destroy()
        }
    }

    // Задаём поведение анимации свойства прозрачности объекта
    Behavior on opacity { PropertyAnimation { duration: 250 } }
}

logic.js

Diese Datei enthält eine Deklaration .pragma-Bibliothek *. *

.pragma library

Dies geschieht aufgrund der Notwendigkeit, auf den Status des Spiels ( var gameState ) von überall zugreifen zu können, wo diese Datei in der QML-Schicht enthalten ist. Tatsächlich werden Variablen zu gemeinsam genutzten Ressourcen für verschiedene Objekte im Spiel. Und die wichtigste Ressource ist gameState (auch bekannt als game arena GameArea ). Tatsache ist, dass, wenn wir direkt per id von verschiedenen Objekten, die statisch in der Spielarena deklariert sind, oder in einer Datei, in der die Arena selbst deklariert ist, auf die Spielarena zugreifen können, dann in dynamischen Ressourcen, wie in * Ziel .qml , diese Methode funktioniert bei uns nicht. Dazu wird gameState aus logic.js * verwendet, mit dem Sie den Zustand der Spielarena unabhängig davon überprüfen können, ob das Objekt statisch deklariert ist (mit Zustand meine ich, ob das Spiel läuft oder pausiert, was in den folgenden Artikeln berücksichtigt wird).

Wenden wir uns nun dem Inhalt der Datei logic.js zu. Hier gibt es zwei höchst interessante Punkte:

  1. Dies ist die Erstellung eines zweidimensionalen Arrays in Javascript, das als Informationsmodell über die im Raster enthaltenen Objekte und als Überprüfung auf die Existenz eines Objekts in einer Zelle dient.
  2. Dies ist die Erstellung dynamischer Ziele.

Wenn mit dem ersten aus dem Code alles klar genug ist, werde ich ein paar Worte zum zweiten sagen. Um ein Ziel dynamisch zu erstellen, wird in diesem Fall die Blank-Komponente verwendet, die aus der Datei Target.qml. erzeugt wird, außerdem wird nur ein solches Blank benötigt, selbst für viele solcher Elemente des gleichen Typs das Spiel.

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

Und die Erstellung des Objekts selbst in der Spielarena wird in der folgenden Funktion unten ausgeführt.

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

In unserem Fall reicht es aus, ein Objekt zu erstellen, indem die createObject-Methode auf den Zielkomponenten-Rohling angewendet wird, wobei das übergeordnete Objekt angegeben wird, d. h. das Objekt, in dem sich das Ziel befinden wird (in diesem Fall ist es die Spielarena ) und listet die Parameter auf, die beim Erstellen des Objekts festgelegt werden müssen, in diesem Fall In diesem Fall ist dies die Zeile und Spalte, in der sich das Ziel befinden wird.

Vollständige Dateiliste

// Объявляем, как библиотеку, чтобы иметь доступ
// к разделяемым ресурсам, например состоянию игры
.pragma library

var gameState       // Локальное объявление состояния игры
                    // в нашем случае это будет игровая область gameArea
function getGameState() { return gameState; }

var gameField;      // Игровое поле, игровая сетка
// Создаём заготовку для мишеней
var targetComponent = Qt.createComponent("Target.qml");

// Инициализируем новое состояние игры
function newGameState(gameArea)
{
    gameState = gameArea;
    // Игровой сеткой будет служить двумерный массив,
    // в котором будем сохранять информацию о наличии в ячейках объектов
    gameField = create2DArray(gameState.rows, gameState.cols);
    return gameState;
}
// Функция получения случайного целого числа
// в диапазоне чисел включительно
function getRandomRound(min, max)
{
    return Math.round(Math.random() * (max - min) + min);
}

// Создаём мишень из компонента заготовки
function createTarget(parent, row, column)
{
    var target = targetComponent.createObject(parent, {"row": row, "col": column})
    gameField[row][column] = target;
}

// Мишень удаляется из массива сетки
function destroyTarget(row, column)
{
    gameField[row][column] = null;
}

// Функция создания двумерного массива сетки
function create2DArray(rows, columns)
{
  var arr = [];

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

  return arr;
}

// Проверка на предмет наличия какого либо объекта в выбранной ячейке
function checkEmptyField(row, column)
{
    if (gameField[row][column] == null) {
        return true;
    } else {
        return false;
    }
}

Insgesamt

Als Ergebnis erhalten wir ein Programm mit einem Spielfeld von 6 x 6, in dem beim Start verschwindende Ziele generiert werden.

Quelle herunterladen von QML-Spielbeispiel von GitHub

Die ganze Unterrichtsreihe

Videoanleitung

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 10:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken