Обнаружение столкновения QT между 2 QGraphicsPixmapItems - PullRequest
0 голосов
/ 02 мая 2018

Ссылка на проект Интересные части должны быть в функции "launchSplash" gameengine.cpp и splashanimation.cpp

Игра создает пузырьки случайным образом в приемлемых условиях. Работа игрока состоит в том, чтобы стрелять пузырьками с каплями воды. Капли воды запускаются из средней нижней части игрового экрана. Сетки используются только для отладки и в дальнейшем исчезнут, но это облегчает визуализацию областей.

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

Я пытаюсь создать обнаружение столкновений для основной игры с пузырьковыми шутерами, но я не уверен, как можно аккуратно обнаружить столкновение.

игровое поле выглядит примерно так игровое поле , капли воды стреляют из средней нижней части экрана в направлении курсора.

В конце концов у меня будет рикошет с капли воды со стен, но в данный момент я не могу понять, как обнаружить столкновения.

Игровое поле имеет размер 500x600 единиц (ширина х высота), поэтому точка попадания капли воды равна (250, 600).

Когда стреляет капля воды, я использую

void GameEngine::launchSplash(int clickX, int clickY){
// <my long method of calculating the coordinates for the water drop's path>

    graphicalGameBoard_.animateSplash(graphicalGameBoard_.width()/2, graphicalGameBoard_.height(), xDestination, yDestination);
}

, где xDestination и yDestionation - место, где капля воды закончится, если она будет перемещаться беспрепятственно. Капля воды либо закончится на x = 0 / x = 500 и / или y = 0 / y = 600, но я не думаю, что это актуально.

Пузырьки добавляются на игровое поле с

board_.clear();

for(int y = 0; y < HEIGHT; ++y)
{
    std::vector< std::shared_ptr<Bubble> > row;
    for(int x = 0; x < WIDTH; ++x)
    {
        std::shared_ptr<Bubble> newBubble = nullptr;

        // There will be bubbles only in the top 3/4 of the board only in the middle
        // (i.e. not in the first two and last two columns).
        if (y < HEIGHT*3/4 && x > 1 && x < WIDTH-2)
        {
            // Generate random numbers using the enumearation type defined in
            // file bubble.hh. The value COLOR_COUNT is used to represent no bubble.
            std::uniform_int_distribution<int> distribution(RED,COLOR_COUNT);

            // If you want no empty squares, change the initialization to:
            // std::uniform_int_distribution<int> distribution(RED,BLUE);

            Color color = static_cast<Color>(distribution(randomEngine_));
            if(color != COLOR_COUNT) {
                newBubble = std::make_shared<Bubble>(x, y, color);
            }
        }
        row.push_back(newBubble);
    }
    board_.push_back(row);
}

в gameengine.cpp, который рисует доску и каплю воды, стреляющую в пузырьки.

Капли воды нарисованы с помощью

SplashAnimation::SplashAnimation(GameBoard* scene, QPointF startPoint, QPointF endPoint):
    QVariantAnimation(0),
    scene_(scene),
    item_()
{
    scene_->addItem(&item_);

    // The animation runs for the given duration and moves the splash
    // smoothly from startpoint to endpoint.
    setDuration(2000);
    setKeyValueAt(0, QPointF(startPoint));
    setKeyValueAt(1, QPointF(endPoint));
}

Я подумал, что есть два способа сделать это: либо встроенное обнаружение коллизий QT, либо выполнить отдельный расчет. Я не был в состоянии работать с QT Collision, и мои попытки обнаружить столкновение вручную не увенчались успехом.

У меня уже есть функция обнаружения пузырьковых объектов в определенных ячейках, но она находится в столбце / строке вместо необработанных координат (500x600).

std::shared_ptr<Bubble> GameEngine::bubbleAt(int x, int y) const
{
    if (0 <= x and x < WIDTH and 0 <= y and y < HEIGHT){
        return board_.at(y).at(x);
    }
    else{
        return nullptr;
    }
}

Edit: в настоящее время я пытаюсь работать над чем-то вроде этого, но я боюсь, что это будет немного тяжело для игры, так как она повторяет так много (или нет?):

