Evgenii Legotckoi
Evgenii LegotckoiOct. 5, 2015, 8:58 p.m.

GameDev on Qt - Tutorial 3. Destroying opponents

In two previous articles, where we taught the hero to track the cursor and shoot towards the goal , it's time to add the targets to the gameand start  to destroy them. The destruction of the target will occur when the targets have completed life. In this case each of the target will be a random number of points of life and every bullet will cause a random amount of damage. Also, each of the target will be life bar, which will decrease on damage.

Destruction based on CallBack function

To implement this algorithm, create a Target target class, and add the ability to call CallBack function in Bullet class, which will be implemented in the class of the main application window and will cause damage to targets.


target.h

The header must declare a function that will do damage to the target. And also declare two variables that will be responsible for the health targets. The first variable - this will be the current health, and the second variable - this will be the maximum health. When health is over, there is the destruction of the target.

#ifndef TARGET_H
#define TARGET_H

#include <QObject>
#include <QGraphicsItem>
#include <QPainter>

class Target : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit Target(QObject *parent = 0);
    ~Target();
    /* Application function damage, damage to the value passed as argument to the function
     * */
    void hit(int damage);

signals:

public slots:

protected:
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

private:
    int health;         // Current stock of the target health
    int maxHealth;      // The maximum stock pf the target health
};

#endif // TARGET_H

target.cpp

The class constructor installs the health parameters. The damage to the application function decreases health passed in the function value. And as soon as the health drops to zero or below, the target is destroyed.

#include "target.h"

static int randomBetween(int low, int high)
{
    return (qrand() % ((high + 1) - low) + low);
}

Target::Target(QObject *parent) :
    QObject(parent), QGraphicsItem()
{
    health = randomBetween(1,15);   // Set random value health
    maxHealth = health;             // Set a maximum health equals to the current health
}

Target::~Target()
{

}

QRectF Target::boundingRect() const
{
    return QRectF(-20,-20,40,40);  
}

void Target::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    /* Draw green square
     * */
    painter->setPen(Qt::black);
    painter->setBrush(Qt::green);
    painter->drawRect(-20,-10,40,30);

    /* We draw a strip of life commensurate with 
     * respect to the current health of your maximum health
     * */
    painter->setPen(Qt::NoPen);
    painter->setBrush(Qt::red);
    painter->drawRect(-20,-20, (int) 40*health/maxHealth,3);

    Q_UNUSED(option);
    Q_UNUSED(widget);
}

void Target::hit(int damage)
{
    health -= damage;   // Reduce the target's health
    this->update(QRectF(-20,-20,40,40));    // Redraw target
    // If health is over, it will initiate the death of the target
    if(health <= 0) this->deleteLater();
}

bullet.h

The bullet from the last class the lesson is necessary to add classifieds signature CallBack function, and the function of the installation CallBack function.

public:
    // Setting CallBack function
    void setCallbackFunc(void (*func) (QGraphicsItem * item));

private:
    // CallBack Function
    void (*callbackFunc)(QGraphicsItem * item);

bullet.cpp

It is also necessary to modify slotTimerBullet function, which will be to search for all objects that come across a bullet. If the bullet came across the object, then we destroy the bullet and call the CallBack function which will cause damage to the target when the bullet came across a target.

Also we realize setCallbackFunc function, which will install a function pointer in the CallBack function .

void Bullet::slotTimerBullet()
{
    setPos(mapToParent(0, -10));

    /* Checks for whether the bullet came across any element on the graphic scene. 
     * To do this, we define a small area in front of the bullet, which will search for items
     * */
    QList<QGraphicsItem *> foundItems = scene()->items(QPolygonF()
                                                           << mapToScene(0, 0)
                                                           << mapToScene(-1, -1)
                                                           << mapToScene(1, -1));
    /* Then we check all the elements. 
     * One of them will be the bullet itself and the hero - 
     * do not do anything with them. A call the CallBack feature
     * */
    foreach (QGraphicsItem *item, foundItems) {
        if (item == this || item == hero)
            continue;
        callbackFunc(item);     
        this->deleteLater();    
    }

    if(this->x() < 0){
        this->deleteLater();
    }
    if(this->x() > 500){
        this->deleteLater();
    }

    if(this->y() < 0){
        this->deleteLater();
    }
    if(this->y() > 500){
        this->deleteLater();
    }
}

void Bullet::setCallbackFunc(void (*func)(QGraphicsItem *))
{
    callbackFunc = func;
}

widget.h

In the header of the main window class you need to add a timer to create an ad targets, as well as slots for processing this timer, which will create and target. Also we declare a static list of targets, which we will check to hit a bullet. A hit test will produce in the CallBack slotHitTarget function. The argument will be transferred to a graphic object, which ran the bullet.

private:
    QTimer *timerTarget;        // Timer for creating targets
    static QList<QGraphicsItem *> targets; 

    static void slotHitTarget(QGraphicsItem *item); 

private slots:
    void slotCreateTarget();

widget.cpp

#include "widget.h"
#include "ui_widget.h"

static int randomBetween(int low, int high)
{
    return (qrand() % ((high + 1) - low) + low);
}

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    /* Source code from previous articles
     * */

    timerTarget = new QTimer();
    connect(timerTarget, &QTimer::timeout, this, &Widget::slotCreateTarget);
    timerTarget->start(1500);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::slotBullet(QPointF start, QPointF end)
{
    /* Source code from previous articles
     * */
}

