Evgenii Legotckoi
22 вересня 2015 р. 22:36

Як створити гру за допомогою Qt - Урок 4. Ворог – значення у виживанні

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

Визначимо поведінку Павука у даній версії гри. Що ж він має робити? Та найпростіше з усіх дій - полювати на Муху, просто ганятися за нею по ігровому полю.

Також додамо в гру кнопку для запуску ігрового процесу, і паузу, і найголовніше, що додамо - це Game Over.

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

Як і у випадку з Мухою до структури проекту додається додатковий клас, який відповідатиме за об'єкт, яким є Павук .

  • spider.h - заголовний файл класу, що відповідає за Павука
  • spider.cpp - файл вихідних кодів, що відповідає за Павука

spider.h

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

  1. #ifndef SPIDER_H
  2. #define SPIDER_H
  3.  
  4. #include <QObject>
  5. #include <QGraphicsItem>
  6. #include <QGraphicsScene>
  7. #include <QPainter>
  8. #include <QTimer>
  9. #include <QDebug>
  10.  
  11. class Spider : public QObject, public QGraphicsItem
  12. {
  13. Q_OBJECT
  14. public:
  15. explicit Spider(QGraphicsItem * target, QObject *parent = 0);
  16. ~Spider();
  17. void pause(); // Сигнал для инициализации паузы
  18.  
  19. signals:
  20. void signalCheckGameOver(); // Сигнал на вызов состояния Game Over
  21.  
  22. public slots:
  23.  
  24. protected:
  25. QRectF boundingRect() const;
  26. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
  27.  
  28. private:
  29. qreal angle; // Угол поворота графического объекта
  30. int steps; // Номер положения ножек паука
  31. int countForSteps; // Счетчик для изменения полоэения ножек
  32. QTimer *timer; // Внутренний таймер паука, по которому инициализируется его движение
  33. QGraphicsItem * target; // Цель паука, данный объект приравнивается объекту Мухи
  34.  
  35. private slots:
  36. void slotGameTimer(); // Слот игрового таймера паука
  37. };
  38.  
  39. #endif // SPIDER_H

spider.cpp

