Evgenii Legotckoi
Evgenii Legotckoi22 сентября 2015 г. 12:36

Как написать игру на Qt - Урок 4. Враг - смысл в выживании

Продолжаем тему того, как написать игру на Qt. После того, как в прошлых статьях была создана Муха, которая поедает яблоки, настало время создать ей врага. А Враг Мухи , как известно, Паук . Создание игровых персонажей, которые будут участвовать в непосредственной жизни Вашего главного героя - это не только отрисовка анимации действий и передвижения, а также логика реакций на воздействия игрока, но и искусственный интеллект, в соответствии с логикой которого будет определятся поведение игрового персонажа. Таким образом, мы добавляем в игру новый смысл, не только съесть как можно больше яблок, но и выжить любой ценой.

Определим поведение Паука в данной версии игры. Что же он должен делать? Да самое обычное из всех действий - охотиться на Муху , просто гоняться за ней по игровому полю.

Также добавим в игру кнопку для запуска игрового процесса, и паузу, и самое главное, что добавим - это Game Over.

Враг мухи в структуре проекта

Как и в случае с Мухой в структуру проекта добавляется дополнительный класс, который будет отвечать за объект, которым является Паук .

  • spider.h - заголовочный файл класса, отвечающего за Паука
  • spider.cpp - файл исходных кодов, отвечающий за Паука

spider.h

Отличие данного файла от заголовочного файла мухи заключается в том, что в нём объявлен игровой таймер, который отвечает за поведение Паука , то есть враг Мухи тактируется не от таймера в ядре игры, а от собственного внутреннего таймера. Также при инициализации паука, в него закладывается его цель, то есть Муха , за которой он неустанно следует. В данном случае искусственный интеллект примитивен до безобразия, но большего на данный момент и не требуется.

#ifndef SPIDER_H
#define SPIDER_H

#include <QObject>
#include <QGraphicsItem>
#include <QGraphicsScene>
#include <QPainter>
#include <QTimer>
#include <QDebug>

class Spider : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit Spider(QGraphicsItem * target, QObject *parent = 0);
    ~Spider();
    void pause();   // Сигнал для инициализации паузы

signals:
    void signalCheckGameOver();  // Сигнал на вызов состояния Game Over

public slots:

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

private:
    qreal angle;        // Угол поворота графического объекта
    int steps;          // Номер положения ножек паука
    int countForSteps;  // Счетчик для изменения полоэения ножек
    QTimer      *timer;     // Внутренний таймер паука, по которому инициализируется его движение
    QGraphicsItem * target; // Цель паука, данный объект приравнивается объекту Мухи

private slots:
    void slotGameTimer();   // Слот игрового таймера паука
};

#endif // SPIDER_H

spider.cpp

Исходный код Паука аналогичен исходному коду Мухи , с тем отличием, что в игровом Слоте Паука отслеживается положение Мухи на игровом поле, и Паук разворачивается в сторону Мухи и ползёт за ней. А как только враг мухи натыкается на какой-нибудь из объектов на графической сцене, то он производит проверку, является ли этот объект Мухой , если да, то инициализируется процедура Game Over .

#include "spider.h"
#include "math.h"

static const double Pi = 3.14159265358979323846264338327950288419717;
static double TwoPi = 2.0 * Pi;

static qreal normalizeAngle(qreal angle)
{
    while (angle < 0)
        angle += TwoPi;
    while (angle > TwoPi)
        angle -= TwoPi;
    return angle;
}

Spider::Spider(QGraphicsItem *target, QObject *parent) :
    QObject(parent), QGraphicsItem()
{
    angle = 0;      // Задаём угол поворота графического объекта
    steps = 0;      // Задаём стартовое положение ножек мухи
    countForSteps = 0;      // Счётчик для отсчета тиков таймера, при которых мы нажимали на кнопки
    setRotation(angle);     // Устанавливаем угол поворота графического объекта

    this->target = target;  // Устанавливаем цель паука

    timer = new QTimer();   // Инициализируем игровой таймер паука
    // подключаем сигнал таймера к игровому слоту паука
    connect(timer, &QTimer::timeout, this, &Spider::slotGameTimer);
    timer->start(15);       // Запускаем таймер
}