void Widget::slotCreateTarget()
{
    Target *target = new Target();  // Create target
    scene->addItem(target);         // Set target into the scene with random position
    target->setPos(qrand() % ((500 - 40 + 1) - 40) + 40,
                  qrand() % ((500 - 40 + 1) - 40) + 40);
    target->setZValue(-1);          
    targets.append(target);        
}

void Widget::slotHitTarget(QGraphicsItem *item)
{
    /* If we get signal from Bullet
     * Loop through the full list of objectives and causes occasional damage
     * */
    foreach (QGraphicsItem *targ, targets) {
        if(targ == item){
            // Cast object from the list in the Target class
            Target *t = qgraphicsitem_cast <Target *> (targ);
            t->hit(randomBetween(1,3)); // deal damage
        }
    }

}

QList<QGraphicsItem *> Widget::targets; 

Result

As a result, you on the playing field will be randomly placed target with a random size health and issued the protagonist bullets will gradually destroy them.

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!

A
  • Jan. 6, 2017, 2:58 a.m.

Почему то у меня, на строке вызова callback функции, вылетает программа. ((( п.с. Qt 5.7 MSVC 64

A
  • Jan. 6, 2017, 3:04 a.m.

e:\work\qt_work\gamedev\les_2\mygame2\bullet.cpp:85: ошибка: Exception at 0x7ff6d35d80b3, code: 0xc0000005: read access violation at: 0x0, flags=0x0 (first chance) e:\work\qt_work\gamedev\les_2\mygame2\bullet.cpp:85: ошибка: Exception at 0x7ff6d35d80b3, code: 0xc0000005: read access violation at: 0x0, flags=0x0 Вот такой exeption вылетает при нажатии мышки (то есть при стрельбе)

A
  • Jan. 6, 2017, 3:22 a.m.

Нашел в чем проблема. Вообще в этих уроках, лучше выкладывать весь код каждого файла, а не только ту часть, которая отличается от предыдущего урока. В определении отличий кода между уроками, Вы делаете ошибки)))) Вот и приходится самому думать, чего еще не хватает в коде=)

A
  • Jan. 6, 2017, 3:25 a.m.

И так, главный вопрос по этому уроку у меня такой: зачем мы используем callback-функцию, вместо слота+сигнала?

Evgenii Legotckoi
  • Jan. 6, 2017, 9:44 a.m.

Наверное, это прозвучит странно, но просто так. Чтобы сделать через callback-функцию . Чтобы показать один из возможных вариантов работы в Qt/C++. Случается же так, что те, кто изучает Qt и даже работают с ним некоторое время, не имеют представления о callback-функциях.

S
  • July 9, 2017, 1:14 a.m.
  1. /* После чего проверяем все элементы.
  2. * Одними из них будут сама Пуля и Герой - с ними ничего не делаем.
  3. * А с остальными вызываем CallBack функцию
  4. * */
  5. foreach (QGraphicsItem *item, foundItems) {
  6. if (item == this || item == hero)
  7. continue;
  8. callbackFunc(item); // Вызываем CallBack функцию
  9. this->deleteLater(); // Уничтожаем пулю
  10. }
Проработав Ваш код появился вопрос:  кто такой - hero - в данном исполнителе. Не подключали вроде в предыдущих уроках класс треугольника...решил вопрос с помощью RTTI.
S
  • July 9, 2017, 1:17 a.m.

И еще для чего нужна конструкция: foreach если есть эквивалент for( : )

S
  • July 9, 2017, 1:29 a.m.

И к верхнему посту AndreyHudz не надо весь код выкладывать, а лучше сделать преднамеренные ошибки.

Evgenii Legotckoi
  • July 9, 2017, 2:04 a.m.

да, foreach - это Qt-шный макрос, который эквивалентен for, который появился позже чем foreach.
Я длительное время работал с foreach, пока не решил заняться плотнее новыми стандартами C++ :-)

Evgenii Legotckoi
  • July 9, 2017, 2:07 a.m.

Поэтому в пятом уроке есть исходники всего проекта )))).

Вообще, все эти материалы были не предыдущей версии сайта, которая на WordPress. Во время переноса мог что-то потерять.
Д
  • Oct. 25, 2018, 8:10 p.m.

Не подскажите в чем проблема. При нажатии аварийно выходит из программы. Не могу додуматься.

Evgenii Legotckoi
  • Oct. 26, 2018, 3:17 a.m.

Скачайте просто из пятого урока полностью готовый пример.

VB
  • June 25, 2020, 10:35 p.m.

А откуда взялся hero? Никак не могу понят секрет его происхождения...

Evgenii Legotckoi
  • June 26, 2020, 12:36 a.m.

Сам уже не помню. 5 лет назад говнокодил это )) В 5-й части есть полный код, думаю, что там найдёте ))

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. 8, 2024, 6:43 p.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, 10:30 a.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, 8:38 a.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. 18, 2023, 9:01 p.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, 11:57 a.m.
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
BlinCT
BlinCTDec. 27, 2023, 8:57 a.m.
Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
Дмитрий
ДмитрийJan. 10, 2024, 4:18 a.m.
Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
Evgenii Legotckoi
Evgenii LegotckoiDec. 12, 2023, 6:48 a.m.
Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

Follow us in social networks