ENIB 2024 : Tetris te? arrête ! : Différence entre versions

De Les Fabriques du Ponant
Aller à : navigation, rechercher
(étapes de fabrication)
(Code Arduino utilisé)
Ligne 52 : Ligne 52 :
 
==fichiers à joindre==
 
==fichiers à joindre==
 
code, ficher d'impression 3D, de découpe laser ou vinyle, ...
 
code, ficher d'impression 3D, de découpe laser ou vinyle, ...
===Mettre du code Arduino===
+
// Toutes les parties de code contenant "mp3"
<syntaxhighlight lang="Arduino" line>
+
// ne sont pas utilisées ici
#define PIN 9
+
// Par manque de temps, nous n'avons pas pu coder la sortie son
#include <Arduino_GFX_Library.h>
+
// Si vous décommentez ces bouts de code, attendez vous à des bugs que nous n'avons pas identifier
  
 +
 +
 +
#include <Adafruit_NeoPixel.h>  //Downlaod here: https://electronoobs.com/eng_arduino_Adafruit_NeoPixel.php
 +
#include "EEPROMAnything.h" //module créé par le créateur du code
 +
#include <SoftwareSerial.h>
 +
#include <DFMiniMp3.h>
 +
#include "pitches.h"
 +
 +
// size of the LED grid
 +
#define GRID_W              (16)
 +
#define GRID_H              (16)
 +
#define STRAND_LENGTH      (GRID_W*GRID_H)
 +
#define LED_DATA_PIN        (16)
 +
// did you wire your grid in an 'S' instead of a 'Z'?  change this value to 0.
 +
#define BACKWARDS          (0)
 +
// max size of each tetris piece
 +
#define PIECE_W            (4)
 +
#define PIECE_H            (4)
 +
// how many kinds of pieces
 +
#define NUM_PIECE_TYPES    (7)
 +
// gravity options
 +
#define DROP_MINIMUM        (20)  // top speed gravity can reach
 +
#define DROP_ACCELERATION  (15)  // how fast gravity increases
 +
#define INITIAL_MOVE_DELAY  (100)
 +
#define INITIAL_DROP_DELAY  (500)
 +
#define INITIAL_DRAW_DELAY  (30)
 +
 +
 +
//Inputs/outputs
 +
#define MAX7219_Data_IN 15
 +
#define MAX7219_Chip_Select  4
 +
#define MAX7219_Clock 5
 +
//pin defining
 +
int button_left = 12;
 +
int button_right = 14;
 +
int button_up = 27;
 +
int button_down = 26;
 +
int button_pause = 25;
 +
int button_start = 33;
 +
 +
//define new variables
 +
byte adr = 0x08;
 +
byte num = 0x00;
 +
int i = 0;
 +
int top_score = 0;
 +
int score = 0;
 +
int top_score_1 = 0;
 +
int top_score_2 = 0;
 +
int top_score_3 = 0;
 +
int top_score_4 = 0;
 +
int score_1 = 0;
 +
int score_2 = 0;
 +
int score_3 = 0;
 +
int score_4 = 0;
 +
bool Pause = false;
 +
bool pause_onece = false;
 +
bool pause_pressed = false;
 +
unsigned long previousMillis = 0;
 +
unsigned long currentMillis = 0;
 +
 +
 +
 +
 +
 +
// 1 color drawings of each piece in each rotation.
 +
// Each piece is max 4 wide, 4 tall, and 4 rotations.
 +
// création
 +
const char piece_I[] = {
 +
  0,0,0,0,
 +
  1,1,1,1,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
 +
  0,0,1,0,
 +
  0,0,1,0,
 +
  0,0,1,0,
 +
  0,0,1,0,
 +
 
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
  1,1,1,1,
 +
  0,0,0,0,
 +
 +
  0,1,0,0,
 +
  0,1,0,0,
 +
  0,1,0,0,
 +
  0,1,0,0,
 +
};
 +
 +
const char piece_L[] = {
 +
  0,0,1,0,
 +
  1,1,1,0,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
 
 +
  0,1,0,0,
 +
  0,1,0,0,
 +
  0,1,1,0,
 +
  0,0,0,0,
 +
 +
  0,0,0,0,
 +
  1,1,1,0,
 +
  1,0,0,0,
 +
  0,0,0,0,
 +
 
 +
  1,1,0,0,
 +
  0,1,0,0,
 +
  0,1,0,0,
 +
  0,0,0,0,
 +
};
 +
 +
const char piece_J[] = {
 +
  1,0,0,0,
 +
  1,1,1,0,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
 
 +
  0,1,1,0,
 +
  0,1,0,0,
 +
  0,1,0,0,
 +
  0,0,0,0,
 +
 +
  0,0,0,0,
 +
  1,1,1,0,
 +
  0,0,1,0,
 +
  0,0,0,0,
 +
 
 +
  0,1,0,0,
 +
  0,1,0,0,
 +
  1,1,0,0,
 +
  0,0,0,0,
 +
 +
};
 +
 +
const char piece_T[] = {
 +
  0,1,0,0,
 +
  1,1,1,0,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
 +
  0,1,0,0,
 +
  0,1,1,0,
 +
  0,1,0,0,
 +
  0,0,0,0,
 +
 
 +
  0,0,0,0,
 +
  1,1,1,0,
 +
  0,1,0,0,
 +
  0,0,0,0,
 +
 +
  0,1,0,0,
 +
  1,1,0,0,
 +
  0,1,0,0,
 +
  0,0,0,0,
 +
 +
};
 +
 +
const char piece_S[] = {
 +
  0,1,1,0,
 +
  1,1,0,0,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
 +
  0,1,0,0,
 +
  0,1,1,0,
 +
  0,0,1,0,
 +
  0,0,0,0,
 +
 +
  0,0,0,0,
 +
  0,1,1,0,
 +
  1,1,0,0,
 +
  0,0,0,0,
 +
 +
  1,0,0,0,
 +
  1,1,0,0,
 +
  0,1,0,0,
 +
  0,0,0,0,
 +
};
 +
 +
const char piece_Z[] = {
 +
  1,1,0,0,
 +
  0,1,1,0,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
 
 +
  0,0,1,0,
 +
  0,1,1,0,
 +
  0,1,0,0,
 +
  0,0,0,0,
 +
 +
  0,0,0,0,
 +
  1,1,0,0,
 +
  0,1,1,0,
 +
  0,0,0,0,
 +
 
 +
  0,1,0,0,
 +
  1,1,0,0,
 +
  1,0,0,0,
 +
  0,0,0,0,
 +
};
 +
 +
const char piece_O[] = {
 +
  1,1,0,0,
 +
  1,1,0,0,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
 
 +
  1,1,0,0,
 +
  1,1,0,0,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
 
 +
  1,1,0,0,
 +
  1,1,0,0,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
 
 +
  1,1,0,0,
 +
  1,1,0,0,
 +
  0,0,0,0,
 +
  0,0,0,0,
 +
};
 +
 +
// An array of pointers! 
 +
// liste des pièces créées
 +
const char *pieces[NUM_PIECE_TYPES] = {
 +
  piece_S,
 +
  piece_Z,
 +
  piece_L,
 +
  piece_J,
 +
  piece_O,
 +
  piece_T,
 +
  piece_I,
 +
};
 +
 +
// couleurs disponibles pour les pièces
 +
const long piece_colors[NUM_PIECE_TYPES] = {
 +
  0x009900, // green S
 +
  0xFF0000, // red Z
 +
  0xFF8000, // orange L
 +
  0x000044, // blue J
 +
  0xFFFF00, // yellow O
 +
  0xFF00FF, // purple T
 +
  0x00FFFF,  // cyan I
 +
};
 +
 +
Adafruit_NeoPixel strip = Adafruit_NeoPixel(STRAND_LENGTH, LED_DATA_PIN, NEO_RGB + NEO_KHZ800);
 +
 +
// this is how arduino remembers what the button was doing in the past,
 +
// so arduino can tell when it changes.
 +
int old_button=0;
 +
// so arduino can tell when user moves sideways
 +
int old_px = 0;
 +
// so arduino can tell when user tries to turn
 +
int old_i_want_to_turn=0;
 +
//Function to shift data on the 7 segment module
 +
 +
// this is how arduino remembers the falling piece.
 +
int piece_id;
 +
int piece_rotation;
 +
int piece_x;
 +
int piece_y;
 +
 +
// the bag from which new pieces are grabbed.
 +
// the bag is only refilled when all pieces are taken.
 +
// this guarantees a maximum of 12 moves between two Is
 +
// or four S & Z in a row.
 +
char piece_sequence[NUM_PIECE_TYPES];
 +
char sequence_i=NUM_PIECE_TYPES;
 +
 +
// this controls how fast the player can move.
 +
long last_move;
 +
long move_delay=100;
 +
 +
// this controls when the piece automatically falls.
 +
long last_drop;
 +
long drop_delay;
 +
 +
long last_draw;
 +
long draw_delay;  // 60 fps
 +
 +
// this is how arduino remembers where pieces are on the grid.
 +
long grid[GRID_W*GRID_H];
 +
 +
// I want to turn on point P(x,y), which is X from the left and Y from the top.
 +
// I might also want to hold it on for us microseconds.
 +
void p(int x,int y,long color) {
 +
  int a = (GRID_H-1-y)*GRID_W;
 +
  if( ( y % 2 ) == BACKWARDS ) {  // % is modulus.
 +
    // y%2 is false when y is an even number - rows 0,2,4,6.
 +
    a += x;
 +
  } else {
 +
    // y%2 is true when y is an odd number - rows 1,3,5,7.
 +
    a += GRID_W - 1 - x;
 +
  }
 +
  a%=STRAND_LENGTH;
 +
  strip.setPixelColor(a,color);
 +
}
 +
 +
// grid contains the arduino's memory of the game board, including the piece that is falling.
 +
void draw_grid() {
 +
  int x, y;
 +
  for(y=0;y<GRID_H;++y) {
 +
    for(x=0;x<GRID_W;++x) {
 +
      if( grid[y*GRID_W+x] != 0 ) {
 +
        p(x,y,grid[y*GRID_W+x]);
 +
      } else {
 +
        p(x,y,0);
 +
      }
 +
    }
 +
  }
 +
  strip.setBrightness(100);
 +
  strip.show();
 +
}
 +
 +
// choose a new piece from the sequence.
 +
// the sequence is a random list that contains one of each piece.
 +
// that way you're guaranteed an even number of pieces over time,
 +
// tho the order is random.
 +
void choose_new_piece() {
 +
  if( sequence_i >= NUM_PIECE_TYPES ) {
 +
    // list exhausted
 +
    int i,j, k;
 +
    for(i=0;i<NUM_PIECE_TYPES;++i) {
 +
      do {
 +
        // pick a random piece
 +
        j = rand() % NUM_PIECE_TYPES;
 +
        // make sure it isn't already in the sequence.
 +
        for(k=0;k<i;++k) {
 +
          if(piece_sequence[k]==j) break;  // already in sequence
 +
        }
 +
      } while(k<i);
 +
      // not in sequence.  Add it.
 +
      piece_sequence[i] = j;
 +
    }
 +
    // rewind sequence counter
 +
    sequence_i=0;
 +
  }
 +
 
 +
  // get the next piece in the sequence.
 +
  piece_id = piece_sequence[sequence_i++];
 +
  // always start the piece top center.
 +
  piece_y=-4;  // -4 squares off the top of the screen.
 +
  piece_x=3;
 +
  // always start in the same orientation.
 +
  piece_rotation=0;
 +
}
 +
 +
void erase_piece_from_grid() {
 +
  int x, y;
 +
 
 +
  const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
 +
 
 +
  for(y=0;y<PIECE_H;++y) {
 +
    for(x=0;x<PIECE_W;++x) {
 +
      int nx=piece_x+x;
 +
      int ny=piece_y+y;
 +
      if(ny<0 || ny>GRID_H) continue;
 +
      if(nx<0 || nx>GRID_W) continue;
 +
      if(piece[y*PIECE_W+x]==1) {
 +
        grid[ny*GRID_W+nx]=0;  // zero erases the grid location.
 +
      }
 +
    }
 +
  }
 +
}
 +
 +
void add_piece_to_grid() {
 +
  int x, y;
 +
 
 +
  const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
 +
 
 +
  for(y=0;y<PIECE_H;++y) {
 +
    for(x=0;x<PIECE_W;++x) {
 +
      int nx=piece_x+x;
 +
      int ny=piece_y+y;
 +
      if(ny<0 || ny>GRID_H) continue;
 +
      if(nx<0 || nx>GRID_W) continue;
 +
      if(piece[y*PIECE_W+x]==1) {
 +
        grid[ny*GRID_W+nx]=piece_colors[piece_id];  // zero erases the grid location.
 +
      }
 +
    }
 +
  }
 +
}
 +
 +
 +
// Move everything down 1 space, destroying the old row number y in the process.
 +
void delete_row(int y) {
 +
  score = score + 10;
 +
  if(score > top_score)
 +
  {
 +
    EEPROM_writeAnything(1, score);
 +
  }
 +
 
 +
  EEPROM_readAnything(1,top_score);
 +
  top_score_1 = top_score - (  ( top_score/10 ) * 10  );
 +
  top_score_2 = ((top_score - (  ( top_score/100 ) * 100  )) - top_score_1)/10;
 +
  top_score_3 = ((top_score - (  ( top_score/1000 ) * 1000  )) - top_score_1 - top_score_2)/100;
 +
  top_score_4 = (top_score - top_score_1 - top_score_2 - top_score_3) / 1000;
 +
 
 +
  score_1 = score - (  ( score/10 ) * 10  );
 +
  score_2 = ((score - (  ( score/100 ) * 100  )) - score_1)/10;
 +
  score_3 = ((score - (  ( score/1000 ) * 1000  )) - score_1 - score_2)/100;
 +
  score_4 = (score - score_1 - score_2 - score_3) / 1000;
 +
 
 +
 
 +
  shift(0x08, score_4); //digit 7 (leftmost digit) data
 +
  shift(0x07, score_3);
 +
  shift(0x06, score_2);
 +
  shift(0x05, score_1);
 +
  shift(0x04, top_score_4);
 +
  shift(0x03, top_score_3);
 +
  shift(0x02, top_score_2);
 +
  shift(0x01, top_score_1); //digit 0 (rightmost digit) data
 +
 +
 
 +
  int x;
 +
  for(;y>0;--y) {
 +
    for(x=0;x<GRID_W;++x) {
 +
      grid[y*GRID_W+x] = grid[(y-1)*GRID_W+x];
 +
    }
 +
  }
 +
  // everything moved down 1, so the top row must be empty or the game would be over.
 +
  for(x=0;x<GRID_W;++x) {
 +
    grid[x]=0;
 +
  }
 +
}
 +
void fall_faster() {
 +
  if(drop_delay > DROP_MINIMUM) drop_delay -= DROP_ACCELERATION;
 +
}
 +
 +
// permet de retirer les lignes complétées par le joueur
 +
void remove_full_rows() {
 +
  int x, y, c;
 +
  char row_removed=0;
 +
 
 +
  for(y=0;y<GRID_H;++y) {
 +
    // count the full spaces in this row
 +
    c = 0;
 +
    for(x=0;x<GRID_W;++x) {
 +
      if( grid[y*GRID_W+x] > 0 ) c++;
 +
    }
 +
    if(c==GRID_W) {
 +
      // row full!
 +
      delete_row(y);
 +
      fall_faster();
 +
    }
 +
  } 
 +
}
 +
 +
// essayer de déplacer la pièce a gauche (left) ou à droite (right)
 +
void try_to_move_piece_sideways() { 
 +
  int new_px = 0;
 +
  if(!digitalRead(button_left)){
 +
    if(piece_can_fit(piece_x-1, piece_y, piece_rotation)==1)  {
 +
      piece_x-=1;
 +
      }
 +
  }
 +
  if(!digitalRead(button_right))
 +
  {
 +
    if(piece_can_fit(piece_x+1, piece_y, piece_rotation)==1)  {
 +
      piece_x+=1;
 +
        }
 +
  }
 +
}
 +
 +
 +
// essayer de faire tourner la pièce, avec le joystick haut
 +
void try_to_rotate_piece() {
 +
  int i_want_to_turn=0;
 +
 
 +
  // what does the joystick button say
 +
  int new_button = !digitalRead(button_up);
 +
  // if the button state has just changed AND it is being let go,
 +
  if( new_button > 0 && old_button != new_button ) {
 +
    i_want_to_turn=1;
 +
   
 +
  }
 +
  old_button=new_button;
 +
 
 +
 
 +
  if(i_want_to_turn==1 && i_want_to_turn != old_i_want_to_turn) {
 +
    // figure out what it will look like at that new angle
 +
    int new_pr = ( piece_rotation + 1 ) % 4;
 +
    // if it can fit at that new angle (doesn't bump anything)
 +
    if(piece_can_fit(piece_x,piece_y,new_pr)) {
 +
      // then make the turn.
 +
      piece_rotation = new_pr;
 +
    } else {
 +
      // wall kick
 +
      if(piece_can_fit(piece_x-1,piece_y,new_pr)) {
 +
        piece_x = piece_x-1;
 +
        piece_rotation = new_pr;
 +
      } else if(piece_can_fit(piece_x+1,piece_y,new_pr)) {
 +
        piece_x = piece_x+1;
 +
        piece_rotation = new_pr;
 +
      }
 +
    }
 +
  }
 +
  old_i_want_to_turn = i_want_to_turn;
 +
}
 +
 +
//verifie si la pièce peut aller au prochain endroit prévu
 +
int piece_can_fit(int px,int py,int pr) {
 +
  if( piece_off_edge(px,py,pr) ) return 0;
 +
  if( piece_hits_rubble(px,py,pr) ) return 0;
 +
  return 1;
 +
}
 +
 +
//verifie que la pièce ne se déplace à l'extérieur de la grille
 +
int piece_off_edge(int px,int py,int pr) {
 +
  int x,y;
 +
  const char *piece = pieces[piece_id] + (pr * PIECE_H * PIECE_W);
 +
 
 +
  for(y=0;y<PIECE_H;++y) {
 +
    for(x=0;x<PIECE_W;++x) {
 +
      int nx=px+x;
 +
      int ny=py+y;
 +
      if(ny<0) continue;  // off top, don't care
 +
      if(piece[y*PIECE_W+x]>0) {
 +
        if(nx<-1)return 1; // yes: off left side
 +
        if(nx>=GRID_W ){return 1;}  // yes: off right side
 +
      }
 +
    }
 +
  }
 +
 
 +
  return 0;  // inside limits
 +
}
 +
 +
//verifie si la pièce tape le fond de la grille ou si elle tape une autre pièce
 +
int piece_hits_rubble(int px,int py,int pr) {
 +
  int x,y;
 +
  const char *piece = pieces[piece_id] + (pr * PIECE_H * PIECE_W);
 +
 
 +
  for(y=0;y<PIECE_H;++y) {   
 +
    int ny=py+y;
 +
    if(ny<0) continue;
 +
    for(x=0;x<PIECE_W;++x) {
 +
      int nx=px+x;
 +
      if(piece[y*PIECE_W+x]>0) {
 +
        if(ny>=GRID_H ) return 1;  // yes: goes off bottom of grid     
 +
        if(grid[ny*GRID_W+nx]!=0 ) return 1;  // yes: grid already full in this space
 +
      }
 +
    }
 +
  }
 +
 
 +
  return 0;  // doesn't hit
 +
}
 +
 +
 +
void draw_restart()
 +
{
 +
  for(int i=0;i<STRAND_LENGTH;i++)
 +
  {
 +
    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
 +
    strip.setPixelColor(i, strip.Color(0,0,0)); // Moderately bright green color. 
 +
  }
 +
 +
  strip.setPixelColor(55, strip.Color(150,150,150)); 
 +
  strip.setPixelColor(74, strip.Color(150,150,150));
 +
  strip.setPixelColor(77, strip.Color(150,150,150));
 +
  strip.setPixelColor(83, strip.Color(150,150,150)); 
 +
  strip.setPixelColor(85, strip.Color(150,150,150));
 +
  strip.setPixelColor(90, strip.Color(150,150,150));
 +
  strip.setPixelColor(91, strip.Color(150,150,150));
 +
  strip.setPixelColor(92, strip.Color(150,150,150));
 +
  strip.setPixelColor(93, strip.Color(150,150,150));
 +
  strip.setPixelColor(98, strip.Color(150,150,150));
 +
  strip.setPixelColor(101, strip.Color(150,150,150));
 +
  strip.setPixelColor(106, strip.Color(150,150,150));
 +
  strip.setPixelColor(107, strip.Color(150,150,150));
 +
  strip.setPixelColor(108, strip.Color(150,150,150));
 +
  strip.setPixelColor(109, strip.Color(150,150,150));
 +
  strip.show(); // This sends the updated pixel color to the hardware.
 +
 +
  /*if(!pause_onece)
 +
  {
 +
    mp3.playMp3FolderTrack(2); 
 +
    pause_onece = true;
 +
    delay(1000);
 +
  }*/
 +
}
 +
 +
 +
 +
 +
 +
void all_white()
 +
{
 +
  for(int i=0;i<STRAND_LENGTH;i++){
 +
 +
    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
 +
    strip.setPixelColor(i, strip.Color(120,120,120)); // Moderately bright green color.
 +
    strip.show(); // This sends the updated pixel color to the hardware.
 +
    delay(3); // Delay for a period of time (in milliseconds).
 +
  }
 +
 
 +
}
 +
 +
 +
void game_over() {
 +
  score = 0;
 +
  /*mp3.playMp3FolderTrack(4);  // engine start + submarine sound*/
 +
  game_over_loop_leds();
 +
  delay(1000);
 +
  int x,y;
 +
 +
  long over_time = millis();
 +
  draw_restart();
 +
  currentMillis = millis();
 +
  previousMillis = currentMillis;
 +
  int led_number = 1;
 +
  while(millis() - over_time < 8000) {
 +
    currentMillis = millis();
 +
    if(currentMillis - previousMillis >= 1000){
 +
      previousMillis += 1000; 
 +
      strip.setPixelColor(55-led_number, strip.Color(150,150,150)); 
 +
      strip.show();
 +
      led_number += 1;
 +
    }   
 +
 
 +
   
 +
    // click the button?
 +
    if(!digitalRead(button_start)) {
 +
      // restart!
 +
      /*mp3.playMp3FolderTrack(3);  // engine start + submarine sound*/
 +
      all_white();
 +
      delay(400);
 +
      break;
 +
    }
 +
  }
 +
  /*mp3.playMp3FolderTrack(3);  // engine start + submarine sound*/
 +
  all_white();
 +
  setup();
 +
  return;
 +
}
 +
 +
 +
void game_over_loop_leds()
 +
{
 +
  for(int i=0;i<STRAND_LENGTH;i++){
 +
 +
    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
 +
    strip.setPixelColor(i, strip.Color(0,150,0)); // Moderately bright green color.
 +
 +
    strip.show(); // This sends the updated pixel color to the hardware.
 +
 +
    delay(10); // Delay for a period of time (in milliseconds).
 +
 +
  }
 +
 
 +
}
 +
 +
 +
