Arduino:Примеры/Rocket

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Игра «Ракета» [1]

Этот пример показывает при помощи Arduino и библиотеки GLCD воспроизвести на GLCD-панели игру в стиле аркадной игры «Asteroids».

Код

 
/*
 * Ракета
 *
 * Примитивная игра в духе «Asteroids» от biegematchbox
 * http://www.beigematchbox.co.uk/site/BeigeMatchbox.co.uk/Electronics/Electronics.html
 *
 * Чтобы управлять позицией ракеты, подключаем регулируемый резистор 
 * к входному аналоговому контакту (potPin)
 * Чтобы был звук, к контакту speakerPin можно подключить пьезодинамик 
 * (или обычный динамик, но понадобится добавочный резистор) 
 *
 * Дискуссия на форуме Arduino: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1265067548
 *
 */


#include <glcd.h>
#include "fonts/SystemFont5x7.h"   // шрифт
#include "bitmaps.h"               // картинки

/*
****************************************************
* Секция, в которой настраиваются нужные контакты. *
* Чтобы активировать нужную функцию,               *
* уберите слеши у соответствующей строчки          * 
****************************************************
*/


//#define potPin        5   // входной аналоговый контакт, к которому подключается регулируемый резистор
//#define speakerPin    2   // цифровой контакт (опциональный), к которому можно подключить пьезодинамик или обычный динамик (для звука)
//#define brightnessPin 3   // выходной контакт (тоже опциональный) для управления фоновой подсветкой


/*
 * Проверяем, не маленький ли дисплей, т.к. этот код требует
 * большого дисплея.
 */
#if DISPLAY_HEIGHT < 64
#error Игра «Ракета» требует дисплея высотой как минимум 64 пикселя
#endif
#if DISPLAY_WIDTH < 128
#error Игра «Ракета» требует дисплея шириной как минимум 128 пикселей
#endif


byte brightness = 64;

#define PLAYER 0
#define ROCK1 1
#define ROCK2 2
#define ROCK3 3
#define ROCK4 4
#define ROCK5 5
#define ROCK6 6
#define ROCK7 7
#define ROCK8 8
#define BONUS 9

#define EX1 0
#define EX2 1
#define EX3 2


#define playerX tracker[0][1]
#define playerY tracker[0][2]

#define enemy1type tracker[1][0]
#define enemy1X tracker[3][1]
#define enemy1Y tracker[4][2]

#define playerXOld trackerOld[0][1]
#define playerYOld trackerOld[0][2]
#define enemy1XOld trackerOld[3][1]
#define enemy1YOld trackerOld[4][2]

char lives = 3;
char score = 0;
char level = 0;
char fastSpeed = 25;
char rockAmount = 6;

long speedMillis[] = {0, 0, 0, 0, 0, 0};

char tracker[8][5] = {
//Картинка, X,      Y,             скорость:
  {PLAYER,  15,     32,            0}  ,
  {ROCK2,   119,    random(0, 56), random(25, 75)}  ,
  {ROCK5,   119,    random(0, 56), random(25, 75)}  ,
  {ROCK8,   119,    random(0, 56), random(25, 75)}  ,
  {ROCK1,   119,    random(0, 56), random(25, 75)}  ,
  {ROCK3,   119,    random(0, 56), random(25, 75)}  ,
  {BONUS,   119,    random(0, 56), random(25, 75)}
};

char trackerOld[8][5] = {
// Картинка, X,      Y,             скорость:
  {PLAYER,  15,     32,            0}  ,
  {ROCK2,   119,    random(0, 56), random(25, 75)}  ,
  {ROCK5,   119,    random(0, 56), random(25, 75)}  ,
  {ROCK8,   119,    random(0, 56), random(25, 75)}  ,
  {ROCK1,   119,    random(0, 56), random(25, 75)}  ,
  {ROCK3,   119,    random(0, 56), random(25, 75)}  ,
  {BONUS,   119,    random(0, 56), random(25, 75)}
};

void setup(){
  GLCD.Init();
#ifdef brightnessPin
  analogWrite(brightnessPin, brightness);
#endif
#ifdef speakerPin
  pinMode(speakerPin, OUTPUT);
#endif
    
  GLCD.SelectFont(System5x7);
#ifdef potPin
  randomSeed(analogRead(potPin));
#endif
  GLCD.DrawBitmap(startup, 0, 0, BLACK);
  delay(2000);
  GLCD.ClearScreen();
}

/*
******************************
*  Главный цикл              *
*                            *
******************************
*/
void  loop(){
  getControls();
  drawFrame();
  drawLives();
  drawScore(); 
}


/*
******************************
*  Рисуем оставшиеся жизни   *
*                            *
******************************
*/
void drawLives(){
  GLCD.DrawBitmap(heart, 0, 0, BLACK);
  GLCD.CursorTo(1,0);
  GLCD.print((int)lives);
}


/*
******************************
*  Рисуем текущий счет       *
*                            *
******************************
*/
void drawScore(){
  GLCD.CursorTo(0,7);
  GLCD.print('S');
  GLCD.print((int)score);
}



/*
******************************
*  Задаем позицию ракеты     *
*                            *
******************************
*/
void getControls(){
#ifdef potPin
  playerY = map(analogRead(potPin), 0, 1023, 0, 56);
#else
/*
 * От потенциометра нет данных, поэтому начинаем двигать ракету вниз и вверх
 */
static uint8_t yval;
static uint8_t iter = 0;
static int8_t dir = 1;
  if(++iter == 0)
    yval += dir;

  if(yval == 0)
    dir = 1;

  if(yval == 56)
    dir = -1;
  playerY = yval;
#endif
}