Spider::~Spider()
{

}

QRectF Spider::boundingRect() const
{
    return QRectF(-40,-50,80,100);
}

void Spider::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    // Рисуем ножки, без ножек паук не догонит муху
    painter->setPen(QPen(Qt::black, 2));
    if(steps == 0){     // Первое положение ножек
        // Left 1
        painter->drawLine(-24,-45,-28,-35);
        painter->drawLine(-28,-35,-22,-10);
        painter->drawLine(-22,-10,0,0);
        // Right 1
        painter->drawLine(24,-45,28,-35);
        painter->drawLine(28,-35,22,-10);
        painter->drawLine(22,-10,0,0);

        // Left 2
        painter->drawLine(-35,-38,-30,-18);
        painter->drawLine(-30,-18,-25,-3);
        painter->drawLine(-25,-3,0,0);
        // Right 2
        painter->drawLine(35,-38,30,-18);
        painter->drawLine(30,-18,25,-3);
        painter->drawLine(25,-3,0,0);

        // Left 3
        painter->drawLine(-35,38,-30,18);
        painter->drawLine(-30,18,-25,3);
        painter->drawLine(-25,3,0,0);
        // Right 3
        painter->drawLine(35,38,30,18);
        painter->drawLine(30,18,25,3);
        painter->drawLine(25,3,0,0);

        // Left 4
        painter->drawLine(-24,45,-28,35);
        painter->drawLine(-28,35,-22,10);
        painter->drawLine(-22,10,0,0);
        // Right 4
        painter->drawLine(24,45,28,35);
        painter->drawLine(28,35,22,10);
        painter->drawLine(22,10,0,0);
    } else if (steps == 1){     // Второе положение ножек
        // Left 1
        painter->drawLine(-23,-40,-24,-30);
        painter->drawLine(-24,-30,-19,-9);
        painter->drawLine(-19,-9,0,0);
        // Right 1
        painter->drawLine(20,-50,23,-40);
        painter->drawLine(23,-40,15,-12);
        painter->drawLine(15,-12,0,0);

        // Left 2
        painter->drawLine(-30,-35,-27,-24);
        painter->drawLine(-27,-24,-23,-5);
        painter->drawLine(-23,-5,0,0);
        // Right 2
        painter->drawLine(40,-27,35,-10);
        painter->drawLine(35,-10,28,-1);
        painter->drawLine(28,-1,0,0);

        // Left 3
        painter->drawLine(-40,27,-35,10);
        painter->drawLine(-35,10,-28,1);
        painter->drawLine(-28,1,0,0);
        // Right 3
        painter->drawLine(30,35,27,24);
        painter->drawLine(27,24,23,5);
        painter->drawLine(23,5,0,0);

        // Left 4
        painter->drawLine(-20,50,-27,30);
        painter->drawLine(-27,30,-20,12);
        painter->drawLine(-20,12,0,0);
        // Right 4
        painter->drawLine(23,40,24,30);
        painter->drawLine(24,30,19,9);
        painter->drawLine(19,9,0,0);
    } else if (steps == 2){     // Третье положение ножек
        // Left 1
        painter->drawLine(-20,-50,-23,-40);
        painter->drawLine(-23,-40,-15,-12);
        painter->drawLine(-15,-12,0,0);
        // Right 1
        painter->drawLine(23,-40,24,-30);
        painter->drawLine(24,-30,19,-9);
        painter->drawLine(19,-9,0,0);

        // Left 2
        painter->drawLine(-40,-27,-35,-10);
        painter->drawLine(-35,-10,-28,-1);
        painter->drawLine(-28,-1,0,0);
        // Right 2
        painter->drawLine(30,-35,27,-24);
        painter->drawLine(27,-24,23,-5);
        painter->drawLine(23,-5,0,0);

        // Left 3
        painter->drawLine(-30,35,-27,24);
        painter->drawLine(-27,24,-23,5);
        painter->drawLine(-23,5,0,0);
        // Right 3
        painter->drawLine(40,27,35,10);
        painter->drawLine(35,10,28,1);
        painter->drawLine(28,1,0,0);

        // Left 4
        painter->drawLine(-23,40,-24,30);
        painter->drawLine(-24,30,-19,9);
        painter->drawLine(-19,9,0,0);
        // Right 4
        painter->drawLine(20,50,27,30);
        painter->drawLine(27,30,20,12);
        painter->drawLine(20,12,0,0);
    }

    painter->setPen(QPen(Qt::black, 1));
    // Левое Жвало
    QPainterPath path1(QPointF(0, -20));
    path1.cubicTo(0, -20, -5, -25, -3, -35);
    path1.cubicTo(-3,-35,-15,-25,-8,-17);
    path1.cubicTo(-8,-17,-5,15,0,-20 );
    painter->setBrush(Qt::black);
    painter->drawPath(path1);

    // Правое Жвало
    QPainterPath path2(QPointF(0, -20));
    path2.cubicTo(0, -20, 5, -25, 3, -35);
    path2.cubicTo(3,-35,15,-25,8,-17);
    path2.cubicTo(8,-17,5,15,0,-20 );
    painter->setBrush(Qt::black);
    painter->drawPath(path2);

    // Голова
    painter->setBrush(QColor(146, 115, 40, 255));
    painter->drawEllipse(-10,-25,20,15);
    // Тушка
    painter->drawEllipse(-15, -15, 30, 30);
    // Жопка
    painter->drawEllipse(-20, 0, 40,50);
    painter->setPen(QPen(Qt::white,3));
    painter->drawLine(-10,25,10,25);
    painter->drawLine(0,35,0,15);
    // Левое глазище
    painter->setPen(QPen(Qt::black,1));
    painter->setBrush(Qt::red);
    painter->drawEllipse(-8,-23,6,8);
    // Правое глазище
    painter->setBrush(Qt::red);
    painter->drawEllipse(2,-23,6,8);

    Q_UNUSED(option);
    Q_UNUSED(widget);
}