void try_to_drop_piece() {
 +
  erase_piece_from_grid(); 
 +
  if(piece_can_fit(piece_x,piece_y+1,piece_rotation)) {
 +
    piece_y++;  // move piece down
 +
    add_piece_to_grid();
 +
  } else {
 +
    // hit something!
 +
    // put it back
 +
    add_piece_to_grid();
 +
    remove_full_rows();
 +
    if(game_is_over()==1) {
 +
      game_over();
 +
    }
 +
    // game isn't over, choose a new piece
 +
    choose_new_piece();
 +
  }
 +
}
 +
 +
 +
void try_to_drop_faster() {
 +
  if(digitalRead(button_down))
 +
  {
 +
    try_to_drop_piece();
 +
  }
 +
}
 +
 +
 +
void react_to_player() {
 +
  erase_piece_from_grid();
 +
  try_to_move_piece_sideways();
 +
  try_to_rotate_piece();
 +
  add_piece_to_grid();
 +
 
 +
  try_to_drop_faster();
 +
}
 +
 +
 +
// can the piece fit in this new location
 +
int game_is_over() {
 +
  int x,y;
 +
  const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
 +
 
 +
  for(y=0;y<PIECE_H;++y) {
 +
    for(x=0;x<PIECE_W;++x) {     
 +
      int ny=piece_y+y;
 +
      int nx=piece_x+x;
 +
      if(piece[y*PIECE_W+x]>0) {
 +
        if(ny<0) return 1;  // yes: off the top!
 +
      }
 +
    }
 +
  }
 +
 
 +
  return 0;  // not over yet...
 +
}
 +
 +
 +
void shift(byte send_to_address, byte send_this_data)
 +
{
 +
  digitalWrite(MAX7219_Chip_Select, LOW);
 +
  shiftOut(MAX7219_Data_IN, MAX7219_Clock, MSBFIRST, send_to_address);
 +
  shiftOut(MAX7219_Data_IN, MAX7219_Clock, MSBFIRST, send_this_data);
 +
  digitalWrite(MAX7219_Chip_Select, HIGH);
 +
}
 
void setup() {
 
void setup() {
   // put your setup code here, to run once:
+
 
 +
  Serial.begin(115200); 
 +
  /*mp3.begin();*/
 +
  /*uint16_t volume = mp3.getVolume();
 +
  mp3.setVolume(30);
 +
  uint16_t count = mp3.getTotalTrackCount();
 +
  delay(1000);
 +
  mp3.playMp3FolderTrack(1);*/// engine start + submarine sound
 +
  //EEPROM_writeAnything(1, 000);
 +
 
 +
  //définir les pins
 +
  pinMode(MAX7219_Data_IN, OUTPUT);
 +
  pinMode(MAX7219_Chip_Select, OUTPUT);
 +
  pinMode(MAX7219_Clock, OUTPUT);
 +
  digitalWrite(MAX7219_Clock, HIGH);
 +
 
 +
  //définir les pins pour chaque bouton
 +
  pinMode(button_pause,INPUT);
 +
  pinMode(button_start,INPUT);
 +
  pinMode(button_left,INPUT);
 +
  pinMode(button_right,INPUT);
 +
  pinMode(button_up,INPUT);
 +
  pinMode(button_down,INPUT);
 +
  delay(1);
 +
 
 +
  //Setup
 +
  shift(0x0f, 0x00); //display test register - test mode off
 +
  shift(0x0c, 0x01); //shutdown register - normal operation
 +
  shift(0x0b, 0x07); //scan limit register - display digits 0 thru 7
 +
  shift(0x0a, 0x0f); //intensity register - max brightness
 +
  shift(0x09, 0xff); //decode mode register - CodeB decode all digits
 +
 
 +
  EEPROM_readAnything(1,top_score);
 +
 
 +
  Serial.println(top_score);
 +
 
 +
  top_score_1 = top_score - (  ( top_score/10 ) * 10  );
 +
  top_score_2 = ((top_score - (  ( top_score/100 ) * 100  )) - top_score_1)/10;
 +
  top_score_3 = ((top_score - (  ( top_score/1000 ) * 1000  )) - top_score_1 - top_score_2)/100;
 +
  top_score_4 = (top_score - top_score_1 - top_score_2 - top_score_3) / 1000;
 +
 
 +
 
 +
  shift(0x08, 0x0f); //digit 7 (leftmost digit) data
 +
  shift(0x07, 0x0f);
 +
  shift(0x06, 0x0f);
 +
  shift(0x05, 0x0f);
 +
  shift(0x04, top_score_4);
 +
  shift(0x03, top_score_3);
 +
  shift(0x02, top_score_2);
 +
  shift(0x01, top_score_1); //digit 0 (rightmost digit) data
 +
 
 +
 
 +
 
 +
  int i;
 +
   // setup the LEDs
 +
  strip.begin();
 +
  strip.setBrightness(100);
 +
  strip.show(); // Initialize all pixels to 'off'
 +
 
 +
;
 +
 
 +
  // make sure arduino knows the grid is empty.
 +
  for(i=0;i<GRID_W*GRID_H;++i) {
 +
    grid[i]=0;
 +
  }
 +
 
 +
  // make the game a bit more random - pull a number from space and use it to 'seed' a crop of random numbers.
 +
  randomSeed(analogRead(4)+analogRead(2)+analogRead(3));
 +
 
 +
  // get ready to start the game.
 +
  choose_new_piece();
 +
 
 +
  move_delay=INITIAL_MOVE_DELAY;
 +
  drop_delay=INITIAL_DROP_DELAY;
 +
  draw_delay=INITIAL_DRAW_DELAY;
  
 +
  // start the game clock after everything else is ready.
 +
  last_draw = last_drop = last_move = millis();
 
}
 
}
  
 +
 +
 +
 +
//Void used for sound pause
 +
void waitMilliseconds(uint16_t msWait)
 +
{
 +
  uint32_t start = millis();
 +
 
 +
  while ((millis() - start) < msWait)
 +
  {
 +
    // calling mp3.loop() periodically allows for notifications
 +
    // to be handled without interrupts
 +
    /*mp3.loop();*/
 +
    delay(1);
 +
  }
 +
}
 +
//modifie les LED pour le mode pause
 +
void draw_pause()
 +
 +
  for(int i=0;i<STRAND_LENGTH;i++)
 +
  {
 +
    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
 +
    strip.setPixelColor(i, strip.Color(0,0,0)); // Moderately bright green color. 
 +
  }
 +
 
 +
  strip.setPixelColor(53, strip.Color(150,150,150));
 +
  strip.setPixelColor(58, strip.Color(150,150,150));
 +
  strip.setPixelColor(66, strip.Color(150,150,150));
 +
  strip.setPixelColor(67, strip.Color(150,150,150));
 +
  strip.setPixelColor(68, strip.Color(150,150,150));
 +
  strip.setPixelColor(69, strip.Color(150,150,150));
 +
  strip.setPixelColor(74, strip.Color(150,150,150));
 +
  strip.setPixelColor(77, strip.Color(150,150,150));
 +
  strip.setPixelColor(82, strip.Color(150,150,150));
 +
  strip.setPixelColor(83, strip.Color(150,150,150));
 +
  strip.setPixelColor(84, strip.Color(150,150,150));
 +
  strip.setPixelColor(85, strip.Color(150,150,150));
 +
  strip.setBrightness(100);
 +
  strip.show(); // This sends the updated pixel color to the hardware.
 +
  if(!pause_onece)
 +
  {
 +
    /*mp3.playMp3FolderTrack(2);  // engine start + submarine sound*/
 +
    pause_onece = true;
 +
    delay(1000);
 +
  }
 +
}
 +
 +
 +
 +
// called over and over after setup()
 
