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);
    }
}

віджет.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
  • 09 травня 2017 р. 09: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
  • 09 травня 2017 р. 09:46

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

Evgenii Legotckoi
  • 10 травня 2017 р. 02:06

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

v
  • 10 травня 2017 р. 04:40

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

Evgenii Legotckoi
  • 10 травня 2017 р. 05:21

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

v
  • 10 травня 2017 р. 07:00

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

v
  • 10 травня 2017 р. 08:58

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

Evgenii Legotckoi
  • 10 травня 2017 р. 09:20

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

v
  • 10 травня 2017 р. 09:46

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

Evgenii Legotckoi
  • 10 травня 2017 р. 10:46

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

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

M
  • 25 червня 2018 р. 05: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 р. 05:25

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

Evgenii Legotckoi
  • 25 червня 2018 р. 05:34

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

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

РР
  • 04 червня 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
  • 05 червня 2019 р. 03:44

Добрый день.

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

РР
  • 05 червня 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!

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

Коментарі

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

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

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

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

  • Результат:80бали,
  • Рейтинг балів4
m
  • molni99
  • 26 жовтня 2024 р. 01:29

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

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 11:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 жовтня 2024 р. 14:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 08:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 07:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 11:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
Evgenii Legotckoi
Evgenii Legotckoi24 червня 2024 р. 15:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 листопада 2024 р. 06:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject04 червня 2022 р. 03:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Слідкуйте за нами в соціальних мережах