for (int i = 0; i<600;++i)
{
     xfract = (xDestination+250.0)/600.0;
     yfract = (600.0-yDestination)/600.0;
     xStep = xfract*i;
     yStep = yfract*i;
     if (xStep >= 50){
        thisX = xStep/50-5;
     }else{
         thisX=5;
     }
     if (yStep >= 50){
         thisY = 11-yStep/50 + 1;
     }else{
         thisY = 11;
     }
     thisX = abs(thisX);
    if (bubbleAt(thisX, thisY)!=nullptr){
        endX = xfract*i;
        endY = yfract*i;
        i = 600;
       std::cout << "collision at x: "<<thisX<< " y: "<<thisY<<std::endl;
       std::cout << "collision at x: "<<xStep<< " y: "<<yStep<<std::endl;
       std::cout << graphicalGameBoard_.width() << " " << graphicalGameBoard_.height()<<std::endl;
       removeBubble(thisX, thisY);
       graphicalGameBoard_.removeBubble(thisX, thisY);
       endY = 600-endY;
    }
}


graphicalGameBoard_.animateSplash(graphicalGameBoard_.width()/2, graphicalGameBoard_.height(), endX, endY);

Я пытаюсь разбить шаги на маленькие фракции и проверить, есть ли на текущем шаге пузырь, пока капля воды не достигнет конца или не найдет пузырь.

Это работает на моей единственной стороне с точки зрения вычисления, но анимация не в порядке, и обнаружение столкновений правой стороны (x> 250) по какой-то причине вообще не работает ( он ударяет, казалось бы, случайные пузыри в невозможных местах на правой стороне).

Редактировать ^ 2: Вот что я пробовал, чтобы работать с фактическим обнаружением столкновений QT:

В файле splashanimation.cpp, где капля воды нарисована с использованием

SplashAnimation::SplashAnimation(GameBoard* scene, QPointF startPoint, QPointF endPoint):
    QVariantAnimation(0),
    scene_(scene),
    item_()
{
    scene_->addItem(&item_);


    // The animation runs for the given duration and moves the splash
    // smoothly from startpoint to endpoint.
    setDuration(2000);
    setKeyValueAt(0, QPointF(startPoint));
    setKeyValueAt(1, QPointF(endPoint));   
}

SplashAnimation::~SplashAnimation()
{
    scene_->removeItem(&item_);
}

void SplashAnimation::updateCurrentValue(QVariant const& value)
{
    item_.setPos(value.toPointF());
}

где сцена - QGraphicsScene, а родительский элемент this содержит пузырьки.

Я пробовал это как на gameboard.cpp (который является родительским для пузырьков и анимации), так и на splash.cpp (который оживляет каплю воды), но оба дают мне одинаковые ошибки компиляции.

    QGraphicsItem::QGraphicsItem();

т

ошибка: невозможно вызвать конструктор? QGraphicsItem :: QGraphicsItem? прямо [-fpermissive] QGraphicsItem :: QGraphicsItem (); ^

QList<QGraphicsItem *> list = collidingItems() ;

т error: ?collidingItems? was not declared in this scope QList<QGraphicsItem *> list = collidingItems() ; ^

    QList<QGraphicsItem *> list = QGraphicsItem::collidingItems() ;

т error: cannot call member function ?QList<QGraphicsItem*> QGraphicsItem::collidingItems(Qt::ItemSelectionMode) const? without object QList<QGraphicsItem *> list = QGraphicsItem::collidingItems() ; ^

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

1 Ответ

0 голосов
/ 03 мая 2018

В этом ответе я дам вам несколько рекомендаций, которые вы используете для реализации решения:

  • Избегайте использования следующей инструкции, используйте сигналы, которые являются одним из самых мощных элементов Qt и которые выполняет цикл обработки событий.

    while (animations_.state() == QAbstractAnimation::Running)
    {
        QCoreApplication::processEvents(QEventLoop::AllEvents);
    }
    
  • QGraphicsScene работает с координатами, которые поддерживают плавающую точку, поэтому координаты сцены обрабатываются с помощью QPointF.

  • Используя вышеизложенное, если вы собираетесь отправлять информацию о точке, используйте QPointF вместо int, int в сигналах.

  • Используйте методы, которые предоставляет Qt, например следующие:

    if (0 <= clickPosition.x() and clickPosition.x() <= GRID_SIDE*WIDTH and
        0 <= clickPosition.y() and clickPosition.y() <= GRID_SIDE*HEIGHT)
    

Может быть уменьшено до следующего:

if(sceneRect().contains(event->scenePos()))

Преимущество этой реализации в том, что она более читаема

Я не понимаю, почему вы не можете реализовать collidingItems, возможно, это конфигурация вашего .pro,

Используйте следующее для добавления графического модуля, ядра и виджетов

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

Также для реализации анимации используйте мой предыдущий ответ

Полный и функциональный код можно найти по следующей ссылке .

...