void loop() {
 
void loop() {
   // put your main code here, to run repeatedly:
+
   long t = millis();
  
 +
  if(!Pause)
 +
  {
 +
    if(!digitalRead(button_pause) && !pause_pressed)
 +
    {
 +
      Pause = !Pause;
 +
      pause_pressed = true;
 +
      pause_onece = false;
 +
    }
 +
    if(digitalRead(button_pause) && pause_pressed)
 +
    {     
 +
      pause_pressed = false;
 +
    }
 +
   
 +
    // the game plays at one speed,
 +
    if(t - last_move > move_delay ) {
 +
      last_move = t;
 +
      react_to_player();
 +
    }
 +
   
 +
    // ...and drops the falling block at a different speed.
 +
    if(t - last_drop > drop_delay ) {
 +
      last_drop = t;
 +
      try_to_drop_piece();
 +
    }
 +
   
 +
    // when it isn't doing those two things, it's redrawing the grid.
 +
    if(t - last_draw > draw_delay ) {
 +
      last_draw = t;
 +
      draw_grid();
 +
    }
 +
  }//end of !pause
 +
 +
  else
 +
  {
 +
    if(!digitalRead(button_pause) && !pause_pressed)
 +
    {
 +
      Pause = !Pause;
 +
      pause_pressed = true;
 +
      /*mp3.playMp3FolderTrack(1);  // engine start + submarine sound*/
 +
    }
 +
    if(digitalRead(button_pause) && pause_pressed)
 +
    {     
 +
      pause_pressed = false;
 +
    }
 +
    draw_pause();
 +
    delay(1);
 +
  }
 
}
 
}
 
</syntaxhighlight>
 
  
 
==étapes de fabrication==
 
==étapes de fabrication==

Version du 25 janvier 2024 à 14:16

Titre de la fiche expérience :

Description (résumé)

Voici les membres de notre équipe pour ce projet :

Samuel

IMG 1406.PNG


Arthur

IMG 1407.PNG

Valentin

IMG 1408.PNG

Valentin

IMG 1409.PNG


Maodan

IMG 1384(1).jpg


Le jeu que nous allons créer est un Tetris.

Introduction

Pour mener à bien le projet, nous allons le réaliser en 2 étapes : la maquette, ainsi que la version finale.

La première maquette sera réalisée à partir de carton, et la version finale sera faite en bois avec des découpes laser.

Nous nous sommes répartit différentes tâches dans le groupe pour pouvoir avancer plus vite. Les différentes parties sont la programmation,l’électronique, ainsi que la mécanique. Pour la réalisation de la documentation nous avons chacun écris ce que l'on a fais.

outil et matériel

Le matériel nécessaire que l'on a à disposition est :

- Carte esp32 Wroom - plaque labdec - afficheur - Haut parleur - Panneau led 16x16 - interrupteur - joystick - Df mini mp3

fichiers à joindre

code, ficher d'impression 3D, de découpe laser ou vinyle, ... // Toutes les parties de code contenant "mp3" // ne sont pas utilisées ici // Par manque de temps, nous n'avons pas pu coder la sortie son // Si vous décommentez ces bouts de code, attendez vous à des bugs que nous n'avons pas identifier


  1. include <Adafruit_NeoPixel.h> //Downlaod here: https://electronoobs.com/eng_arduino_Adafruit_NeoPixel.php
  2. include "EEPROMAnything.h" //module créé par le créateur du code
  3. include <SoftwareSerial.h>
  4. include <DFMiniMp3.h>
  5. include "pitches.h"

// size of the LED grid

  1. define GRID_W (16)
  2. define GRID_H (16)
  3. define STRAND_LENGTH (GRID_W*GRID_H)
  4. define LED_DATA_PIN (16)

// did you wire your grid in an 'S' instead of a 'Z'? change this value to 0.

  1. define BACKWARDS (0)

// max size of each tetris piece

  1. define PIECE_W (4)
  2. define PIECE_H (4)

// how many kinds of pieces

  1. define NUM_PIECE_TYPES (7)

// gravity options

  1. define DROP_MINIMUM (20) // top speed gravity can reach
  2. define DROP_ACCELERATION (15) // how fast gravity increases
  3. define INITIAL_MOVE_DELAY (100)
  4. define INITIAL_DROP_DELAY (500)
  5. define INITIAL_DRAW_DELAY (30)


//Inputs/outputs

  1. define MAX7219_Data_IN 15
  2. define MAX7219_Chip_Select 4
  3. define MAX7219_Clock 5

//pin defining int button_left = 12; int button_right = 14; int button_up = 27; int button_down = 26; int button_pause = 25; int button_start = 33;

//define new variables byte adr = 0x08; byte num = 0x00; int i = 0; int top_score = 0; int score = 0; int top_score_1 = 0; int top_score_2 = 0; int top_score_3 = 0; int top_score_4 = 0; int score_1 = 0; int score_2 = 0; int score_3 = 0; int score_4 = 0; bool Pause = false; bool pause_onece = false; bool pause_pressed = false; unsigned long previousMillis = 0; unsigned long currentMillis = 0;



// 1 color drawings of each piece in each rotation. // Each piece is max 4 wide, 4 tall, and 4 rotations. // création const char piece_I[] = {

 0,0,0,0,
 1,1,1,1,
 0,0,0,0,
 0,0,0,0,
 0,0,1,0,
 0,0,1,0,
 0,0,1,0,
 0,0,1,0,
 
 0,0,0,0,
 0,0,0,0,
 1,1,1,1,
 0,0,0,0,
 0,1,0,0,
 0,1,0,0,
 0,1,0,0,
 0,1,0,0,

};

const char piece_L[] = {

 0,0,1,0,
 1,1,1,0,
 0,0,0,0,
 0,0,0,0,
 
 0,1,0,0,
 0,1,0,0,
 0,1,1,0,
 0,0,0,0,
 0,0,0,0,
 1,1,1,0,
 1,0,0,0,
 0,0,0,0,
 
 1,1,0,0,
 0,1,0,0,
 0,1,0,0,
 0,0,0,0,

};

const char piece_J[] = {

 1,0,0,0,
 1,1,1,0,
 0,0,0,0,
 0,0,0,0,
 
 0,1,1,0,
 0,1,0,0,
 0,1,0,0,
 0,0,0,0,
 0,0,0,0,
 1,1,1,0,
 0,0,1,0,
 0,0,0,0,
 
 0,1,0,0,
 0,1,0,0,
 1,1,0,0,
 0,0,0,0,

};

const char piece_T[] = {

 0,1,0,0,
 1,1,1,0,
 0,0,0,0,
 0,0,0,0,
 0,1,0,0,
 0,1,1,0,
 0,1,0,0,
 0,0,0,0,
 
 0,0,0,0,
 1,1,1,0,
 0,1,0,0,
 0,0,0,0,
 0,1,0,0,
 1,1,0,0,
 0,1,0,0,
 0,0,0,0,

};

const char piece_S[] = {

 0,1,1,0,
 1,1,0,0,
 0,0,0,0,
 0,0,0,0,
 0,1,0,0,
 0,1,1,0,
 0,0,1,0,
 0,0,0,0,
 0,0,0,0,
 0,1,1,0,
 1,1,0,0,
 0,0,0,0,
 1,0,0,0,
 1,1,0,0,
 0,1,0,0,
 0,0,0,0,

};

const char piece_Z[] = {

 1,1,0,0,
 0,1,1,0,
 0,0,0,0,
 0,0,0,0,
 
 0,0,1,0,
 0,1,1,0,
 0,1,0,0,
 0,0,0,0,
 0,0,0,0,
 1,1,0,0,
 0,1,1,0,
 0,0,0,0,
 
 0,1,0,0,
 1,1,0,0,
 1,0,0,0,
 0,0,0,0,

};