void Spider::slotGameTimer()
{
    // Определяем расстояние до Мухи
    QLineF lineToTarget(QPointF(0, 0), mapFromItem(target, 0, 0));
    // Угол поворота в направлении к Мухе
    qreal angleToTarget = ::acos(lineToTarget.dx() / lineToTarget.length());
    if (lineToTarget.dy() < 0)
        angleToTarget = TwoPi - angleToTarget;
    angleToTarget = normalizeAngle((Pi - angleToTarget) + Pi / 2);

    /* В Зависимости от того, слева или справа находится Муха от Паука,
     * устанавливаем направление поворота паука в данном тике таймера
     * Скорость разворота зависит от угла, на который необходимо повернуться пауку
     * */
    if (angleToTarget > 0 && angleToTarget < Pi) {
        // Rotate left
        if(angleToTarget > Pi / 5){
            angle = -15;
        } else if(angleToTarget > Pi / 10){
            angle = -5;
        } else {
            angle = -1;
        }
    } else if (angleToTarget <= TwoPi && angleToTarget > (TwoPi - Pi)) {
        // Rotate right
        if(angleToTarget < (TwoPi - Pi / 5)){
            angle = 15;
        } else if(angleToTarget < (TwoPi - Pi / 10)){
            angle = 5;
        } else {
            angle = 1;
        }
    } else if(angleToTarget == 0) {
        angle = 0;
    }

    setRotation(rotation() + angle); // Разворачиваемся

    // Бежим в сторону мухи
    if(lineToTarget.length() >= 40){
        setPos(mapToParent(0, -(qrand() % ((4 + 1) - 1) + 1)));

        // Двигаем ножками, Dance, dance, Spidy !!!
        countForSteps++;
        if(countForSteps == 6){
            steps = 1;
            update(QRectF(-40,-50,80,100));
        } else if (countForSteps == 12){
            steps = 0;
            update(QRectF(-40,-50,80,100));
        } else if (countForSteps == 18){
            steps = 2;
            update(QRectF(-40,-50,80,100));
        } else if (countForSteps == 24) {
            steps = 0;
            update(QRectF(-40,-50,80,100));
            countForSteps = 0;
        }
    }

    /* Производим проверку на то, наткнулся ли паук на какой-нибудь
     * элемент на графической сцене.
     * Для этого определяем небольшую область перед пауком,
     * в которой будем искать элементы
     * */
    QList<QGraphicsItem *> foundItems = scene()->items(QPolygonF()
                                                           << mapToScene(0, 0)
                                                           << mapToScene(-2, -2)
                                                           << mapToScene(2, -2));
    /* После чего проверяем все элементы.
     * Один из них будет сам Паук - с ним ничего не делаем.
     * А с остальными высылаем сигнал в ядро игры
     * */
    foreach (QGraphicsItem *item, foundItems) {
        if (item == this)
            continue;
        if(item == target){
            emit signalCheckGameOver();
        }
    }

    /* Проверка выхода за границы поля
     * Если объект выходит за заданные границы, то возвращаем его назад
     * */
    if(this->x() - 10 < -250){
        this->setX(-240);       // слева
    }
    if(this->x() + 10 > 250){
        this->setX(240);        // справа
    }

    if(this->y() - 10 < -250){
        this->setY(-240);       // сверху
    }
    if(this->y() + 10 > 250){
        this->setY(240);        // снизу
    }
}

/* Функция паузы, отвечает за включение и отключение паузы
 * */
void Spider::pause()
{
    if(timer->isActive()){
        timer->stop();
    } else {
        timer->start(15);
    }
}

widget.h

В заголовочном файле ядра приложения необходимо определить объект, который отвечает за Паука, переменную состояния игры и Горячую клавишу паузы. А также слоты для обработки запуска игры, паузы и процедуры Game Over .

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QShortcut>
#include <QDebug>
#include <QTimer>
#include <QMessageBox>

#include <triangle.h>
#include <apple.h>
#include <spider.h>

#define GAME_STOPED 0
#define GAME_STARTED 1

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget      *ui;
    QGraphicsScene  *scene;     /// Объявляем графическую сцену
    Triangle        *triangle;  /// и треугольник
    QTimer          *timer;     /** Объявляем игровой таймер, благодаря которому
                                 * будет производиться изменения положения объекта на сцене
                                 * При воздействии на него клавишами клавиатуры
                                 * */
    QTimer          *timerCreateApple;  /// Таймер для периодического создания яблок в игре

    QList<QGraphicsItem *> apples;  /// Список со всеми яблоками, присутствующими в игре
    double count;   /// Переменная, которая хранит счёт игре

    Spider          *spider;        // Объект Паука

    QShortcut       *pauseKey;      // Горячая клавиша, отвечающая за паузу в игре
    int             gameState;      /* Переменная, которая хранит состояние игры.
                                     * То есть, если игра запущена, то статус будет GAME_STARTED,
                                     * в противном случае GAME_STOPED
                                     * */

private slots:
    /// Слот для удаления яблок если Муха наткнулась на это яблоко
    void slotDeleteApple(QGraphicsItem * item);
    void slotCreateApple();     /// Слот для создания яблок, срабатывает по таймеру

    void on_pushButton_clicked();               // Слот для запуска игры
    void slotGameOver();                        // Слот инициализации Game Over
    void slotPause();                           // Слот для обработки паузы
};

#endif // WIDGET_H

widget.cpp

По сравнению с программным кодом, который был в предыдущих уроках, с данным файлом в этом уроке необходимо основательно поработать. Поскольку игра, стартует по нажатию кнопки pushButton, то и программный код инициализации объектов и запуска таймеров необходимо вынести в слот, которому передаётся сигнал от кнопки. Также возникает необходимость реализовать функцию паузы в игре, по которой все игровые таймеры останавливаются и объекты не могут передвигаться или производить иных действий. А в слоте, который отвечает за Game Over необходимо правильно обработать удаление всех объектов с игровой сцены.

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

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->resize(600,640);          /// Задаем размеры виджета, то есть окна
    this->setFixedSize(600,640);    /// Фиксируем размеры виджета

    scene = new QGraphicsScene();   /// Инициализируем графическую сцену

    ui->graphicsView->setScene(scene);  /// Устанавливаем графическую сцену в graphicsView
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);    /// Устанавливаем сглаживание
    ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по вертикали
    ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по горизонтали

    scene->setSceneRect(-250,-250,500,500); /// Устанавливаем область графической сцены

    timer = new QTimer();
    timerCreateApple = new QTimer();

    gameState = GAME_STOPED;

    pauseKey = new QShortcut(this);
    pauseKey->setKey(Qt::Key_Pause);
    connect(pauseKey, &QShortcut::activated, this, &Widget::slotPause);


}

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