/*
******************************
*  Обновляем позицию         *
*  астероидов                *
******************************
*/
void updatePos(int entity){
    if (millis() - speedMillis[entity-1] > tracker[entity][3]) {
      speedMillis[entity-1] = millis();
      tracker[entity][1] --;
      
        if(collision(entity) == true){
          BLOWUP();
        }
      
      if(tracker[entity][1] < 1){
        score++;
        level++;
        constrain(level, 0, 75);
        if(level > 75){
          fastSpeed --;
          constrain(fastSpeed, 10, 25);
        }
        
        tracker[entity][0] = random(1, 8);   // картинка
        tracker[entity][1] = 119;            // стартовая точка
        tracker[entity][2] = random(8, 56);  // высота
        tracker[entity][3] = random(fastSpeed, 100-level); // скорость
      }  
  }
}


/*
******************************
*  Определяем столкновения   *
*                            *
******************************
*/
boolean collision(char entity){
  for(char playerScanCOL = 0; playerScanCOL<=9; playerScanCOL++){
    if(tracker[0][1]+playerScanCOL == tracker[entity][1]+1){
      for(char playerScanROW = -1; playerScanROW < 6; playerScanROW  ++){
      for(char entityScanROW = -1; entityScanROW < 6; entityScanROW  ++){
        if(tracker[0][2]+playerScanROW == tracker[entity][2]+entityScanROW){
          return true;
         }
      }
     }
    }
  }
  return false;
}


/*
******************************
*  Взрываем корабль          *
*                            *
******************************
*/
void BLOWUP(){
  lives--;
  digitalWrite(13, HIGH);
  explosionAnim(tracker[0][1]-2, tracker[0][2]-4);
  digitalWrite(13, LOW);
  GLCD.ClearScreen();
  if(lives < 0){
    gameOver();
    lives = 3;
    level = 0;
  }
  resetTracker();
}


/*
******************************
*  Сбрасываем трекер, задаем *
*  ему новое состояние       *
******************************
*/
void resetTracker(){
  char trackerReset[8][5] = {
  {PLAYER, 15, 32, 0}  ,
  {ROCK2,   119, random(0, 56), random(25, 75)}  ,
  {ROCK5,   119, random(0, 56), random(25, 75)}  ,
  {ROCK8,   119, random(0, 56), random(25, 75)}  ,
  {ROCK1,   119, random(0, 56), random(25, 75)}  ,
  {ROCK3,   119, random(0, 56), random(25, 75)}  ,
  {BONUS,   119, random(0, 56), random(25, 75)}
  };
  
  for(byte entity = 0; entity <= 6; entity++){
    for(byte data = 0; data <= 3; data++){
      tracker[entity][data] = trackerReset[entity][data];
    }
  }
}


/*
******************************
*  Рисуем GAME OVER          *
*  и сбрасываем очки         *
******************************
*/
void gameOver(){
  GLCD.DrawBitmap(gameover, 37, 0, BLACK);
  delay(5000);
  score = 0;
  GLCD.ClearScreen();
}




/*
***********************************
* Анимированный 3-кадровый взрыв. *
* Кадрам нужен один массив.       *
***********************************
*/
void explosionAnim(char xPos, char yPos){
  GLCD.DrawBitmap(ex1, xPos, yPos, BLACK);
#ifdef speakerPin
  noise(175);
#else
  delay(175);
#endif
  GLCD.DrawBitmap(ex2, xPos, yPos, BLACK);
#ifdef speakerPin
  noise(175);
#else
  delay(175);
#endif
  GLCD.DrawBitmap(ex3, xPos, yPos, BLACK);
#ifdef speakerPin
  noise(175);
#else
  delay(175);
#endif

}


/*
*************************************
*  Рисуем рамку, игрока и астероиды *
*                                   *
*************************************
*/
void drawFrame(){
  for(int i=1; i<=rockAmount; i++){
    updatePos(i);
    drawRock(i);
  }
  if(playerY != playerYOld){
    GLCD.FillRect(playerXOld, playerYOld, 10, 8, WHITE);
    GLCD.DrawBitmap(player, playerX, playerY, BLACK);
  }

  for(byte entity = 0; entity <= 6; entity++){
    for(byte data = 0; data <= 3; data++){
      trackerOld[entity][data] = tracker[entity][data];
    }
  }
}


/*
******************************
*  Рисуем астероиды          *
*                            *
******************************
*/
void drawRock(char entity){
// Картинки астероидов должны быть в 2D-массиве; они будут уменьшены ниже
  
  if(tracker[entity][1] != trackerOld[entity][1]){

    GLCD.FillRect(trackerOld[entity][1], trackerOld[entity][2], 12, 8, WHITE);
    GLCD.DrawBitmap(rocks[tracker[entity][0]], tracker[entity][1], tracker[entity][2], BLACK);
  }
}

#ifdef speakerPin
/*
********************************************      
*  Делаем шум, который будет продолжаться  *
*  заданное количество секунд.             *
********************************************
*/
void noise(int duration)
{
  unsigned long start = millis();
  
  while( millis() - start < duration)
  {
    int period = random(8,25); 
    digitalWrite(speakerPin, HIGH);
    delay(period);
    digitalWrite(speakerPin, LOW);      
    delay(period);
  }
}  
#endif

См.также

Внешние ссылки