const char piece_O[] = {

 1,1,0,0,
 1,1,0,0,
 0,0,0,0,
 0,0,0,0,
 
 1,1,0,0,
 1,1,0,0,
 0,0,0,0,
 0,0,0,0,
 
 1,1,0,0,
 1,1,0,0,
 0,0,0,0,
 0,0,0,0,
 
 1,1,0,0,
 1,1,0,0,
 0,0,0,0,
 0,0,0,0,

};

// An array of pointers! // liste des pièces créées const char *pieces[NUM_PIECE_TYPES] = {

 piece_S,
 piece_Z,
 piece_L,
 piece_J,
 piece_O,
 piece_T,
 piece_I,

};

// couleurs disponibles pour les pièces const long piece_colors[NUM_PIECE_TYPES] = {

 0x009900, // green S
 0xFF0000, // red Z
 0xFF8000, // orange L
 0x000044, // blue J
 0xFFFF00, // yellow O
 0xFF00FF, // purple T
 0x00FFFF,  // cyan I

};

Adafruit_NeoPixel strip = Adafruit_NeoPixel(STRAND_LENGTH, LED_DATA_PIN, NEO_RGB + NEO_KHZ800);

// this is how arduino remembers what the button was doing in the past, // so arduino can tell when it changes. int old_button=0; // so arduino can tell when user moves sideways int old_px = 0; // so arduino can tell when user tries to turn int old_i_want_to_turn=0; //Function to shift data on the 7 segment module

// this is how arduino remembers the falling piece. int piece_id; int piece_rotation; int piece_x; int piece_y;

// the bag from which new pieces are grabbed. // the bag is only refilled when all pieces are taken. // this guarantees a maximum of 12 moves between two Is // or four S & Z in a row. char piece_sequence[NUM_PIECE_TYPES]; char sequence_i=NUM_PIECE_TYPES;

// this controls how fast the player can move. long last_move; long move_delay=100;

// this controls when the piece automatically falls. long last_drop; long drop_delay;

long last_draw; long draw_delay; // 60 fps

// this is how arduino remembers where pieces are on the grid. long grid[GRID_W*GRID_H];

// I want to turn on point P(x,y), which is X from the left and Y from the top. // I might also want to hold it on for us microseconds. void p(int x,int y,long color) {

 int a = (GRID_H-1-y)*GRID_W;
 if( ( y % 2 ) == BACKWARDS ) {  // % is modulus.
   // y%2 is false when y is an even number - rows 0,2,4,6.
   a += x;
 } else {
   // y%2 is true when y is an odd number - rows 1,3,5,7.
   a += GRID_W - 1 - x;
 }
 a%=STRAND_LENGTH;
 strip.setPixelColor(a,color);

}

// grid contains the arduino's memory of the game board, including the piece that is falling. void draw_grid() {

 int x, y;
 for(y=0;y<GRID_H;++y) {
   for(x=0;x<GRID_W;++x) {
     if( grid[y*GRID_W+x] != 0 ) {
       p(x,y,grid[y*GRID_W+x]);
     } else {
       p(x,y,0);
     }
   }
 }
 strip.setBrightness(100);
 strip.show();

}

// choose a new piece from the sequence. // the sequence is a random list that contains one of each piece. // that way you're guaranteed an even number of pieces over time, // tho the order is random. void choose_new_piece() {

 if( sequence_i >= NUM_PIECE_TYPES ) {
   // list exhausted
   int i,j, k;
   for(i=0;i<NUM_PIECE_TYPES;++i) {
     do {
       // pick a random piece
       j = rand() % NUM_PIECE_TYPES;
       // make sure it isn't already in the sequence.
       for(k=0;k<i;++k) {
         if(piece_sequence[k]==j) break;  // already in sequence
       }
     } while(k<i);
     // not in sequence.  Add it.
     piece_sequence[i] = j;
   }
   // rewind sequence counter
   sequence_i=0;
 }
 
 // get the next piece in the sequence.
 piece_id = piece_sequence[sequence_i++];
 // always start the piece top center.
 piece_y=-4;  // -4 squares off the top of the screen.
 piece_x=3;
 // always start in the same orientation.
 piece_rotation=0;

}

void erase_piece_from_grid() {

 int x, y;
 
 const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
 
 for(y=0;y<PIECE_H;++y) {
   for(x=0;x<PIECE_W;++x) {
     int nx=piece_x+x;
     int ny=piece_y+y;
     if(ny<0 || ny>GRID_H) continue;
     if(nx<0 || nx>GRID_W) continue;
     if(piece[y*PIECE_W+x]==1) {
       grid[ny*GRID_W+nx]=0;  // zero erases the grid location.
     }
   }
 }

}

void add_piece_to_grid() {

 int x, y;
 
 const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
 
 for(y=0;y<PIECE_H;++y) {
   for(x=0;x<PIECE_W;++x) {
     int nx=piece_x+x;
     int ny=piece_y+y;
     if(ny<0 || ny>GRID_H) continue;
     if(nx<0 || nx>GRID_W) continue;
     if(piece[y*PIECE_W+x]==1) {
       grid[ny*GRID_W+nx]=piece_colors[piece_id];  // zero erases the grid location.
     }
   }
 }

}


// Move everything down 1 space, destroying the old row number y in the process. void delete_row(int y) {

 score = score + 10;
 if(score > top_score)
 {
   EEPROM_writeAnything(1, score);
 }
 
 EEPROM_readAnything(1,top_score);
 top_score_1 = top_score - (  ( top_score/10 ) * 10  );
 top_score_2 = ((top_score - (  ( top_score/100 ) * 100  )) - top_score_1)/10;
 top_score_3 = ((top_score - (  ( top_score/1000 ) * 1000  )) - top_score_1 - top_score_2)/100;
 top_score_4 = (top_score - top_score_1 - top_score_2 - top_score_3) / 1000;
 
 score_1 = score - (  ( score/10 ) * 10  );
 score_2 = ((score - (  ( score/100 ) * 100  )) - score_1)/10;
 score_3 = ((score - (  ( score/1000 ) * 1000  )) - score_1 - score_2)/100;
 score_4 = (score - score_1 - score_2 - score_3) / 1000;
 
 
 shift(0x08, score_4); //digit 7 (leftmost digit) data
 shift(0x07, score_3);
 shift(0x06, score_2);
 shift(0x05, score_1);
 shift(0x04, top_score_4);
 shift(0x03, top_score_3);
 shift(0x02, top_score_2);
 shift(0x01, top_score_1); //digit 0 (rightmost digit) data


 int x;
 for(;y>0;--y) {
   for(x=0;x<GRID_W;++x) {
     grid[y*GRID_W+x] = grid[(y-1)*GRID_W+x];
   }
 }
 // everything moved down 1, so the top row must be empty or the game would be over.
 for(x=0;x<GRID_W;++x) {
   grid[x]=0;
 }

} void fall_faster() {

 if(drop_delay > DROP_MINIMUM) drop_delay -= DROP_ACCELERATION;

}

// permet de retirer les lignes complétées par le joueur void remove_full_rows() {

 int x, y, c;
 char row_removed=0;
 
 for(y=0;y<GRID_H;++y) {
   // count the full spaces in this row
   c = 0;
   for(x=0;x<GRID_W;++x) {
     if( grid[y*GRID_W+x] > 0 ) c++;
   }
   if(c==GRID_W) {
     // row full!
     delete_row(y);
     fall_faster();
   }
 }  

}

// essayer de déplacer la pièce a gauche (left) ou à droite (right) void try_to_move_piece_sideways() {

 int new_px = 0;
 if(!digitalRead(button_left)){
   if(piece_can_fit(piece_x-1, piece_y, piece_rotation)==1)  {
     piece_x-=1;
     }
 }
 if(!digitalRead(button_right))
 {
   if(piece_can_fit(piece_x+1, piece_y, piece_rotation)==1)  {
     piece_x+=1;
       }
 }

}