void Widget::slotDeleteApple(QGraphicsItem *item)
{
    /* Получив сигнал от Мухи
     * Перебираем весь список яблок и удаляем найденное яблоко
     * */
    foreach (QGraphicsItem *apple, apples) {
        if(apple == item){
            scene->removeItem(apple);   // Удаляем со сцены
            apples.removeOne(apple);     // Удаляем из списка
            delete apple;               // Вообще удаляем
            ui->lcdNumber->display(count++);    /* Увеличиваем счёт на единицу
                                                 * и отображаем на дисплее
                                                 * */
        }
    }
}

void Widget::slotCreateApple()
{
    Apple *apple = new Apple(); // Создаём яблоко
    scene->addItem(apple);      // Помещаем его в сцену со случайной позицией
    apple->setPos((qrand() % (251)) * ((qrand()%2 == 1)?1:-1),
                  (qrand() % (251)) * ((qrand()%2 == 1)?1:-1));
    apple->setZValue(-1);       /* Помещаем яблоко ниже Мухи, то есть Муха
                                 * на сцене будет выше яблок
                                 * */
    apples.append(apple);       // Добавляем Муху в Список
}

void Widget::on_pushButton_clicked()
{
    count = 0;
    ui->lcdNumber->display(count);
    triangle = new Triangle();      /// Инициализируем муху

    scene->addItem(triangle);       /// Добавляем на сцену треугольник
    triangle->setPos(0,0);          /// Устанавливаем треугольник в центр сцены

    spider = new Spider(triangle);  // Инициализируем паука
    scene->addItem(spider);         // Добавляем паука на сцену
    spider->setPos(180,180);        // Устанавливаем позицию паука

    /* Подключаем сигнал от паука на проверку состояния GameOver
     * */
    connect(spider, &Spider::signalCheckGameOver, this, &Widget::slotGameOver);

    /** Инициализируем таймер и вызываем слот обработки сигнала таймера
     * у Треугольника 100 раз в секунду.
     * Управляя скоростью отсчётов, соответственно управляем скоростью
     * изменения состояния графической сцены
     * */
    connect(timer, &QTimer::timeout, triangle, &Triangle::slotGameTimer);
    timer->start(1000 / 100);

    /** Раз в секунду отсылаем сигнал на создание яблока в игре
     * */
    connect(timerCreateApple, &QTimer::timeout, this, &Widget::slotCreateApple);
    timerCreateApple->start(1000);

    /** Подключаем сигнал от Мухи, в котором передаются Объекты, на которые
     * наткнулась Муха
     * */
    connect(triangle, &Triangle::signalCheckItem, this, &Widget::slotDeleteApple);

    ui->pushButton->setEnabled(false);

    gameState = GAME_STARTED;
}

void Widget::slotGameOver()
{
    /* Если игра окончена
     * Отключаем все таймеры
     * */
    timer->stop();
    timerCreateApple->stop();
    QMessageBox::warning(this,
                         "Game Over",
                         "Мои соболезнования, но Вас только что слопали");
    /* Отключаем все сигналы от слотов
     * */
    disconnect(timerCreateApple, &QTimer::timeout, this, &Widget::slotCreateApple);
    disconnect(triangle, &Triangle::signalCheckItem, this, &Widget::slotDeleteApple);
    disconnect(spider, &Spider::signalCheckGameOver, this, &Widget::slotGameOver);
    /* И удаляем все объекты со сцены
     * */
    spider->deleteLater();
    triangle->deleteLater();

    foreach (QGraphicsItem *apple, apples) {
        scene->removeItem(apple);   // Удаляем со сцены
        apples.removeOne(apple);    // Удаляем из списка
        delete apple;               // Вообще удаляем
    }
    /* Активируем кнопку старта игры
     * */
    ui->pushButton->setEnabled(true);

    gameState = GAME_STOPED; // Устанавливаем состояние игры в GAME_STOPED
}

void Widget::slotPause()
{
    /* Выполняем проверку на состояние игры,
     * если игра не запущена, то игнорируем Паузу.
     * В противном случае или запускаем, или останавливаем все таймеры
     * */
    if(gameState == GAME_STARTED){
        if(timer->isActive()){
            timer->stop();
            timerCreateApple->stop();
            spider->pause();
        } else {
            timer->start(1000/100);
            timerCreateApple->start(1000);
            spider->pause();
        }
    }
}

Итог

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

Также в видеоуроке по данной статье даны дополнительные комментарии и продемонстрирована работа игры.

Полный список статей данного цикла:

Видеоурок

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

v
  • 9 мая 2017 г. 9:27

Здравствуй у меня опять проблема как решить? In member function 'void Widget::on_pushButton_clicked()': ошибка: 'class Ui::Widget' has no member named 'pushButton' ui->pushButton->setEnabled(false); : In member function 'void Widget::slotGameOver()': ошибка: 'class Ui::Widget' has no member named 'pushButton' ui->pushButton->setEnabled(true); скрин http://priscree.ru/img/a9de07f8d2a5a0.jpg ^ ^

v
  • 9 мая 2017 г. 9:46

вставляю кнопку вообще 10 ошибок не определена ссылка на паука и тд

Evgenii Legotckoi
  • 10 мая 2017 г. 2:06

Добавьте через графический дизайнер кнопку в widget.ui и проследите, чтобы название кнопки было pushButton

v
  • 10 мая 2017 г. 4:40

добавил кнопку все равно много ошибок вот скрины http://priscree.ru/img/e8e0d04f9e232c.jpg http://priscree.ru/img/3fb040824e8665.jpg

Evgenii Legotckoi
  • 10 мая 2017 г. 5:21

ошибки в vtable... Это moc файлы попортились. Нужно удалить build сборку и пересобрать, и если не поможет, то создать новый проект и переписать в него код. Иначе никак.

v
  • 10 мая 2017 г. 7:00

хорошо попробую переписать все.как напишу отпишусь)

v
  • 10 мая 2017 г. 8:58

все заработало спасибо еще вопрос у нас препод просит чтобы мы сделали так.чтобы можно было сохранять результаты это возможно ?

Evgenii Legotckoi
  • 10 мая 2017 г. 9:20

Конечно, возможно. Можно сохранять в файл. Можно сохранять в базу данных. Можно даже в реестр писать с помощью QSettings . Мне больше всего нравится база данных для таких целей. По окончании игры можно добавлять результат в базу данных. Также можно добавить кнопку, которая бы открывала окно с результатами.

v
  • 10 мая 2017 г. 9:46

а как это сделать ? можете помочь если не сложно конечно и есть время

Evgenii Legotckoi
  • 10 мая 2017 г. 10:46

Значит так. Просто писать код за вас я не буду, но подсказать и направить на нужный путь - это без проблем.

Поэтому -> В предыдущем сообщении я дал ссылку на статью с базой данных. Изучите её. Изучите, как добавлять записи в базу данных. Там же показано, как отобразить записи в таблице. А потом попытайтесь по окончании игры сделать добавление строк в базу данных. В коде есть место, где по окончании игры вызывается диалог. Это происходит в слоте slotGameOver . Вот в нём можно сделать добавление записей в базу данных. Также можете добавить кнопку в окно игры, по нажатию которой можно будет вызвать диалог, в котором как раз и будете показывать рекорды. Если есть затруднения с пониманием сигналов и слотов, то изучите следующую статью .

M
  • 25 июня 2018 г. 5:13