Вихідний код Павука аналогічний вихідному коду Мухи , з тією відмінністю, що в ігровому Слоті Павука відстежується положення Мухи на ігровому полі, і Павук розгортається убік * Мухи і повзе за нею. А як тільки ворог мухи натикається на якийсь із об'єктів на графічній сцені, то він проводить перевірку, чи є цей об'єкт Мухою , якщо так, то ініціалізується процедура Game Over * .

  1. #include "spider.h"
  2. #include "math.h"
  3.  
  4. static const double Pi = 3.14159265358979323846264338327950288419717;
  5. static double TwoPi = 2.0 * Pi;
  6.  
  7. static qreal normalizeAngle(qreal angle)
  8. {
  9. while (angle < 0)
  10. angle += TwoPi;
  11. while (angle > TwoPi)
  12. angle -= TwoPi;
  13. return angle;
  14. }
  15.  
  16. Spider::Spider(QGraphicsItem *target, QObject *parent) :
  17. QObject(parent), QGraphicsItem()
  18. {
  19. angle = 0; // Задаём угол поворота графического объекта
  20. steps = 0; // Задаём стартовое положение ножек мухи
  21. countForSteps = 0; // Счётчик для отсчета тиков таймера, при которых мы нажимали на кнопки
  22. setRotation(angle); // Устанавливаем угол поворота графического объекта
  23.  
  24. this->target = target; // Устанавливаем цель паука
  25.  
  26. timer = new QTimer(); // Инициализируем игровой таймер паука
  27. // подключаем сигнал таймера к игровому слоту паука
  28. connect(timer, &QTimer::timeout, this, &Spider::slotGameTimer);
  29. timer->start(15); // Запускаем таймер
  30. }
  31.  
  32. Spider::~Spider()
  33. {
  34.  
  35. }
  36.  
  37. QRectF Spider::boundingRect() const
  38. {
  39. return QRectF(-40,-50,80,100);
  40. }
  41.  
  42. void Spider::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  43. {
  44. // Рисуем ножки, без ножек паук не догонит муху
  45. painter->setPen(QPen(Qt::black, 2));
  46. if(steps == 0){ // Первое положение ножек
  47. // Left 1
  48. painter->drawLine(-24,-45,-28,-35);
  49. painter->drawLine(-28,-35,-22,-10);
  50. painter->drawLine(-22,-10,0,0);
  51. // Right 1
  52. painter->drawLine(24,-45,28,-35);
  53. painter->drawLine(28,-35,22,-10);
  54. painter->drawLine(22,-10,0,0);
  55.  
  56. // Left 2
  57. painter->drawLine(-35,-38,-30,-18);
  58. painter->drawLine(-30,-18,-25,-3);
  59. painter->drawLine(-25,-3,0,0);
  60. // Right 2
  61. painter->drawLine(35,-38,30,-18);
  62. painter->drawLine(30,-18,25,-3);
  63. painter->drawLine(25,-3,0,0);
  64.  
  65. // Left 3
  66. painter->drawLine(-35,38,-30,18);
  67. painter->drawLine(-30,18,-25,3);
  68. painter->drawLine(-25,3,0,0);
  69. // Right 3
  70. painter->drawLine(35,38,30,18);
  71. painter->drawLine(30,18,25,3);
  72. painter->drawLine(25,3,0,0);
  73.  
  74. // Left 4
  75. painter->drawLine(-24,45,-28,35);
  76. painter->drawLine(-28,35,-22,10);
  77. painter->drawLine(-22,10,0,0);
  78. // Right 4
  79. painter->drawLine(24,45,28,35);
  80. painter->drawLine(28,35,22,10);
  81. painter->drawLine(22,10,0,0);
  82. } else if (steps == 1){ // Второе положение ножек
  83. // Left 1
  84. painter->drawLine(-23,-40,-24,-30);
  85. painter->drawLine(-24,-30,-19,-9);
  86. painter->drawLine(-19,-9,0,0);
  87. // Right 1
  88. painter->drawLine(20,-50,23,-40);
  89. painter->drawLine(23,-40,15,-12);
  90. painter->drawLine(15,-12,0,0);
  91.  
  92. // Left 2
  93. painter->drawLine(-30,-35,-27,-24);
  94. painter->drawLine(-27,-24,-23,-5);
  95. painter->drawLine(-23,-5,0,0);
  96. // Right 2
  97. painter->drawLine(40,-27,35,-10);
  98. painter->drawLine(35,-10,28,-1);
  99. painter->drawLine(28,-1,0,0);
  100.  
  101. // Left 3
  102. painter->drawLine(-40,27,-35,10);
  103. painter->drawLine(-35,10,-28,1);
  104. painter->drawLine(-28,1,0,0);
  105. // Right 3
  106. painter->drawLine(30,35,27,24);
  107. painter->drawLine(27,24,23,5);
  108. painter->drawLine(23,5,0,0);
  109.  
  110. // Left 4
  111. painter->drawLine(-20,50,-27,30);
  112. painter->drawLine(-27,30,-20,12);
  113. painter->drawLine(-20,12,0,0);
  114. // Right 4
  115. painter->drawLine(23,40,24,30);
  116. painter->drawLine(24,30,19,9);
  117. painter->drawLine(19,9,0,0);
  118. } else if (steps == 2){ // Третье положение ножек
  119. // Left 1
  120. painter->drawLine(-20,-50,-23,-40);
  121. painter->drawLine(-23,-40,-15,-12);
  122. painter->drawLine(-15,-12,0,0);
  123. // Right 1
  124. painter->drawLine(23,-40,24,-30);
  125. painter->drawLine(24,-30,19,-9);
  126. painter->drawLine(19,-9,0,0);
  127.  
  128. // Left 2
  129. painter->drawLine(-40,-27,-35,-10);
  130. painter->drawLine(-35,-10,-28,-1);
  131. painter->drawLine(-28,-1,0,0);
  132. // Right 2
  133. painter->drawLine(30,-35,27,-24);
  134. painter->drawLine(27,-24,23,-5);
  135. painter->drawLine(23,-5,0,0);
  136.  
  137. // Left 3
  138. painter->drawLine(-30,35,-27,24);
  139. painter->drawLine(-27,24,-23,5);
  140. painter->drawLine(-23,5,0,0);
  141. // Right 3
  142. painter->drawLine(40,27,35,10);
  143. painter->drawLine(35,10,28,1);
  144. painter->drawLine(28,1,0,0);
  145.  
  146. // Left 4
  147. painter->drawLine(-23,40,-24,30);
  148. painter->drawLine(-24,30,-19,9);
  149. painter->drawLine(-19,9,0,0);
  150. // Right 4
  151. painter->drawLine(20,50,27,30);
  152. painter->drawLine(27,30,20,12);
  153. painter->drawLine(20,12,0,0);
  154. }
  155.  
  156. painter->setPen(QPen(Qt::black, 1));
  157. // Левое Жвало
  158. QPainterPath path1(QPointF(0, -20));
  159. path1.cubicTo(0, -20, -5, -25, -3, -35);
  160. path1.cubicTo(-3,-35,-15,-25,-8,-17);
  161. path1.cubicTo(-8,-17,-5,15,0,-20 );
  162. painter->setBrush(Qt::black);
  163. painter->drawPath(path1);
  164.  
  165. // Правое Жвало
  166. QPainterPath path2(QPointF(0, -20));
  167. path2.cubicTo(0, -20, 5, -25, 3, -35);
  168. path2.cubicTo(3,-35,15,-25,8,-17);
  169. path2.cubicTo(8,-17,5,15,0,-20 );
  170. painter->setBrush(Qt::black);
  171. painter->drawPath(path2);
  172.  
  173. // Голова
  174. painter->setBrush(QColor(146, 115, 40, 255));
  175. painter->drawEllipse(-10,-25,20,15);
  176. // Тушка
  177. painter->drawEllipse(-15, -15, 30, 30);
  178. // Жопка
  179. painter->drawEllipse(-20, 0, 40,50);
  180. painter->setPen(QPen(Qt::white,3));
  181. painter->drawLine(-10,25,10,25);
  182. painter->drawLine(0,35,0,15);
  183. // Левое глазище
  184. painter->setPen(QPen(Qt::black,1));
  185. painter->setBrush(Qt::red);
  186. painter->drawEllipse(-8,-23,6,8);
  187. // Правое глазище
  188. painter->setBrush(Qt::red);
  189. painter->drawEllipse(2,-23,6,8);
  190.  
  191. Q_UNUSED(option);
  192. Q_UNUSED(widget);
  193. }
  194.  
  195. void Spider::slotGameTimer()
  196. {
  197. // Определяем расстояние до Мухи
  198. QLineF lineToTarget(QPointF(0, 0), mapFromItem(target, 0, 0));
  199. // Угол поворота в направлении к Мухе
  200. qreal angleToTarget = ::acos(lineToTarget.dx() / lineToTarget.length());
  201. if (lineToTarget.dy() < 0)
  202. angleToTarget = TwoPi - angleToTarget;
  203. angleToTarget = normalizeAngle((Pi - angleToTarget) + Pi / 2);
  204.  
  205. /* В Зависимости от того, слева или справа находится Муха от Паука,
  206. * устанавливаем направление поворота паука в данном тике таймера
  207. * Скорость разворота зависит от угла, на который необходимо повернуться пауку
  208. * */
  209. if (angleToTarget > 0 && angleToTarget < Pi) {
  210. // Rotate left
  211. if(angleToTarget > Pi / 5){
  212. angle = -15;
  213. } else if(angleToTarget > Pi / 10){
  214. angle = -5;
  215. } else {
  216. angle = -1;
  217. }
  218. } else if (angleToTarget <= TwoPi && angleToTarget > (TwoPi - Pi)) {
  219. // Rotate right
  220. if(angleToTarget < (TwoPi - Pi / 5)){
  221. angle = 15;
  222. } else if(angleToTarget < (TwoPi - Pi / 10)){
  223. angle = 5;
  224. } else {
  225. angle = 1;
  226. }
  227. } else if(angleToTarget == 0) {
  228. angle = 0;
  229. }
  230.  
  231. setRotation(rotation() + angle); // Разворачиваемся
  232.  
  233. // Бежим в сторону мухи
  234. if(lineToTarget.length() >= 40){
  235. setPos(mapToParent(0, -(qrand() % ((4 + 1) - 1) + 1)));
  236.  
  237. // Двигаем ножками, Dance, dance, Spidy !!!
  238. countForSteps++;
  239. if(countForSteps == 6){
  240. steps = 1;
  241. update(QRectF(-40,-50,80,100));
  242. } else if (countForSteps == 12){
  243. steps = 0;
  244. update(QRectF(-40,-50,80,100));
  245. } else if (countForSteps == 18){
  246. steps = 2;
  247. update(QRectF(-40,-50,80,100));
  248. } else if (countForSteps == 24) {
  249. steps = 0;
  250. update(QRectF(-40,-50,80,100));
  251. countForSteps = 0;
  252. }
  253. }
  254.  
  255. /* Производим проверку на то, наткнулся ли паук на какой-нибудь
  256. * элемент на графической сцене.
  257. * Для этого определяем небольшую область перед пауком,
  258. * в которой будем искать элементы
  259. * */
  260. QList<QGraphicsItem *> foundItems = scene()->items(QPolygonF()
  261. << mapToScene(0, 0)
  262. << mapToScene(-2, -2)
  263. << mapToScene(2, -2));
  264. /* После чего проверяем все элементы.
  265. * Один из них будет сам Паук - с ним ничего не делаем.
  266. * А с остальными высылаем сигнал в ядро игры
  267. * */
  268. foreach (QGraphicsItem *item, foundItems) {
  269. if (item == this)
  270. continue;
  271. if(item == target){
  272. emit signalCheckGameOver();
  273. }
  274. }
  275.  
  276. /* Проверка выхода за границы поля
  277. * Если объект выходит за заданные границы, то возвращаем его назад
  278. * */
  279. if(this->x() - 10 < -250){
  280. this->setX(-240); // слева
  281. }
  282. if(this->x() + 10 > 250){
  283. this->setX(240); // справа
  284. }
  285.  
  286. if(this->y() - 10 < -250){
  287. this->setY(-240); // сверху
  288. }
  289. if(this->y() + 10 > 250){
  290. this->setY(240); // снизу
  291. }
  292. }
  293.  
  294. /* Функция паузы, отвечает за включение и отключение паузы
  295. * */
  296. void Spider::pause()
  297. {
  298. if(timer->isActive()){
  299. timer->stop();
  300. } else {
  301. timer->start(15);
  302. }
  303. }

