Обнаружение коллизий QT между 2 QGraphicsPixmapItems

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

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

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

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

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

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

Размер игрового поля составляет 500х600 единиц (ширина х высота), поэтому точка, из которой стреляет капля воды, равна (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, и мои попытки обнаружить столкновение вручную не очень хорошо работали.

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

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

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

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

Решение

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

  • Избегайте использования следующей инструкции, используйте сигналы, которые являются одним из самых мощных элементов 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

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

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

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]