Здравствуйте,
Подскажите, пжлст, как работает этот код :

  1. QLineF lineToTarget(QPointF(0, 0), mapFromItem(target, 0, 0));  // Проводим линию от паука к мухе
  2. qreal angleToTarget = ::acos(lineToTarget.dx() / lineToTarget.length()); // Находим угол. Например 120 гр( 2пи/3 )
  3. if (lineToTarget.dy() < 0)                                             //Если y отрицательный зачем отнимать?
  4. angleToTarget = TwoPi - angleToTarget;                 // ??
  5. angleToTarget = normalizeAngle((Pi - angleToTarget) + Pi / 2); // Тут мы убираем намотку по 2пи. Но зачем добавлять 90 гр?
    Самое непонятное - это 5 -ая строчка, зачем добавлять 90 градусов?

M
  • 25 июня 2018 г. 5:25

не 90 на 45, ошибся

Evgenii Legotckoi
  • 25 июня 2018 г. 5:34

Там неправильный подсчёт был по направлению и полный бардак был с поведением, эти 45 градусов исправляли ситуацию. Точную причину уже совсем не помню.

А вообще все эти расчёты довольно тяжелы для процессора, я подобрал более лёгкий вариант со скалярными векторами. Но статью ещё пока не недописал к сожалению (она пока в разработке).

РР
  • 4 июня 2019 г. 11:28
  • (ред.)

Здравствуйте! Почему может быть такая ошибка: враг висит в углу, колеблется в нём, но не двигается? По логике код такой же, но вместо орисовки моделей использую спрайты. Со спрайтом "мухи" всё хорошо, а вот "паук" отказывается вести себя нормально. Подозреваю, что ошибка может быть здесь (это код, который идёт вместо отрисовки):

void Crocodillo::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->drawPixmap(-10,-10, *spriteImageCroco, currentFrameCroco, 0, 96,95);
    Q_UNUSED(option);
    Q_UNUSED(widget);
}

Или же ошибка где-то в управлении "паука", но там код вообще неизменный. (в Spider.cpp, void Spider...)

Evgenii Legotckoi
  • 5 июня 2019 г. 3:44

Добрый день.

Дело тут явно не в методе paint, скорее всего всё-таки есть какая-то ошибка в другом месте. Обычно такое может быть в районе метода slotGamerTimer

РР
  • 5 июня 2019 г. 20:27
  • (ред.)

Спасибо! На самом деле ошибка оказалась от невнимательности - просто пропустила подключение движения в сторону модели. Теперь всё работает.

Если вам не сложно, могли бы вы, пожалуйста, объяснить, за что отвечают параметры в скобках тут: setPos(mapToParent(0, -(qrand() % ((2 + 1) - 1) + 1)))?
Нашла только такое, не много о чём говорит: (qrand() % ((high + 1) - low) + low). Экспериментально кое-что выяснила, но хотелось бы знать точно)
А ещё вот тут, когда генерировали бананы: banana->setPos((qrand() % (251)) * ((qrand()%2 == 1)?1:-1),
(qrand() % (251)) * ((qrand()%2 == 1)?1:-1));

А так, благодарю за указку на slotGameTimer!

П.С.: я не очень умею пока читать документацию( поэтому прошу помощи у вас, чтобы разобраться с этими параметрами

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
SH
  • Sak Hax
  • 25 апреля 2024 г. 19:00

C++ - Тест 001. Первая программа и типы данных

  • Результат:33баллов,
  • Очки рейтинга-10
г
  • ги
  • 23 апреля 2024 г. 20:51

C++ - Тест 005. Структуры и Классы

  • Результат:41баллов,
  • Очки рейтинга-8
l
  • laei
  • 23 апреля 2024 г. 14:19

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:10баллов,
  • Очки рейтинга-10
Последние комментарии
k
kmssr8 февраля 2024 г. 23:43
Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко5 февраля 2024 г. 6:50
Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 декабря 2023 г. 15:30
Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 декабря 2023 г. 13:38
Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 декабря 2023 г. 2:01
Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Сейчас обсуждают на форуме
G
Gar22 апреля 2024 г. 10:46
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil Academics20 апреля 2024 г. 12:45
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasov14 апреля 2024 г. 11:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 апреля 2024 г. 7:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex4 апреля 2024 г. 9:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Следите за нами в социальных сетях