// essayer de faire tourner la pièce, avec le joystick haut void try_to_rotate_piece() {

 int i_want_to_turn=0;
 
 // what does the joystick button say
 int new_button = !digitalRead(button_up);
 // if the button state has just changed AND it is being let go,
 if( new_button > 0 && old_button != new_button ) {
   i_want_to_turn=1;
   
 }
 old_button=new_button;
 
 
 if(i_want_to_turn==1 && i_want_to_turn != old_i_want_to_turn) {
   // figure out what it will look like at that new angle
   int new_pr = ( piece_rotation + 1 ) % 4;
   // if it can fit at that new angle (doesn't bump anything)
   if(piece_can_fit(piece_x,piece_y,new_pr)) {
     // then make the turn.
     piece_rotation = new_pr;
   } else {
     // wall kick
     if(piece_can_fit(piece_x-1,piece_y,new_pr)) {
       piece_x = piece_x-1;
       piece_rotation = new_pr;
     } else if(piece_can_fit(piece_x+1,piece_y,new_pr)) {
       piece_x = piece_x+1;
       piece_rotation = new_pr;
     } 
   }
 }
 old_i_want_to_turn = i_want_to_turn;

}

//verifie si la pièce peut aller au prochain endroit prévu int piece_can_fit(int px,int py,int pr) {

 if( piece_off_edge(px,py,pr) ) return 0;
 if( piece_hits_rubble(px,py,pr) ) return 0;
 return 1;

}

//verifie que la pièce ne se déplace à l'extérieur de la grille int piece_off_edge(int px,int py,int pr) {

 int x,y;
 const char *piece = pieces[piece_id] + (pr * PIECE_H * PIECE_W);
 
 for(y=0;y<PIECE_H;++y) {
   for(x=0;x<PIECE_W;++x) {
     int nx=px+x;
     int ny=py+y;
     if(ny<0) continue;  // off top, don't care
     if(piece[y*PIECE_W+x]>0) {
       if(nx<-1)return 1; // yes: off left side
       if(nx>=GRID_W ){return 1;}  // yes: off right side
     }
   }
 }
 
 return 0;  // inside limits

}

//verifie si la pièce tape le fond de la grille ou si elle tape une autre pièce int piece_hits_rubble(int px,int py,int pr) {

 int x,y;
 const char *piece = pieces[piece_id] + (pr * PIECE_H * PIECE_W);
 
 for(y=0;y<PIECE_H;++y) {    
   int ny=py+y;
   if(ny<0) continue;
   for(x=0;x<PIECE_W;++x) {
     int nx=px+x;
     if(piece[y*PIECE_W+x]>0) {
       if(ny>=GRID_H ) return 1;  // yes: goes off bottom of grid      
       if(grid[ny*GRID_W+nx]!=0 ) return 1;  // yes: grid already full in this space
     }
   }
 }
 
 return 0;  // doesn't hit

}


void draw_restart() {

 for(int i=0;i<STRAND_LENGTH;i++)
  {
   // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
   strip.setPixelColor(i, strip.Color(0,0,0)); // Moderately bright green color.  
  }
  strip.setPixelColor(55, strip.Color(150,150,150));  
  strip.setPixelColor(74, strip.Color(150,150,150)); 
  strip.setPixelColor(77, strip.Color(150,150,150));
  strip.setPixelColor(83, strip.Color(150,150,150));  
  strip.setPixelColor(85, strip.Color(150,150,150)); 
  strip.setPixelColor(90, strip.Color(150,150,150)); 
  strip.setPixelColor(91, strip.Color(150,150,150)); 
  strip.setPixelColor(92, strip.Color(150,150,150)); 
  strip.setPixelColor(93, strip.Color(150,150,150)); 
  strip.setPixelColor(98, strip.Color(150,150,150)); 
  strip.setPixelColor(101, strip.Color(150,150,150)); 
  strip.setPixelColor(106, strip.Color(150,150,150)); 
  strip.setPixelColor(107, strip.Color(150,150,150)); 
  strip.setPixelColor(108, strip.Color(150,150,150)); 
  strip.setPixelColor(109, strip.Color(150,150,150)); 
  strip.show(); // This sends the updated pixel color to the hardware.
  /*if(!pause_onece)
  {
   mp3.playMp3FolderTrack(2);  
   pause_onece = true;
   delay(1000);
  }*/

}



void all_white() {

 for(int i=0;i<STRAND_LENGTH;i++){
   // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
   strip.setPixelColor(i, strip.Color(120,120,120)); // Moderately bright green color.
   strip.show(); // This sends the updated pixel color to the hardware.
   delay(3); // Delay for a period of time (in milliseconds).
 }
  

}


void game_over() {

 score = 0;
 /*mp3.playMp3FolderTrack(4);  // engine start + submarine sound*/
 game_over_loop_leds();
 delay(1000);
 int x,y;
 long over_time = millis();
 draw_restart();
 currentMillis = millis();
 previousMillis = currentMillis;
 int led_number = 1;
 while(millis() - over_time < 8000) {
   currentMillis = millis();
   if(currentMillis - previousMillis >= 1000){
     previousMillis += 1000;  
     strip.setPixelColor(55-led_number, strip.Color(150,150,150));  
     strip.show();
     led_number += 1; 
   }    
  
   
   // click the button?
   if(!digitalRead(button_start)) {
     // restart!
     /*mp3.playMp3FolderTrack(3);  // engine start + submarine sound*/
     all_white();
     delay(400);
     break;
   }
 }
 /*mp3.playMp3FolderTrack(3);  // engine start + submarine sound*/
 all_white();
 setup();
 return;

}


void game_over_loop_leds() {

 for(int i=0;i<STRAND_LENGTH;i++){
   // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
   strip.setPixelColor(i, strip.Color(0,150,0)); // Moderately bright green color.
   strip.show(); // This sends the updated pixel color to the hardware.
   delay(10); // Delay for a period of time (in milliseconds).
 }
 

}


void try_to_drop_piece() {

 erase_piece_from_grid();  
 if(piece_can_fit(piece_x,piece_y+1,piece_rotation)) {
   piece_y++;  // move piece down
   add_piece_to_grid();
 } else {
   // hit something!
   // put it back
   add_piece_to_grid();
   remove_full_rows();
   if(game_is_over()==1) {
     game_over();
   }
   // game isn't over, choose a new piece
   choose_new_piece();
 }

}


void try_to_drop_faster() {

 if(digitalRead(button_down))
 {
   try_to_drop_piece();
 }

}


void react_to_player() {

 erase_piece_from_grid();
 try_to_move_piece_sideways();
 try_to_rotate_piece();
 add_piece_to_grid();
 
 try_to_drop_faster();

}


// can the piece fit in this new location int game_is_over() {

 int x,y;
 const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
 
 for(y=0;y<PIECE_H;++y) {
   for(x=0;x<PIECE_W;++x) {      
     int ny=piece_y+y;
     int nx=piece_x+x;
     if(piece[y*PIECE_W+x]>0) {
       if(ny<0) return 1;  // yes: off the top!
     }
   }
 }
 
 return 0;  // not over yet...

}


