Advertisement
Astranome

spaceInvaders9

Jul 28th, 2020
307
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 23.63 KB | None | 0 0
  1. /*
  2.   Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - www.fabgl.com
  3.   Copyright (c) 2019-2020 Fabrizio Di Vittorio.
  4.   All rights reserved.
  5.  
  6.   This file is part of FabGL Library.
  7.  
  8.   FabGL is free software: you can redistribute it and/or modify
  9.   it under the terms of the GNU General Public License as published by
  10.   the Free Software Foundation, either version 3 of the License, or
  11.   (at your option) any later version.
  12.  
  13.   FabGL is distributed in the hope that it will be useful,
  14.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.   GNU General Public License for more details.
  17.  
  18.   You should have received a copy of the GNU General Public License
  19.   along with FabGL.  If not, see <http://www.gnu.org/licenses/>.
  20.  */
  21.  
  22.  
  23. #include "fabgl.h"
  24. #include "fabutils.h"
  25.  
  26. #include "sprites.h"
  27. #include "sounds.h"
  28.  
  29.  
  30.  
  31.  
  32. using fabgl::iclamp;
  33.  
  34. fabgl::ILI9341Controller DisplayController;
  35. //fabgl::VGAController DisplayController;
  36. fabgl::Canvas        canvas(&DisplayController);
  37. fabgl::PS2Controller PS2Controller;
  38. SoundGenerator       soundGenerator;
  39. #define TFT_SCK    18
  40. #define TFT_MOSI   23
  41. #define TFT_CS     5
  42. #define TFT_DC     22
  43. #define TFT_RESET  21
  44. #define TFT_SPIBUS VSPI_HOST
  45.  
  46. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  47. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  48. // IntroScene
  49.  
  50. struct IntroScene : public Scene {
  51.  
  52.   static const int TEXTROWS = 4;
  53.   static const int TEXT_X   = 130;
  54.   static const int TEXT_Y   = 122;
  55.  
  56.   static int controller_; // 1 = keyboard, 2 = mouse
  57.  
  58.   int textRow_  = 0;
  59.   int textCol_  = 0;
  60.   int starting_ = 0;
  61.  
  62.   SamplesGenerator * music_ = nullptr;
  63.  
  64.   IntroScene()
  65.     : Scene(0, 20, DisplayController.getViewPortWidth(), DisplayController.getViewPortHeight())
  66.   {
  67.   }
  68.  
  69.   void init()
  70.   {
  71.     canvas.setBrushColor(Color::Black);
  72.     canvas.clear();
  73.     canvas.setGlyphOptions(GlyphOptions().FillBackground(true));
  74.     canvas.selectFont(&fabgl::FONT_8x8);
  75.     canvas.setPenColor(Color::BrightWhite);
  76.     canvas.setGlyphOptions(GlyphOptions().DoubleWidth(1));
  77.     canvas.drawText(50, 15, "SPACE INVADERS");
  78.     canvas.setGlyphOptions(GlyphOptions().DoubleWidth(0));
  79.  
  80.     canvas.setPenColor(Color::Green);
  81.     canvas.drawText(10, 40, "ESP32 version by Fabrizio Di Vittorio");
  82.     canvas.drawText(105, 55, "www.fabgl.com");
  83.  
  84.     canvas.setPenColor(Color::Yellow);
  85.     canvas.drawText(72, 97, "* SCORE ADVANCE TABLE *");
  86.     canvas.drawBitmap(TEXT_X - 20 - 2, TEXT_Y, &bmpEnemyD);
  87.     canvas.drawBitmap(TEXT_X - 20, TEXT_Y + 15, &bmpEnemyA[0]);
  88.     canvas.drawBitmap(TEXT_X - 20, TEXT_Y + 30, &bmpEnemyB[0]);
  89.     canvas.drawBitmap(TEXT_X - 20, TEXT_Y + 45, &bmpEnemyC[0]);
  90.  
  91.     canvas.setBrushColor(Color::Black);
  92.  
  93.     controller_ = 0;
  94.  
  95.     music_ = soundGenerator.playSamples(themeSoundSamples, sizeof(themeSoundSamples), 100, -1);
  96.   }
  97.  
  98.   void update(int updateCount)
  99.   {
  100.     static const char * scoreText[] = {"= ? MISTERY", "= 30 POINTS", "= 20 POINTS", "= 10 POINTS" };
  101.  
  102.     auto keyboard = PS2Controller.keyboard();
  103.     auto mouse    = PS2Controller.mouse();
  104.  
  105.     if (starting_) {
  106.  
  107.       if (starting_ > 50) {
  108.         // stop music
  109.         soundGenerator.detach(music_);
  110.         // stop scene
  111.         stop();
  112.       }
  113.  
  114.       ++starting_;
  115.       canvas.scroll(0, -5);
  116.  
  117.     } else {
  118.       if (updateCount > 30 && updateCount % 5 == 0 && textRow_ < 4) {
  119.         int x = TEXT_X + textCol_ * canvas.getFontInfo()->width;
  120.         int y = TEXT_Y + textRow_ * 15 - 4;
  121.         canvas.setPenColor(Color::White);
  122.         canvas.drawChar(x, y, scoreText[textRow_][textCol_]);
  123.         ++textCol_;
  124.         if (scoreText[textRow_][textCol_] == 0) {
  125.           textCol_ = 0;
  126.           ++textRow_;
  127.         }
  128.       }
  129.  
  130.       if (updateCount % 20 == 0) {
  131.         canvas.setPenColor(random(256), random(256), random(256));
  132.         if (keyboard->isKeyboardAvailable() && mouse->isMouseAvailable())
  133.           canvas.drawText(45, 75, "Press [SPACE] or CLICK to Play");
  134.         else if (keyboard->isKeyboardAvailable())
  135.           canvas.drawText(80, 75, "Press [SPACE] to Play");
  136.         else if (mouse->isMouseAvailable())
  137.           canvas.drawText(105, 75, "Click to Play");
  138.       }
  139.  
  140.       // handle keyboard or mouse (after two seconds)
  141.       if (updateCount > 50) {
  142.         if (keyboard->isKeyboardAvailable() && keyboard->isVKDown(fabgl::VK_SPACE))
  143.           controller_ = 1;  // select keyboard as controller
  144.         else if (mouse->isMouseAvailable() && mouse->deltaAvailable() && mouse->getNextDelta(nullptr, 0) && mouse->status().buttons.left)
  145.           controller_ = 2;  // select mouse as controller
  146.         starting_ = (controller_ > 0);  // start only when a controller has been selected
  147.       }
  148.     }
  149.   }
  150.  
  151.   void collisionDetected(Sprite * spriteA, Sprite * spriteB, Point collisionPoint)
  152.   {
  153.   }
  154.  
  155. };
  156.  
  157.  
  158. int IntroScene::controller_ = 0;
  159.  
  160.  
  161. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  162. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  163. // GameScene
  164.  
  165.  
  166. struct GameScene : public Scene {
  167.  
  168.   enum SpriteType { TYPE_PLAYERFIRE, TYPE_ENEMIESFIRE, TYPE_ENEMY, TYPE_PLAYER, TYPE_SHIELD, TYPE_ENEMYMOTHER };
  169.  
  170.   struct SISprite : Sprite {
  171.     SpriteType type;
  172.     uint8_t    enemyPoints;
  173.   };
  174.  
  175.   enum GameState { GAMESTATE_PLAYING, GAMESTATE_PLAYERKILLED, GAMESTATE_ENDGAME, GAMESTATE_GAMEOVER, GAMESTATE_LEVELCHANGING, GAMESTATE_LEVELCHANGED };
  176.  
  177.   static const int PLAYERSCOUNT       = 1;
  178.   static const int SHIELDSCOUNT       = 4;
  179.   static const int ROWENEMIESCOUNT    = 11;
  180.   static const int PLAYERFIRECOUNT    = 1;
  181.   static const int ENEMIESFIRECOUNT   = 1;
  182.   static const int ENEMYMOTHERCOUNT   = 1;
  183.   static const int SPRITESCOUNT       = PLAYERSCOUNT + SHIELDSCOUNT + 5 * ROWENEMIESCOUNT + PLAYERFIRECOUNT + ENEMIESFIRECOUNT + ENEMYMOTHERCOUNT;
  184.  
  185.   static const int ENEMIES_X_SPACE    = 16;
  186.   static const int ENEMIES_Y_SPACE    = 10;
  187.   static const int ENEMIES_START_X    = 0;
  188.   static const int ENEMIES_START_Y    = 30;
  189.   static const int ENEMIES_STEP_X     = 6;
  190.   static const int ENEMIES_STEP_Y     = 8;
  191.  
  192.   static const int PLAYER_Y           = 170;
  193.  
  194.   static int lives_;
  195.   static int score_;
  196.   static int level_;
  197.   static int hiScore_;
  198.  
  199.   SISprite * sprites_     = new SISprite[SPRITESCOUNT];
  200.   SISprite * player_      = sprites_;
  201.   SISprite * shields_     = player_ + PLAYERSCOUNT;
  202.   SISprite * enemies_     = shields_ + SHIELDSCOUNT;
  203.   SISprite * enemiesR1_   = enemies_;
  204.   SISprite * enemiesR2_   = enemiesR1_ + ROWENEMIESCOUNT;
  205.   SISprite * enemiesR3_   = enemiesR2_ + ROWENEMIESCOUNT;
  206.   SISprite * enemiesR4_   = enemiesR3_ + ROWENEMIESCOUNT;
  207.   SISprite * enemiesR5_   = enemiesR4_ + ROWENEMIESCOUNT;
  208.   SISprite * playerFire_  = enemiesR5_ + ROWENEMIESCOUNT;
  209.   SISprite * enemiesFire_ = playerFire_ + PLAYERFIRECOUNT;
  210.   SISprite * enemyMother_ = enemiesFire_ + ENEMIESFIRECOUNT;
  211.  
  212.   int playerVelX_          = 0;  // used when controller is keyboard (0 = no move)
  213.   int playerAbsX_          = -1; // used when controller is mouse (-1 = no move)
  214.   int enemiesX_            = ENEMIES_START_X;
  215.   int enemiesY_            = ENEMIES_START_Y;
  216.  
  217.   // enemiesDir_
  218.   //   bit 0 : if 1 moving left
  219.   //   bit 1 : if 1 moving right
  220.   //   bit 2 : if 1 moving down
  221.   //   bit 3 : if 0 before was moving left, if 1 before was moving right
  222.   // Allowed cases:
  223.   //   1  = moving left
  224.   //   2  = moving right
  225.   //   4  = moving down (before was moving left)
  226.   //   12 = moving down (before was moving right)
  227.  
  228.   static constexpr int ENEMY_MOV_LEFT              = 1;
  229.   static constexpr int ENEMY_MOV_RIGHT             = 2;
  230.   static constexpr int ENEMY_MOV_DOWN_BEFORE_LEFT  = 4;
  231.   static constexpr int ENEMY_MOV_DOWN_BEFORE_RIGHT = 12;
  232.  
  233.   int enemiesDir_          = ENEMY_MOV_RIGHT;
  234.  
  235.   int enemiesAlive_        = ROWENEMIESCOUNT * 5;
  236.   int enemiesSoundCount_   = 0;
  237.   SISprite * lastHitEnemy_ = nullptr;
  238.   GameState gameState_     = GAMESTATE_PLAYING;
  239.  
  240.   bool updateScore_        = true;
  241.   int64_t pauseStart_;
  242.  
  243.   Bitmap bmpShield[4] = { Bitmap(22, 16, shield_data, PixelFormat::Mask, RGB888(0, 255, 0), true),
  244.                           Bitmap(22, 16, shield_data, PixelFormat::Mask, RGB888(0, 255, 0), true),
  245.                           Bitmap(22, 16, shield_data, PixelFormat::Mask, RGB888(0, 255, 0), true),
  246.                           Bitmap(22, 16, shield_data, PixelFormat::Mask, RGB888(0, 255, 0), true), };
  247.  
  248.   GameScene()
  249.     : Scene(SPRITESCOUNT, 20, DisplayController.getViewPortWidth(), DisplayController.getViewPortHeight())
  250.   {
  251.   }
  252.  
  253.   ~GameScene()
  254.   {
  255.     delete [] sprites_;
  256.   }
  257.  
  258.   void initEnemy(Sprite * sprite, int points)
  259.   {
  260.     SISprite * s = (SISprite*) sprite;
  261.     s->addBitmap(&bmpEnemyExplosion);
  262.     s->type = TYPE_ENEMY;
  263.     s->enemyPoints = points;
  264.     addSprite(s);
  265.   }
  266.  
  267.   void init()
  268.   {
  269.     // setup player
  270.     player_->addBitmap(&bmpPlayer)->addBitmap(&bmpPlayerExplosion[0])->addBitmap(&bmpPlayerExplosion[1]);
  271.     player_->moveTo(152, PLAYER_Y);
  272.     player_->type = TYPE_PLAYER;
  273.     addSprite(player_);
  274.     // setup player fire
  275.     playerFire_->addBitmap(&bmpPlayerFire);
  276.     playerFire_->visible = false;
  277.     playerFire_->type = TYPE_PLAYERFIRE;
  278.     addSprite(playerFire_);
  279.     // setup shields
  280.     for (int i = 0; i < 4; ++i) {
  281.       shields_[i].addBitmap(&bmpShield[i])->moveTo(35 + i * 75, 150);
  282.       shields_[i].isStatic = true;
  283.       shields_[i].type = TYPE_SHIELD;
  284.       addSprite(&shields_[i]);
  285.     }
  286.     // setup enemies
  287.     for (int i = 0; i < ROWENEMIESCOUNT; ++i) {
  288.       initEnemy( enemiesR1_[i].addBitmap(&bmpEnemyA[0])->addBitmap(&bmpEnemyA[1]), 30 );
  289.       initEnemy( enemiesR2_[i].addBitmap(&bmpEnemyB[0])->addBitmap(&bmpEnemyB[1]), 20 );
  290.       initEnemy( enemiesR3_[i].addBitmap(&bmpEnemyB[0])->addBitmap(&bmpEnemyB[1]), 20 );
  291.       initEnemy( enemiesR4_[i].addBitmap(&bmpEnemyC[0])->addBitmap(&bmpEnemyC[1]), 10 );
  292.       initEnemy( enemiesR5_[i].addBitmap(&bmpEnemyC[0])->addBitmap(&bmpEnemyC[1]), 10 );
  293.     }
  294.     // setup enemies fire
  295.     enemiesFire_->addBitmap(&bmpEnemiesFire[0])->addBitmap(&bmpEnemiesFire[1]);
  296.     enemiesFire_->visible = false;
  297.     enemiesFire_->type = TYPE_ENEMIESFIRE;
  298.     addSprite(enemiesFire_);
  299.     // setup enemy mother ship
  300.     enemyMother_->addBitmap(&bmpEnemyD)->addBitmap(&bmpEnemyExplosionRed);
  301.     enemyMother_->visible = false;
  302.     enemyMother_->type = TYPE_ENEMYMOTHER;
  303.     enemyMother_->enemyPoints = 100;
  304.     enemyMother_->moveTo(getWidth(), ENEMIES_START_Y);
  305.     addSprite(enemyMother_);
  306.  
  307.     DisplayController.setSprites(sprites_, SPRITESCOUNT);
  308.  
  309.     canvas.setBrushColor(Color::Black);
  310.     canvas.clear();
  311.  
  312.     canvas.setPenColor(Color::Green);
  313.     canvas.drawLine(0, 180, 320, 180);
  314.  
  315.     //canvas.setPenColor(Color::Yellow);
  316.     //canvas.drawRectangle(0, 0, getWidth() - 1, getHeight() - 1);
  317.  
  318.     canvas.setGlyphOptions(GlyphOptions().FillBackground(true));
  319.     canvas.selectFont(&fabgl::FONT_4x6);
  320.     canvas.setPenColor(Color::White);
  321.     canvas.drawText(125, 20, "WE COME IN PEACE");
  322.     canvas.selectFont(&fabgl::FONT_8x8);
  323.     canvas.setPenColor(0, 255, 255);
  324.     canvas.drawText(2, 2, "SCORE");
  325.     canvas.setPenColor(0, 0, 255);
  326.     canvas.drawText(254, 2, "HI-SCORE");
  327.     canvas.setPenColor(255, 255, 255);
  328.     canvas.drawTextFmt(254, 181, "Level %02d", level_);
  329.  
  330.     if (IntroScene::controller_ == 2) {
  331.       // setup mouse controller
  332.       auto mouse = PS2Controller.mouse();
  333.       mouse->setSampleRate(40);  // reduce number of samples from mouse to reduce delays
  334.       mouse->setupAbsolutePositioner(getWidth() - player_->getWidth(), 0, false); // take advantage of mouse acceleration
  335.     }
  336.  
  337.     showLives();
  338.   }
  339.  
  340.   void drawScore()
  341.   {
  342.     canvas.setPenColor(255, 255, 255);
  343.     canvas.drawTextFmt(2, 14, "%05d", score_);
  344.     if (score_ > hiScore_)
  345.       hiScore_ = score_;
  346.     canvas.setPenColor(255, 255, 255);
  347.     canvas.drawTextFmt(266, 14, "%05d", hiScore_);
  348.   }
  349.  
  350.   void moveEnemy(SISprite * enemy, int x, int y, bool * touchSide)
  351.   {
  352.     if (enemy->visible) {
  353.       if (x <= 0 || x >= getWidth() - enemy->getWidth())
  354.         *touchSide = true;
  355.       enemy->moveTo(x, y);
  356.       enemy->setFrame(enemy->getFrameIndex() ? 0 : 1);
  357.       updateSprite(enemy);
  358.       if (y >= PLAYER_Y) {
  359.         // enemies reach earth!
  360.         gameState_ = GAMESTATE_ENDGAME;
  361.       }
  362.     }
  363.   }
  364.  
  365.   void gameOver()
  366.   {
  367.     // disable enemies drawing, so text can be over them
  368.     for (int i = 0; i < ROWENEMIESCOUNT * 5; ++i)
  369.       enemies_[i].allowDraw = false;
  370.     // show game over
  371.     canvas.setPenColor(0, 255, 0);
  372.     canvas.setBrushColor(0, 0, 0);
  373.     canvas.fillRectangle(80, 60, 240, 130);
  374.     canvas.drawRectangle(80, 60, 240, 130);
  375.     canvas.setGlyphOptions(GlyphOptions().DoubleWidth(1));
  376.     canvas.setPenColor(255, 255, 255);
  377.     canvas.drawText(90, 80, "GAME OVER");
  378.     canvas.setGlyphOptions(GlyphOptions().DoubleWidth(0));
  379.     canvas.setPenColor(0, 255, 0);
  380.     if (IntroScene::controller_ == 1)
  381.       canvas.drawText(110, 100, "Press [SPACE]");
  382.     else if (IntroScene::controller_ == 2)
  383.       canvas.drawText(93, 100, "Click to continue");
  384.     // change state
  385.     gameState_ = GAMESTATE_GAMEOVER;
  386.     level_ = 1;
  387.     lives_ = 3;
  388.     score_ = 0;
  389.   }
  390.  
  391.   void levelChange()
  392.   {
  393.     ++level_;
  394.     // show game over
  395.     canvas.setPenColor(0, 255, 0);
  396.     canvas.drawRectangle(80, 80, 240, 110);
  397.     canvas.setGlyphOptions(GlyphOptions().DoubleWidth(1));
  398.     canvas.drawTextFmt(105, 88, "LEVEL %d", level_);
  399.     canvas.setGlyphOptions(GlyphOptions().DoubleWidth(0));
  400.     // change state
  401.     gameState_  = GAMESTATE_LEVELCHANGED;
  402.     pauseStart_ = esp_timer_get_time();
  403.   }
  404.  
  405.   void update(int updateCount)
  406.   {
  407.     auto keyboard = PS2Controller.keyboard();
  408.     auto mouse    = PS2Controller.mouse();
  409.  
  410.     if (updateScore_) {
  411.       updateScore_ = false;
  412.       drawScore();
  413.     }
  414.  
  415.     if (gameState_ == GAMESTATE_PLAYING || gameState_ == GAMESTATE_PLAYERKILLED) {
  416.  
  417.       // move enemies and shoot
  418.       if ((updateCount % max(3, 21 - level_ * 2)) == 0) {
  419.         // handle enemy explosion
  420.         if (lastHitEnemy_) {
  421.           lastHitEnemy_->visible = false;
  422.           lastHitEnemy_ = nullptr;
  423.         }
  424.         // handle enemies movement
  425.         enemiesX_ += (-1 * (enemiesDir_ & 1) + (enemiesDir_ >> 1 & 1)) * ENEMIES_STEP_X;
  426.         enemiesY_ += (enemiesDir_ >> 2 & 1) * ENEMIES_STEP_Y;
  427.         bool touchSide = false;
  428.         for (int i = 0; i < ROWENEMIESCOUNT; ++i) {
  429.           moveEnemy(&enemiesR1_[i], enemiesX_ + i * ENEMIES_X_SPACE, enemiesY_ + 0 * ENEMIES_Y_SPACE, &touchSide);
  430.           moveEnemy(&enemiesR2_[i], enemiesX_ + i * ENEMIES_X_SPACE, enemiesY_ + 1 * ENEMIES_Y_SPACE, &touchSide);
  431.           moveEnemy(&enemiesR3_[i], enemiesX_ + i * ENEMIES_X_SPACE, enemiesY_ + 2 * ENEMIES_Y_SPACE, &touchSide);
  432.           moveEnemy(&enemiesR4_[i], enemiesX_ + i * ENEMIES_X_SPACE, enemiesY_ + 3 * ENEMIES_Y_SPACE, &touchSide);
  433.           moveEnemy(&enemiesR5_[i], enemiesX_ + i * ENEMIES_X_SPACE, enemiesY_ + 4 * ENEMIES_Y_SPACE, &touchSide);
  434.         }
  435.         switch (enemiesDir_) {
  436.           case ENEMY_MOV_DOWN_BEFORE_LEFT:
  437.             enemiesDir_ = ENEMY_MOV_RIGHT;
  438.             break;
  439.           case ENEMY_MOV_DOWN_BEFORE_RIGHT:
  440.             enemiesDir_ = ENEMY_MOV_LEFT;
  441.             break;
  442.           default:
  443.             if (touchSide)
  444.               enemiesDir_ = (enemiesDir_ == ENEMY_MOV_LEFT ? ENEMY_MOV_DOWN_BEFORE_LEFT : ENEMY_MOV_DOWN_BEFORE_RIGHT);
  445.             break;
  446.         }
  447.         // sound
  448.         ++enemiesSoundCount_;
  449.         soundGenerator.playSamples(invadersSoundSamples[enemiesSoundCount_ % 4], invadersSoundSamplesSize[enemiesSoundCount_ % 4]);
  450.         // handle enemies fire generation
  451.         if (!enemiesFire_->visible) {
  452.           int shottingEnemy = random(enemiesAlive_);
  453.           for (int i = 0, a = 0; i < ROWENEMIESCOUNT * 5; ++i) {
  454.             if (enemies_[i].visible) {
  455.               if (a == shottingEnemy) {
  456.                 enemiesFire_->x = enemies_[i].x + enemies_[i].getWidth() / 2;
  457.                 enemiesFire_->y = enemies_[i].y + enemies_[i].getHeight() / 2;
  458.                 enemiesFire_->visible = true;
  459.                 break;
  460.               }
  461.               ++a;
  462.             }
  463.           }
  464.         }
  465.       }
  466.  
  467.       if (gameState_ == GAMESTATE_PLAYERKILLED) {
  468.         // animate player explosion or restart playing other lives
  469.         if ((updateCount % 20) == 0) {
  470.           if (player_->getFrameIndex() == 1)
  471.             player_->setFrame(2);
  472.           else {
  473.             player_->setFrame(0);
  474.             gameState_ = GAMESTATE_PLAYING;
  475.           }
  476.         }
  477.       } else if (IntroScene::controller_ == 1 && playerVelX_ != 0) {
  478.         // move player using Keyboard
  479.         player_->x += playerVelX_;
  480.         player_->x = iclamp(player_->x, 0, getWidth() - player_->getWidth());
  481.         updateSprite(player_);
  482.       } else if (IntroScene::controller_ == 2 && playerAbsX_ != -1) {
  483.         // move player using Mouse
  484.         player_->x = playerAbsX_;
  485.         playerAbsX_ = -1;
  486.         updateSprite(player_);
  487.       }
  488.  
  489.       // move player fire
  490.       if (playerFire_->visible) {
  491.         playerFire_->y -= 3;
  492.         if (playerFire_->y < ENEMIES_START_Y)
  493.           playerFire_->visible = false;
  494.         else
  495.           updateSpriteAndDetectCollisions(playerFire_);
  496.       }
  497.  
  498.       // move enemies fire
  499.       if (enemiesFire_->visible) {
  500.         enemiesFire_->y += 2;
  501.         enemiesFire_->setFrame( enemiesFire_->getFrameIndex() ? 0 : 1 );
  502.         if (enemiesFire_->y > PLAYER_Y + player_->getHeight())
  503.           enemiesFire_->visible = false;
  504.         else
  505.           updateSpriteAndDetectCollisions(enemiesFire_);
  506.       }
  507.  
  508.       // move enemy mother ship
  509.       if (enemyMother_->visible && enemyMother_->getFrameIndex() == 0) {
  510.         enemyMother_->x -= 1;
  511.         if (enemyMother_->x < -enemyMother_->getWidth())
  512.           enemyMother_->visible = false;
  513.         else
  514.           updateSprite(enemyMother_);
  515.       }
  516.  
  517.       // start enemy mother ship
  518.       if ((updateCount % 800) == 0) {
  519.         soundGenerator.playSamples(motherShipSoundSamples, sizeof(motherShipSoundSamples), 100, 7000);
  520.         enemyMother_->x = getWidth();
  521.         enemyMother_->setFrame(0);
  522.         enemyMother_->visible = true;
  523.       }
  524.  
  525.       // handle fire and movement from controller
  526.       if (IntroScene::controller_ == 1) {
  527.         // KEYBOARD controller
  528.         if (keyboard->isVKDown(fabgl::VK_LEFT))
  529.           playerVelX_ = -1;
  530.         else if (keyboard->isVKDown(fabgl::VK_RIGHT))
  531.           playerVelX_ = +1;
  532.         else
  533.           playerVelX_ = 0;
  534.         if (keyboard->isVKDown(fabgl::VK_SPACE) && !playerFire_->visible)  // player fire?
  535.           fire();
  536.       } else if (IntroScene::controller_ == 2) {
  537.         // MOUSE controller
  538.         if (mouse->deltaAvailable()) {
  539.           MouseDelta delta;
  540.           mouse->getNextDelta(&delta);
  541.           mouse->updateAbsolutePosition(&delta);
  542.           playerAbsX_ = mouse->status().X;
  543.           if (delta.buttons.left && !playerFire_->visible)    // player fire?
  544.             fire();
  545.         }
  546.       }
  547.     }
  548.  
  549.     if (gameState_ == GAMESTATE_ENDGAME)
  550.       gameOver();
  551.  
  552.     if (gameState_ == GAMESTATE_LEVELCHANGING)
  553.       levelChange();
  554.  
  555.     if (gameState_ == GAMESTATE_LEVELCHANGED && esp_timer_get_time() >= pauseStart_ + 2500000) {
  556.       stop(); // restart from next level
  557.       DisplayController.removeSprites();
  558.     }
  559.  
  560.     if (gameState_ == GAMESTATE_GAMEOVER) {
  561.  
  562.       // animate player burning
  563.       if ((updateCount % 20) == 0)
  564.         player_->setFrame( player_->getFrameIndex() == 1 ? 2 : 1);
  565.  
  566.       // wait for SPACE or click from mouse
  567.       if ((IntroScene::controller_ == 1 && keyboard->isVKDown(fabgl::VK_SPACE)) ||
  568.           (IntroScene::controller_ == 2 && mouse->deltaAvailable() && mouse->getNextDelta(nullptr, 0) && mouse->status().buttons.left)) {
  569.         stop();
  570.         DisplayController.removeSprites();
  571.       }
  572.  
  573.     }
  574.  
  575.     DisplayController.refreshSprites();
  576.   }
  577.  
  578.   // player shoots
  579.   void fire()
  580.   {
  581.     playerFire_->moveTo(player_->x + 7, player_->y - 1)->visible = true;
  582.     soundGenerator.playSamples(fireSoundSamples, sizeof(fireSoundSamples));
  583.   }
  584.  
  585.   // shield has been damaged
  586.   void damageShield(SISprite * shield, Point collisionPoint)
  587.   {
  588.     Bitmap * shieldBitmap = shield->getFrame();
  589.     int x = collisionPoint.X - shield->x;
  590.     int y = collisionPoint.Y - shield->y;
  591.     shieldBitmap->setPixel(x, y, 0);
  592.     for (int i = 0; i < 32; ++i) {
  593.       int px = iclamp(x + random(-4, 5), 0, shield->getWidth() - 1);
  594.       int py = iclamp(y + random(-4, 5), 0, shield->getHeight() - 1);
  595.       shieldBitmap->setPixel(px, py, 0);
  596.     }
  597.   }
  598.  
  599.   void showLives()
  600.   {
  601.     canvas.fillRectangle(1, 181, 100, 195);
  602.     canvas.setPenColor(Color::White);
  603.     canvas.drawTextFmt(5, 181, "%d", lives_);
  604.     for (int i = 0; i < lives_; ++i)
  605.       canvas.drawBitmap(15 + i * (bmpPlayer.width + 5), 183, &bmpPlayer);
  606.   }
  607.  
  608.   void collisionDetected(Sprite * spriteA, Sprite * spriteB, Point collisionPoint)
  609.   {
  610.     SISprite * sA = (SISprite*) spriteA;
  611.     SISprite * sB = (SISprite*) spriteB;
  612.     if (!lastHitEnemy_ && sA->type == TYPE_PLAYERFIRE && sB->type == TYPE_ENEMY) {
  613.       // player fire hits an enemy
  614.       soundGenerator.playSamples(shootSoundSamples, sizeof(shootSoundSamples));
  615.       sA->visible = false;
  616.       sB->setFrame(2);
  617.       lastHitEnemy_ = sB;
  618.       --enemiesAlive_;
  619.       score_ += sB->enemyPoints;
  620.       updateScore_ = true;
  621.       if (enemiesAlive_ == 0)
  622.         gameState_ = GAMESTATE_LEVELCHANGING;
  623.     }
  624.     if (sB->type == TYPE_SHIELD) {
  625.       // something hits a shield
  626.       sA->visible = false;
  627.       damageShield(sB, collisionPoint);
  628.       sB->allowDraw = true;
  629.     }
  630.     if (gameState_ == GAMESTATE_PLAYING && sA->type == TYPE_ENEMIESFIRE && sB->type == TYPE_PLAYER) {
  631.       // enemies fire hits player
  632.       soundGenerator.playSamples(explosionSoundSamples, sizeof(explosionSoundSamples));
  633.       --lives_;
  634.       gameState_ = lives_ ? GAMESTATE_PLAYERKILLED : GAMESTATE_ENDGAME;
  635.       player_->setFrame(1);
  636.       showLives();
  637.     }
  638.     if (sB->type == TYPE_ENEMYMOTHER) {
  639.       // player fire hits enemy mother ship
  640.       soundGenerator.playSamples(mothershipexplosionSoundSamples, sizeof(mothershipexplosionSoundSamples));
  641.       sA->visible = false;
  642.       sB->setFrame(1);
  643.       lastHitEnemy_ = sB;
  644.       score_ += sB->enemyPoints;
  645.       updateScore_ = true;
  646.     }
  647.   }
  648.  
  649. };
  650.  
  651. int GameScene::hiScore_ = 0;
  652. int GameScene::level_   = 1;
  653. int GameScene::lives_   = 3;
  654. int GameScene::score_   = 0;
  655.  
  656.  
  657. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  658. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  659.  
  660.  
  661.  
  662. void setup()
  663. {
  664.   PS2Controller.begin(PS2Preset::KeyboardPort0_MousePort1, KbdMode::GenerateVirtualKeys);
  665.  
  666.   DisplayController.begin(TFT_SCK, TFT_MOSI, TFT_DC, TFT_RESET, TFT_CS, TFT_SPIBUS);
  667.   DisplayController.setResolution(TFT_240x320);
  668.   DisplayController.setOrientation(fabgl::TFTOrientation::Rotate90);
  669.   //DisplayController.begin();
  670.   //DisplayController.setResolution(VGA_320x200_75Hz);
  671.  
  672.   // adjust this to center screen in your monitor
  673.   //DisplayController.moveScreen(20, -2);
  674. }
  675.  
  676.  
  677. void loop()
  678. {
  679.   if (GameScene::level_ == 1) {
  680.     IntroScene introScene;
  681.     introScene.start();
  682.   }
  683.   GameScene gameScene;
  684.   gameScene.start();
  685. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement