След като сме готови с началния екран, ще пристъпим към екрана за самата игра. Но преди това ще покажем заглавието на играта и ще обработим събитията за бутоните „Към играта“ и „За играта“.

Съдържание

  1. Добавяне на заглавие.
  2. Обработка на събитията на бутоните „Към играта“ и „За играта“.
  3. Да качим нивото. Екран за играта.

 

Добавяне на заглавие.

Във FifteenGame.h в private добавяме:

  1. // шрифт за заглавието
  2. BmpFont* bmpFont;
  3. // заглавие на играта
  4. LineText* titleText;

Във файла FifteenGame.cpp в метода

  1. void FifteenGame::init()

след реда:

  1. addSprite(btnAboutGame);

добавяме:

  1.     // шрифт, който ще се използва за показване на заглавието
  2.     bmpFont = new BmpFont();
  3.     // зареждаме шрифта
  4.     bmpFont->setImage(Constants::RESOURCE_DIR + Constants::pathSeparator + „sampleFont.png“);
  5.     // указваме размерността
  6.     bmpFont->initFont(117, 1);
  7.     titleText = new LineText();
  8.     titleText->setFont(bmpFont);
  9.     titleText->setText(L„Игра“);
  10.     titleText->setX((getWidth() titleText->getWidth())/2);
  11.     titleText->setY(150);

В render добавяме:

  1. titleText->render(screen);

а в деструктора:

  1.     if (bmpFont) {
  2.         delete bmpFont;
  3.         bmpFont = 0;
  4.     }
  5.     if (titleText) {
  6.         delete titleText;
  7.         titleText = 0;
  8.     }

Компилираме и стартираме:

Уроци по програмиране

Вече имаме заглавие.

Обработка на събитията на бутоните.

Във файла FifteenGame.cpp в метода

  1. void FifteenGame::render()

към обработчика на събитието на бутона за излизане добавяме тези за бутоните „Към играта“ и „За играта“:

  1.     // изход от играта
  2.     if (btnExitGame->isMouseButtonDown()) {
  3.         this->setDone(true);
  4.     } // „Към играта“
  5.     else if ( btnGoGame ->isMouseButtonDown()) {
  6.     } // „За играта“
  7.     else if (btnAboutGame->isMouseButtonDown()) {
  8.     }


Когато кликнем върху бутона „За играта“, ще искаме да излиза някаква информация за играта. Това можем да го направим по различни начини. Бихме могли да си напишем клас, който логически да формира прозорец, със съответните координати, информация и т.н. и всичко това да рисуваме върху главната повърхност. А може и в новия клас да си дефинираме нова повърхност, специално за прозорчето и всичко да рисуваме в нея. В класът TextMessage.cpp сме избрали втория подход. Няма да се спирам върху TextMessage, само ще отбележа, че той съдържа пример за това как да се създава и използва нова повърхност. Това би могла да е полезно, ако искаме да реализираме например video player в рамките на приложението ни. TextMessage е недовършен и служи само за демонстрация.
И така във FifteenGame.h добавяме в секцията private:

  1. // прозорче с информация за играта
  2. TextMessage* aboutTextMessage;
  3. // шрифт за текста в aboutTextMessage
  4. BmpFont* bmpFont14;

TextMessage е основен клас, така че той се включва в Game engine и тук не е нужно да го включваме. Естествено, ако предпочитате може да оптимизирате Game engine в това отношение.

Във

  1. void FifteenGame::init()

добавяме:

  1.     bmpFont14 = new BmpFont();
  2.     bmpFont14->setImage(Constants::RESOURCE_DIR + Constants::pathSeparator + „font14.png“);
  3.     // какваме каква е геометрията на шрифта – 1 ред с 132 колони
  4.     bmpFont14->initFont(132, 1);
  5.     // как се мапват данните от bmp шрифта със символите
  6.     wstring stringFont14 = L“ !,.0123456789:?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя“;
  7.     bmpFont14->setStringFont(stringFont14);
  8.     //урок 2
  9.     aboutTextMessage = new TextMessage();
  10.     aboutTextMessage->setBmpFont(bmpFont14);
  11.     aboutTextMessage->setTitle(L„Игра 15“);
  12.     aboutTextMessage->setContent(L„Jinnee представя!“);
  13.     aboutTextMessage->setX((getWidth()-350)/2);
  14.     aboutTextMessage->setY(150);
  15.     aboutTextMessage->setWidth(350);
  16.     aboutTextMessage->setHeight(150);
  17.     aboutTextMessage->setShowTextMessage(false);
  18.     aboutTextMessage->init();

В render добавяме:

  1.     aboutTextMessage->render(screen);

Както и добавяме код в частта за обработка на събитията:

  1.     if (btnExitGame->isMouseButtonDown()) {
  2.         this->setDone(true);
  3.     } else if ( btnGoGame ->isMouseButtonDown()) {
  4.          // ако отиваме към играта – скриваме инфото за играта
  5.          aboutTextMessage->setShowTextMessage(false);
  6.     } else if (btnAboutGame->isMouseButtonDown()) {
  7.          // ако не сме показали инфо, показваме
  8.          if (!aboutTextMessage->getShowTextMessage()) {
  9.             aboutTextMessage->setShowTextMessage(true);
  10.         } else { // скриване
  11.              aboutTextMessage->setShowTextMessage(false);
  12.         }
  13.        btnAboutGame->setMouseButtonDown(false);
  14.    }

В деструктора добавяме:

  1.     if (bmpFont14) {
  2.         delete bmpFont14;
  3.         bmpFont14 = 0;
  4.     }
  5.     if (aboutTextMessage) {
  6.         delete aboutTextMessage;
  7.         aboutTextMessage = 0;
  8.     }