віджет.h

У заголовному файлі ядра програми необхідно визначити об'єкт, який відповідає за Павука, змінну стану гри та Гарячу клавішу паузи. А також слоти для обробки запуску гри, паузи та процедури Game Over .

  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3.  
  4. #include <QWidget>
  5. #include <QGraphicsScene>
  6. #include <QGraphicsItem>
  7. #include <QShortcut>
  8. #include <QDebug>
  9. #include <QTimer>
  10. #include <QMessageBox>
  11.  
  12. #include <triangle.h>
  13. #include <apple.h>
  14. #include <spider.h>
  15.  
  16. #define GAME_STOPED 0
  17. #define GAME_STARTED 1
  18.  
  19. namespace Ui {
  20. class Widget;
  21. }
  22.  
  23. class Widget : public QWidget
  24. {
  25. Q_OBJECT
  26.  
  27. public:
  28. explicit Widget(QWidget *parent = 0);
  29. ~Widget();
  30.  
  31. private:
  32. Ui::Widget *ui;
  33. QGraphicsScene *scene; /// Объявляем графическую сцену
  34. Triangle *triangle; /// и треугольник
  35. QTimer *timer; /** Объявляем игровой таймер, благодаря которому
  36. * будет производиться изменения положения объекта на сцене
  37. * При воздействии на него клавишами клавиатуры
  38. * */
  39. QTimer *timerCreateApple; /// Таймер для периодического создания яблок в игре
  40.  
  41. QList<QGraphicsItem *> apples; /// Список со всеми яблоками, присутствующими в игре
  42. double count; /// Переменная, которая хранит счёт игре
  43.  
  44. Spider *spider; // Объект Паука
  45.  
  46. QShortcut *pauseKey; // Горячая клавиша, отвечающая за паузу в игре
  47. int gameState; /* Переменная, которая хранит состояние игры.
  48. * То есть, если игра запущена, то статус будет GAME_STARTED,
  49. * в противном случае GAME_STOPED
  50. * */
  51.  
  52. private slots:
  53. /// Слот для удаления яблок если Муха наткнулась на это яблоко
  54. void slotDeleteApple(QGraphicsItem * item);
  55. void slotCreateApple(); /// Слот для создания яблок, срабатывает по таймеру
  56.  
  57. void on_pushButton_clicked(); // Слот для запуска игры
  58. void slotGameOver(); // Слот инициализации Game Over
  59. void slotPause(); // Слот для обработки паузы
  60. };
  61.  
  62. #endif // WIDGET_H