void shift(byte send_to_address, byte send_this_data) {

 digitalWrite(MAX7219_Chip_Select, LOW);
 shiftOut(MAX7219_Data_IN, MAX7219_Clock, MSBFIRST, send_to_address);
 shiftOut(MAX7219_Data_IN, MAX7219_Clock, MSBFIRST, send_this_data);
 digitalWrite(MAX7219_Chip_Select, HIGH);

} void setup() {

 Serial.begin(115200);  
 /*mp3.begin();*/
 /*uint16_t volume = mp3.getVolume();
 mp3.setVolume(30);
 uint16_t count = mp3.getTotalTrackCount();
 delay(1000);
 mp3.playMp3FolderTrack(1);*/// engine start + submarine sound
 //EEPROM_writeAnything(1, 000);
 //définir les pins 
 pinMode(MAX7219_Data_IN, OUTPUT);
 pinMode(MAX7219_Chip_Select, OUTPUT);
 pinMode(MAX7219_Clock, OUTPUT);
 digitalWrite(MAX7219_Clock, HIGH);
 //définir les pins pour chaque bouton
 pinMode(button_pause,INPUT);
 pinMode(button_start,INPUT);
 pinMode(button_left,INPUT);
 pinMode(button_right,INPUT);
 pinMode(button_up,INPUT);
 pinMode(button_down,INPUT);
 delay(1);
 //Setup
 shift(0x0f, 0x00); //display test register - test mode off
 shift(0x0c, 0x01); //shutdown register - normal operation
 shift(0x0b, 0x07); //scan limit register - display digits 0 thru 7
 shift(0x0a, 0x0f); //intensity register - max brightness
 shift(0x09, 0xff); //decode mode register - CodeB decode all digits
 
 EEPROM_readAnything(1,top_score);
 Serial.println(top_score);
 
 top_score_1 = top_score - (  ( top_score/10 ) * 10  );
 top_score_2 = ((top_score - (  ( top_score/100 ) * 100  )) - top_score_1)/10;
 top_score_3 = ((top_score - (  ( top_score/1000 ) * 1000  )) - top_score_1 - top_score_2)/100;
 top_score_4 = (top_score - top_score_1 - top_score_2 - top_score_3) / 1000;
 
 
 shift(0x08, 0x0f); //digit 7 (leftmost digit) data
 shift(0x07, 0x0f);
 shift(0x06, 0x0f);
 shift(0x05, 0x0f);
 shift(0x04, top_score_4);
 shift(0x03, top_score_3);
 shift(0x02, top_score_2);
 shift(0x01, top_score_1); //digit 0 (rightmost digit) data


 int i;
 // setup the LEDs
 strip.begin();
 strip.setBrightness(100);
 strip.show(); // Initialize all pixels to 'off'
 
 // make sure arduino knows the grid is empty.
 for(i=0;i<GRID_W*GRID_H;++i) {
   grid[i]=0;
 }
 
 // make the game a bit more random - pull a number from space and use it to 'seed' a crop of random numbers.
 randomSeed(analogRead(4)+analogRead(2)+analogRead(3));
 
 // get ready to start the game.
 choose_new_piece();
 
 move_delay=INITIAL_MOVE_DELAY;
 drop_delay=INITIAL_DROP_DELAY;
 draw_delay=INITIAL_DRAW_DELAY;
 // start the game clock after everything else is ready.
 last_draw = last_drop = last_move = millis();

}



//Void used for sound pause void waitMilliseconds(uint16_t msWait) {

 uint32_t start = millis();
 
 while ((millis() - start) < msWait)
 {
   // calling mp3.loop() periodically allows for notifications 
   // to be handled without interrupts
   /*mp3.loop();*/
   delay(1);
 }

} //modifie les LED pour le mode pause void draw_pause() {

  for(int i=0;i<STRAND_LENGTH;i++)
  {
   // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
   strip.setPixelColor(i, strip.Color(0,0,0)); // Moderately bright green color.  
  }
  
  strip.setPixelColor(53, strip.Color(150,150,150)); 
  strip.setPixelColor(58, strip.Color(150,150,150)); 
  strip.setPixelColor(66, strip.Color(150,150,150)); 
  strip.setPixelColor(67, strip.Color(150,150,150)); 
  strip.setPixelColor(68, strip.Color(150,150,150)); 
  strip.setPixelColor(69, strip.Color(150,150,150)); 
  strip.setPixelColor(74, strip.Color(150,150,150)); 
  strip.setPixelColor(77, strip.Color(150,150,150)); 
  strip.setPixelColor(82, strip.Color(150,150,150)); 
  strip.setPixelColor(83, strip.Color(150,150,150)); 
  strip.setPixelColor(84, strip.Color(150,150,150)); 
  strip.setPixelColor(85, strip.Color(150,150,150));
  strip.setBrightness(100);
  strip.show(); // This sends the updated pixel color to the hardware.
  if(!pause_onece)
  {
   /*mp3.playMp3FolderTrack(2);  // engine start + submarine sound*/
   pause_onece = true;
   delay(1000);
  }

}


// called over and over after setup() void loop() {

 long t = millis();
 if(!Pause)
 {
   if(!digitalRead(button_pause) && !pause_pressed)
   {
     Pause = !Pause;
     pause_pressed = true;
     pause_onece = false;
   }
   if(digitalRead(button_pause) && pause_pressed)
   {      
     pause_pressed = false;
   }
   
   // the game plays at one speed,
   if(t - last_move > move_delay ) {
     last_move = t;
     react_to_player();
   }
   
   // ...and drops the falling block at a different speed.
   if(t - last_drop > drop_delay ) {
     last_drop = t;
     try_to_drop_piece();
   }
   
   // when it isn't doing those two things, it's redrawing the grid.
   if(t - last_draw > draw_delay ) {
     last_draw = t;
     draw_grid();
   }
 }//end of !pause
 else
 {
   if(!digitalRead(button_pause) && !pause_pressed)
   {
     Pause = !Pause;
     pause_pressed = true;
     /*mp3.playMp3FolderTrack(1);  // engine start + submarine sound*/
   }
   if(digitalRead(button_pause) && pause_pressed)
   {      
     pause_pressed = false;
   }
   draw_pause();
   delay(1);
 }

}

étapes de fabrication

indiquer autant d'étape que nécessaire, chacune illustrée par des images (phot, dessins, ...)

étape 1

Réalisation de la maquette.

Pour la maquette, on a récupéré un quadrillage pour les led d'un projet précédent. Nous l'avons entouré de carton pour le maintenir et pouvoir faire la première version.

Il aurait été inutile de faire un boitier en carton pour mettre les composants tels que le joystick ainsi que les boutons, car les composants sont les mêmes pour la version finale.

C'est pour cela que nous avons minimisé un maximum la version de maquette.

Voici la maquette :


IMG 1412.JPG

étape 2

On s'intéresse ensuite à la conception mécanique de notre structure. On a pensé à réaliser un écran ainsi qu'un tableau de bord avec le joystick et les boutons.

Pour la conception, on utilise Solidworks. On a au final ce modèle :

Solidworks tetris.png


On utilisera une découpe laser pour que ce soit plus rapide et moins risqué à imprimer.

Voici les découpes :

IMG 1414.JPG

étape 3

En parallèle, on s'occupe aussi de la programmation. On utilisera le code présenté précédemment.

Pour la partie électronique, on a testé plusieurs composants tels que le joystick pour savoir quel câble correspondait à quelle direction. Nous avons aussi fait marcher en premier la carte Arduino.Les boutons ainsi que le registre ont été testés pour bien comprendre leur fonctionnement.

On a donc implémenté chacun des composants nécessaires au fur et à mesure, tout en câblant sur la plaque labdec. Il faut bien prendre en compte les résistances de pull-up dans le montage, elles sont indispensables pour le bon fonctionnement des composants à faible résistance, tels que le bouton et le joystick.

On a donc le montage suivant ensuite :

IMG 1417.JPG


Remarque : il est important de détailler chacun des fils en mettant des bouts de scotch pour décrire l’utilisation des fils. Par exemple, mettre "droite" pour le fil qui gère la droite du joystick, cela nous permettra de ne pas faire d'erreur de câblage.

Voici la première fois que l'on a pu jouer au jeu :

IMG 14201.JPG

étape 4

Montage comlet

troubleshouting

Un des problèmes majeurs que l'on a rencontré est l'absence de résistance de pull-up. En effet, ces résistances servent à bien déterminer le niveau haut et le niveau bas, pour que l'on ne connecte pas le 5v à la masse si le composant à une faible résistance. Donc pour les composants tels que les boutons ainsi que le joystick il faut mettre des résistances de pull-up.

Sources et documentation complémentaire

ne pas modifier sous cette ligne