И така, вече имаме и прозорче за инфо за играта.

Да качим нивото. Екран за играта.

Идва ред и да направим и екрана за играта. Ще са ни необходими картинки с плочките и рамката. Всички ресурси, необходими за играта, може да изтеглите оттук – Github

Тъй като рамката е неподвижна част, не е необходимо да правим за нея специален спрайт. Просто ще я поставим на background-а на екрана за играта и ще получим:

Уроци по програмиране

Ще сложим и три бутона: за изход към менюто, за нова игра и рестартиране.

Да добавим клас за състоянията на играта:
За сега ще отбелязваме само дали сме в екрана за игра или не. Може да имаме също така състояние стартирана или не, записана или не.

Създаваме си клас за състоянията в директорията gsrc.

GameState.h

  1. #ifndef GAMESTATE_H
  2. #define GAMESTATE_H
  3. class GameState
  4. {
  5.     public:
  6.     static int inGame;
  7. };
  8. #endif // GAMESTATE_H

GameState.cpp

  1. #include „GameState.h“
  2. int GameState::inGame = 0;

Ще ни е необходим и клас, който ще показва играта Game15. Той ще наследява AbstractGame. Ето и декларацията (в директория gsrc):

  1. #ifndef GAME15_H
  2. #define GAME15_H
  3. #include „../include/SpriteManager.h“
  4. #include „../include/AbstractGame.h“
  5. #include „../include/AnimatedSprite.h“
  6. #include „../include/Button.h“
  7. #include „../include/Background.h“
  8. #include „FConstants.h“
  9. #include „GameState.h“
  10. class Game15 : public AbstractGame {
  11. public:
  12.       Game15(SDL_Surface* screen);
  13.      void init();
  14.      void render();
  15.      void update(double deltaTime);
  16.      void freeResources();
  17.      void setSurface(SDL_Surface* screen);
  18.      virtual ~Game15();
  19. private:
  20.      // бутон за изход към менюто
  21.      Button* btnToMainMenu;
  22.      // бутон за нова игра
  23.     Button* btnNewGame;
  24.     // бутон за рестартиране на играта
  25.     Button* btnRestartGame;
  26.     Background* mBackground;
  27.     SDL_Surface* screen;
  28.     // позиции на бутоните
  29.     int buttonsTopMenu;
  30.     int buttonsLeftMargin;
  31.     int buttonsHeight;
  32.     int buttonsDistance;
  33. };
  34. #endif // GAME15_H

Тялото на Game15 не съдържа по-различни неща от този на главния екран. Кода може да се види от тук:

https://github.com/jinnee/tutorials/blob/tutorial_2/gsrc/Game15.cpp

Промените свързани със класът FifteenGame са в методите render и update, и декларирането на нова член променлива mGame15 обект за класа за екрана.

В FifteenGame.h вмъкваме класът за екрана на дъската:
#include „Game15.h“
и добавяме нова променлива:

  1. Game15* mGame15;

Методът update се променя така:

  1.     if (mGame15 && GameState::inGame == 1) {
  2.     mGame15->update(deltaTime);
  3.     } else if (sparks) {
  4.     sparks->update(deltaTime);
  5.     }

а методът render:

  1. void FifteenGame::render() {
  2.       // Ако не сме в екрана на играта,
  3.       // напуснали сме го или правим първо стартиране на играта
  4.       //- показваме главният екран
  5.       if( GameState::inGame == 0 ) {
  6.          if (mGame15){
  7.            mGame15 = 0;
  8.            delete mGame15;
  9.          }
  10.       // показваме
  11.       background->render(screen);
  12.       sparks->render(screen);
  13.       btnExitGame->render(screen);
  14.       btnGoGame->render(screen);
  15.       btnAboutGame->render(screen);
  16.       titleText->render(screen);
  17.       aboutTextMessage->render(screen);
  18.       if (btnExitGame->isCursorInSprite()
  19.                   || btnGoGame->isCursorInSprite()
  20.                   || btnAboutGame->isCursorInSprite()) {
  21.           cursor->changeCursor(cursor_ladybug);
  22.           cursor_flag = true;
  23.        } else {
  24.             if (cursor_flag) {
  25.                 cursor_flag = false;
  26.                 cursor->changeCursor(FConstants::STANDART_CURSOR);
  27.             }
  28.        }
  29.       // ако отиваме към екрана на играта
  30.       if ( btnGoGame ->isMouseButtonDown()) {
  31.            // променяме състоянието
  32.            GameState::inGame = 1;
  33.            // скриваме текста (от бутона за играта),
  34.            // ако сме го показали
  35.            aboutTextMessage->setShowTextMessage(false);
  36.           // променяме курсора, защото върху бутона той не е
  37.           // стандартният
  38.           cursor->changeCursor(FConstants::STANDART_CURSOR);
  39.           // създаваме класа за екрана на играта
  40.           mGame15 = new Game15(screen);
  41.           mGame15->init();
  42.       } else if (btnAboutGame->isMouseButtonDown()) {
  43.           if (!aboutTextMessage->getShowTextMessage()) {
  44.           aboutTextMessage->setShowTextMessage(true);
  45.           } else {
  46.           aboutTextMessage->setShowTextMessage(false);
  47.           }
  48.           btnAboutGame->setMouseButtonDown(false);
  49.      }
  50.     // изход от играта
  51.     if (btnExitGame->isMouseButtonDown()) {
  52.         this->setDone(true);
  53.      }
  54.       } else {
  55.       mGame15->render();
  56.       }
  57.       cursor->render(screen);
  58. }

Кодът може да свалите оттук:

Github

В следващата част ще реализираме алгоритмите на играта.

Приятно кодиране 🙂

Автор: Янко Попов