widget.cpp

Порівняно з програмним кодом, який був у попередніх уроках, з цим файлом у цьому уроці необхідно ґрунтовно попрацювати. Оскільки гра, стартує натисканням кнопки pushButton, то і програмний код ініціалізації об'єктів та запуску таймерів необхідно винести в слот, якому передається сигнал від кнопки. Також виникає необхідність реалізувати функцію паузи в грі, за якою всі ігрові таймери зупиняються і об'єкти не можуть пересуватися або здійснювати інші дії. А в слоті, який відповідає за Game Over , необхідно правильно обробити видалення всіх об'єктів з ігрової сцени.

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3.  
  4. Widget::Widget(QWidget *parent) :
  5. QWidget(parent),
  6. ui(new Ui::Widget)
  7. {
  8. ui->setupUi(this);
  9. this->resize(600,640); /// Задаем размеры виджета, то есть окна
  10. this->setFixedSize(600,640); /// Фиксируем размеры виджета
  11.  
  12. scene = new QGraphicsScene(); /// Инициализируем графическую сцену
  13.  
  14. ui->graphicsView->setScene(scene); /// Устанавливаем графическую сцену в graphicsView
  15. ui->graphicsView->setRenderHint(QPainter::Antialiasing); /// Устанавливаем сглаживание
  16. ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по вертикали
  17. ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по горизонтали
  18.  
  19. scene->setSceneRect(-250,-250,500,500); /// Устанавливаем область графической сцены
  20.  
  21. timer = new QTimer();
  22. timerCreateApple = new QTimer();
  23.  
  24. gameState = GAME_STOPED;
  25.  
  26. pauseKey = new QShortcut(this);
  27. pauseKey->setKey(Qt::Key_Pause);
  28. connect(pauseKey, &QShortcut::activated, this, &Widget::slotPause);
  29.  
  30.  
  31. }
  32.  
  33. Widget::~Widget()
  34. {
  35. delete ui;
  36. }
  37.  
  38. void Widget::slotDeleteApple(QGraphicsItem *item)
  39. {
  40. /* Получив сигнал от Мухи
  41. * Перебираем весь список яблок и удаляем найденное яблоко
  42. * */
  43. foreach (QGraphicsItem *apple, apples) {
  44. if(apple == item){
  45. scene->removeItem(apple); // Удаляем со сцены
  46. apples.removeOne(apple); // Удаляем из списка
  47. delete apple; // Вообще удаляем
  48. ui->lcdNumber->display(count++); /* Увеличиваем счёт на единицу
  49. * и отображаем на дисплее
  50. * */
  51. }
  52. }
  53. }
  54.  
  55. void Widget::slotCreateApple()
  56. {
  57. Apple *apple = new Apple(); // Создаём яблоко
  58. scene->addItem(apple); // Помещаем его в сцену со случайной позицией
  59. apple->setPos((qrand() % (251)) * ((qrand()%2 == 1)?1:-1),
  60. (qrand() % (251)) * ((qrand()%2 == 1)?1:-1));
  61. apple->setZValue(-1); /* Помещаем яблоко ниже Мухи, то есть Муха
  62. * на сцене будет выше яблок
  63. * */
  64. apples.append(apple); // Добавляем Муху в Список
  65. }
  66.  
  67. void Widget::on_pushButton_clicked()
  68. {
  69. count = 0;
  70. ui->lcdNumber->display(count);
  71. triangle = new Triangle(); /// Инициализируем муху
  72.  
  73. scene->addItem(triangle); /// Добавляем на сцену треугольник
  74. triangle->setPos(0,0); /// Устанавливаем треугольник в центр сцены
  75.  
  76. spider = new Spider(triangle); // Инициализируем паука
  77. scene->addItem(spider); // Добавляем паука на сцену
  78. spider->setPos(180,180); // Устанавливаем позицию паука
  79.  
  80. /* Подключаем сигнал от паука на проверку состояния GameOver
  81. * */
  82. connect(spider, &Spider::signalCheckGameOver, this, &Widget::slotGameOver);
  83.  
  84. /** Инициализируем таймер и вызываем слот обработки сигнала таймера
  85. * у Треугольника 100 раз в секунду.
  86. * Управляя скоростью отсчётов, соответственно управляем скоростью
  87. * изменения состояния графической сцены
  88. * */
  89. connect(timer, &QTimer::timeout, triangle, &Triangle::slotGameTimer);
  90. timer->start(1000 / 100);
  91.  
  92. /** Раз в секунду отсылаем сигнал на создание яблока в игре
  93. * */
  94. connect(timerCreateApple, &QTimer::timeout, this, &Widget::slotCreateApple);
  95. timerCreateApple->start(1000);
  96.  
  97. /** Подключаем сигнал от Мухи, в котором передаются Объекты, на которые
  98. * наткнулась Муха
  99. * */
  100. connect(triangle, &Triangle::signalCheckItem, this, &Widget::slotDeleteApple);
  101.  
  102. ui->pushButton->setEnabled(false);
  103.  
  104. gameState = GAME_STARTED;
  105. }
  106.  
  107. void Widget::slotGameOver()
  108. {
  109. /* Если игра окончена
  110. * Отключаем все таймеры
  111. * */
  112. timer->stop();
  113. timerCreateApple->stop();
  114. QMessageBox::warning(this,
  115. "Game Over",
  116. "Мои соболезнования, но Вас только что слопали");
  117. /* Отключаем все сигналы от слотов
  118. * */
  119. disconnect(timerCreateApple, &QTimer::timeout, this, &Widget::slotCreateApple);
  120. disconnect(triangle, &Triangle::signalCheckItem, this, &Widget::slotDeleteApple);
  121. disconnect(spider, &Spider::signalCheckGameOver, this, &Widget::slotGameOver);
  122. /* И удаляем все объекты со сцены
  123. * */
  124. spider->deleteLater();
  125. triangle->deleteLater();
  126.  
  127. foreach (QGraphicsItem *apple, apples) {
  128. scene->removeItem(apple); // Удаляем со сцены
  129. apples.removeOne(apple); // Удаляем из списка
  130. delete apple; // Вообще удаляем
  131. }
  132. /* Активируем кнопку старта игры
  133. * */
  134. ui->pushButton->setEnabled(true);
  135.  
  136. gameState = GAME_STOPED; // Устанавливаем состояние игры в GAME_STOPED
  137. }
  138.  
  139. void Widget::slotPause()
  140. {
  141. /* Выполняем проверку на состояние игры,
  142. * если игра не запущена, то игнорируем Паузу.
  143. * В противном случае или запускаем, или останавливаем все таймеры
  144. * */
  145. if(gameState == GAME_STARTED){
  146. if(timer->isActive()){
  147. timer->stop();
  148. timerCreateApple->stop();
  149. spider->pause();
  150. } else {
  151. timer->start(1000/100);
  152. timerCreateApple->start(1000);
  153. spider->pause();
  154. }
  155. }
  156. }

Підсумок

За результатами проведеної роботи гра перестане бути нескінченною і цінність очок, що набираються, зросте в рази.

Також у відеоуроці за цією статтею подано додаткові коментарі та продемонстровано роботу гри.

Повний список статей цього циклу:

Відеоурок

Вам це подобається? Поділіться в соціальних мережах!

v
  • 09 травня 2017 р. 19: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 р. 19:46

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

РР
  • 04 червня 2019 р. 21:28
  • (відредаговано)

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

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

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

Evgenii Legotckoi
  • 05 червня 2019 р. 13:44

Добрый день.

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

РР
  • 06 червня 2019 р. 06: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