Ссылка на проект
Интересные части должны быть в функции «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() ;
^
Я также попытался добавить аргументы, но ничто из того, что я имел в виду, не помогло.
В этом ответе я собираюсь дать вам несколько рекомендаций, которые вы используете для реализации решения:
Избегайте использования следующей инструкции, используйте сигналы, которые являются одним из самых мощных элементов 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
Также для реализации анимации используйте мой предыдущий ответ
Полный и функциональный код можно найти по следующему ссылка на сайт.
Других решений пока нет …