This shows you the differences between two versions of the page.
|
pm:prj2022:arosca:snakegamewithgyroscope [2022/05/23 20:25] gabriel.saru [Software Design] |
pm:prj2022:arosca:snakegamewithgyroscope [2022/05/27 19:29] (current) gabriel.saru [Download] |
||
|---|---|---|---|
| Line 64: | Line 64: | ||
| În codul meu am setat lungimea maximă a șarpelui la 64, care este întreaga matrice LED. Am făcut asta pentru că am vrut ca jocul să se termine doar dacă șarpele a murit și nu dacă a ajuns la o anumită lungime. | În codul meu am setat lungimea maximă a șarpelui la 64, care este întreaga matrice LED. Am făcut asta pentru că am vrut ca jocul să se termine doar dacă șarpele a murit și nu dacă a ajuns la o anumită lungime. | ||
| - | ''asd'' | + | Un mic rezumat in ceea ce fac functiile: |
| + | |||
| + | * void playGame() --> această funcție va porni jocul | ||
| + | * void draw() --> aceasta functie va apela funcțiile pentru a desena șarpele și ținta | ||
| + | * void drawSnake() --> aceasta functie va desena sarpele | ||
| + | * void drawTarget() --> aceasta functie va atrage ținta | ||
| + | * boolean inPlayField(int x, int y) --> va stabili terenul de joc pentru țintă și șarpe pentru a se spawna pe harta | ||
| + | * void makeTarget() --> aceasta functie va alege o valoare aleatorie și va stabili ținta | ||
| + | * boolean isPartOfSnake(int x, int y) --> aceasta functie se va citi dacă valoarea face parte sau nu din șarpe. | ||
| + | * void makeSnake() --> aceasta functie va stabili valorile șarpelui | ||
| + | * void moveSnake() --> această funcție va muta șarpele în funcție de accelerometru | ||
| + | * void gameOver() --> aceasta functie va afișa spectacolul de lumini și va nota după terminarea jocului | ||
| + | |||
| + | ==== Cod Sursa ==== | ||
| + | |||
| + | <code> | ||
| + | |||
| + | #include <SparkFun_MMA8452Q.h> | ||
| + | |||
| + | |||
| + | //First we need to set up some libraries so that we can use all the parts we want | ||
| + | #include <Wire.h> // we need this to use I2C which is a requirement of the | ||
| + | // acceleromter and LED matrix | ||
| + | //#include <SFE_MMA8452Q.h> // this will include the library so we can use the accelerometer | ||
| + | |||
| + | //these two libraries are so we can use the LED matrix | ||
| + | #include "Adafruit_LEDBackpack.h" | ||
| + | #include "Adafruit_GFX.h" | ||
| + | |||
| + | // these three libraries are needed to connect the Arduino with the internet and Twitter. | ||
| + | #include <SPI.h> // needed in Arduino 0019 or later | ||
| + | #include <Ethernet.h> | ||
| + | #include <EEPROM.h> // this will allow us to store memory on the Arduino. | ||
| + | |||
| + | //Now we need to set up some features for our accelerometer | ||
| + | MMA8452Q accel; | ||
| + | |||
| + | //Now we need to set up some features for our LED matrix | ||
| + | Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix(); | ||
| + | |||
| + | //Now to set up our Ethernet shield and Twitter | ||
| + | |||
| + | byte mac[] { 0x90, 0xA2, 0xDA, 0x0D, 0x14, 0x79 }; | ||
| + | //This is where you enter the information for your Ethernet shield | ||
| + | //You should find your code on a label on the bottom of the shield | ||
| + | //You want to enter it 0x## where ## is the information found on your label. | ||
| + | |||
| + | //If you want to specify a specific a IP address you can enter it like seen below | ||
| + | // byte ip[] = { 10, 3, 19, 73 }; | ||
| + | |||
| + | //Specify your Token so we can use your Twitter | ||
| + | //You can get your token from (http://arduino-tweet.appspot.com/) | ||
| + | //this is my token, make sure to use your own for it to show up on your Twitter news feed | ||
| + | |||
| + | //this will set up a message which we will use later when we want to post to Twitter | ||
| + | char msg[70]; | ||
| + | |||
| + | //Now we need to set up some variables | ||
| + | const int powerButton = 7; | ||
| + | const int sendButton = 6; | ||
| + | int resetButton; | ||
| + | const int maxSnake = 64; //this is the maximum length the snake can reach | ||
| + | int snakeX[maxSnake]; // this is the x coordinate of the snake | ||
| + | int snakeY[maxSnake]; // this is the y coordinate of the snake | ||
| + | int snakeLength = 1; // this is the starting length of the snake | ||
| + | int targetX; //this is the x coordinate of the item we are going after | ||
| + | int targetY; //the y coordinate of the item we are going after | ||
| + | unsigned long targetPrevTime = 0; //these will be used to help with the timing of the target | ||
| + | unsigned long targetBlinkTime = 1000 / 250; | ||
| + | int targetLED = LED_GREEN; | ||
| + | unsigned long prevTime = 0; | ||
| + | unsigned long delayTime = 500; | ||
| + | int score = 0; | ||
| + | |||
| + | int8_t collision = 0; | ||
| + | |||
| + | // these variables will be used to make our switch work properly | ||
| + | int mode = 0; | ||
| + | const int NUMMODES = 3; | ||
| + | |||
| + | int storedScore = 0; //this will be used to store our score inthe EEPROM | ||
| + | |||
| + | static int prevDirection; //this will be used to store the previous direction the snake was moving in | ||
| + | |||
| + | void setup() { | ||
| + | //Set up our pins as inputs | ||
| + | pinMode(powerButton, INPUT); | ||
| + | pinMode(sendButton, INPUT); | ||
| + | pinMode(resetButton, INPUT); | ||
| + | |||
| + | Serial.begin(9600); | ||
| + | |||
| + | matrix.begin(0x70); //pass in the address, set up the matrix | ||
| + | |||
| + | accel.init(); //this will intiate the accelerometer | ||
| + | randomSeed(analogRead(A0)); //we use this so that we will be able to | ||
| + | //make a random pixel light up that will serve as the target our snake is after. | ||
| + | |||
| + | makeSnake(); //this will call a function to set up where our snake will start on the matrix | ||
| + | makeTarget(); // this will call a function to set up where our target will be on the matrix. | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | // this will clear the display just in case something else was on it before | ||
| + | matrix.clear(); | ||
| + | matrix.writeDisplay(); | ||
| + | |||
| + | static int prevPowerState = 0; //this will ensure we read only the button push, and not how long it is pushed. | ||
| + | int powerButtonState = digitalRead(powerButton); //this will moniter the state of the button | ||
| + | if ((powerButtonState == HIGH) && (prevPowerState == LOW)) { | ||
| + | mode = (mode + 1) % NUMMODES; | ||
| + | } | ||
| + | prevPowerState = powerButtonState; | ||
| + | |||
| + | switch (mode) { | ||
| + | case 0: //if the button has not been pushed nothing happens | ||
| + | //Serial.println("OFF"); debug to make sure switch works properly | ||
| + | break; | ||
| + | case 1: //if the button is pushed the game starts | ||
| + | playGame(); | ||
| + | break; | ||
| + | case 2: | ||
| + | gameOver(); | ||
| + | break; | ||
| + | } | ||
| + | |||
| + | |||
| + | int sendButtonState = digitalRead(sendButton); //this will send a Tweet of the score by pushing the red button | ||
| + | if (sendButtonState == HIGH) { | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void playGame() { // this funciton will start up the game | ||
| + | |||
| + | unsigned long currentTime = millis(); | ||
| + | if (currentTime - prevTime >= delayTime) { | ||
| + | nextstep(); | ||
| + | prevTime = currentTime; | ||
| + | } | ||
| + | draw(); // this will call the draw function which will draw the snake and target | ||
| + | } | ||
| + | |||
| + | void nextstep() { | ||
| + | for (int i = snakeLength - 1; i > 0; i--) { | ||
| + | snakeX[i] = snakeX[i - 1]; | ||
| + | snakeY[i] = snakeY[i - 1]; | ||
| + | } | ||
| + | |||
| + | for (int8_t h = 3; h <= snakeLength; h++) { // this will monitor if the snake's head is colliding with another part | ||
| + | // of the snake. we use 3 because it is basically impossible for the snake to hit itself before then. | ||
| + | if ((snakeX[0] == snakeX[h]) && (snakeY[0] == snakeY[h])) | ||
| + | { | ||
| + | collision = 1; // if it is then it will send a message of collision. | ||
| + | } | ||
| + | } | ||
| + | Serial.print("Collision:"); //used for debugging to ensure the collision detection worked | ||
| + | Serial.println(collision); | ||
| + | |||
| + | if ((inPlayField(snakeX[0], snakeY[0])) && collision == 0) { // if the snake is in the playing field | ||
| + | // or not colliding with itself then we will be able to continue to play | ||
| + | moveSnake(); //this will call a function to move the snake | ||
| + | |||
| + | if ((snakeX[0] == targetX) && (snakeY[0] == targetY)) { //this will read if the snake is on the target | ||
| + | snakeLength++; //if it is it will gain a length of one | ||
| + | score++; // and the score will increase by one | ||
| + | Serial.print("Score: "); // the score will then be written on the serial monitor | ||
| + | Serial.println(score); | ||
| + | if (snakeLength < maxSnake) { // if the snake is less than the maxium lenght | ||
| + | makeTarget(); //then we will make a new target to go after | ||
| + | } | ||
| + | else { | ||
| + | targetX = targetY = -1; //if it is not less than the max, then we will not | ||
| + | //make any more targets | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | else { // if it is not in the play field or it collids with itself then the game is over. | ||
| + | mode = 2; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void draw () { //this will call the functions to draw the snake and target | ||
| + | matrix.clear(); | ||
| + | drawSnake(); | ||
| + | drawTarget(); | ||
| + | matrix.writeDisplay(); | ||
| + | } | ||
| + | |||
| + | void drawSnake() { //this will draw the snake | ||
| + | for ( int i = 0; i < snakeLength; i++) { | ||
| + | matrix.drawPixel(snakeX[i], snakeY[i], LED_GREEN); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void drawTarget() { //this will draw the target | ||
| + | if (inPlayField(targetX, targetY)) { | ||
| + | unsigned long currenttime = millis(); | ||
| + | if (currenttime - targetPrevTime >= targetBlinkTime) { | ||
| + | targetLED = (targetLED == LED_RED) ? LED_OFF : LED_RED; | ||
| + | targetPrevTime = currenttime; | ||
| + | } | ||
| + | matrix.drawPixel(targetX, targetY, targetLED); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | boolean inPlayField(int x, int y) { //this will set up the playing field for the target | ||
| + | // and snake to spawn in. | ||
| + | return (x >= 0) && (x < 8) && (y >= 0) && (y < 8); | ||
| + | } | ||
| + | |||
| + | void makeTarget() { //this will choose a random value and set up the target | ||
| + | int x; | ||
| + | int y; | ||
| + | x = random(0, 8); | ||
| + | y = random(0, 8); | ||
| + | while (isPartOfSnake(x, y)) { //here it will check if the target is part of the snake | ||
| + | x = random(0, 8); // if it is it will choose a new random point and thus continue the game | ||
| + | y = random(0, 8); | ||
| + | } | ||
| + | targetX = x; | ||
| + | targetY = y; | ||
| + | } | ||
| + | |||
| + | boolean isPartOfSnake(int x, int y) { //this will read if the value is part of the snake or not. | ||
| + | for (int i = 0; i < snakeLength - 1; i++) { | ||
| + | if ((x == snakeX[i]) && (y == snakeY[i])) { | ||
| + | return true; //if it is it will return true | ||
| + | } | ||
| + | } | ||
| + | return false; // if it is not part of the snake it will return false | ||
| + | } | ||
| + | |||
| + | |||
| + | void makeSnake() { //this will set up the values of the snake | ||
| + | |||
| + | snakeX[0] = 3; | ||
| + | snakeY[0] = 4; | ||
| + | |||
| + | for (int i = 1; i < maxSnake; i++) { | ||
| + | snakeX[i] = snakeY[i] = -1; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void moveSnake() { // this function will move the snake according to the accelerometer | ||
| + | if (accel.available()) { | ||
| + | accel.read(); //this will read the values of the accelerometer | ||
| + | Serial.print("x: "); | ||
| + | Serial.print(accel.cx, 3); | ||
| + | Serial.print("\t"); | ||
| + | Serial.print("y: "); | ||
| + | Serial.print(accel.cy, 3); | ||
| + | Serial.print("\t"); | ||
| + | Serial.print("z: "); | ||
| + | Serial.print(accel.cz, 3); | ||
| + | Serial.print("\t"); | ||
| + | Serial.println(prevDirection); | ||
| + | float restingX = 0; //the accelerometer at rest | ||
| + | float restingY = 0; | ||
| + | float threshold = 0.350; //how much it should be tilted to move the snake. | ||
| + | |||
| + | |||
| + | Serial.println(accel.cy - restingY); | ||
| + | Serial.println(accel.cx - restingX); | ||
| + | Serial.println(abs(accel.cx - restingX)); | ||
| + | |||
| + | |||
| + | if (((accel.cy - restingY) > threshold) && (abs(accel.cx - restingX) < threshold)) { //if the accelerometer is tilted left | ||
| + | Serial.println("Left"); | ||
| + | snakeY[0] = snakeY[0] + 1; // the snake will move to the left. | ||
| + | prevDirection = 1; | ||
| + | } | ||
| + | |||
| + | if (((accel.cy - restingY) < -threshold) && (abs(accel.cx - restingX) < threshold)) { //if the accelerometer is tilted right | ||
| + | Serial.println("Right"); | ||
| + | snakeY[0] = snakeY[0] - 1; // snake will move to the right | ||
| + | prevDirection = 2; | ||
| + | } | ||
| + | |||
| + | if (((accel.cx - restingX) > threshold) && (abs(accel.cy - restingY) < threshold)) { //if the accelerometer is tilted up | ||
| + | Serial.println("Up"); | ||
| + | snakeX[0] = snakeX[0] - 1; // the snake will move up | ||
| + | prevDirection = 3; | ||
| + | } | ||
| + | |||
| + | if (((accel.cx - restingX) < -threshold) && (abs(accel.cy - restingY) < threshold)) { //if the accelerometer is tilted down | ||
| + | Serial.println("Down"); | ||
| + | snakeX[0] = snakeX[0] + 1; // it will move the snake down | ||
| + | prevDirection = 4; | ||
| + | } | ||
| + | |||
| + | if ((-threshold < accel.cx) && (accel.cx < threshold) && (-threshold < accel.cy) && (accel.cy < threshold)) { | ||
| + | if (prevDirection == 1) { | ||
| + | snakeY[0] = snakeY[0] + 1; | ||
| + | } | ||
| + | if (prevDirection == 2) { | ||
| + | snakeY[0] = snakeY[0] - 1; | ||
| + | } | ||
| + | if (prevDirection == 3) { | ||
| + | snakeX[0] = snakeX[0] - 1; | ||
| + | } | ||
| + | if (prevDirection == 4) { | ||
| + | snakeX[0] = snakeX[0] + 1; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void gameOver() { //this will display the lightshow and score after the game is over | ||
| + | Serial.println("Game Over"); | ||
| + | Serial.print("Final Score: "); | ||
| + | Serial.println(score); | ||
| + | EEPROM.write (storedScore, score); | ||
| + | |||
| + | |||
| + | matrix.clear(); | ||
| + | matrix.drawPixel(3, 4, LED_YELLOW); //start a spiral lightshow from the middle to edge | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(3, 4, 4, 4, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(4, 4, 4, 3, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(4, 3, 2, 3, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(2, 3, 2, 5, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(2, 5, 5, 5, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(5, 5, 5, 2, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(5, 2, 1, 2, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(1, 2, 1, 6, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(1, 6, 6, 6, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(6, 6, 6, 1, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(6, 1, 0, 1, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(0, 1, 0, 7, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(0, 7, 7, 7, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(7, 7, 7, 0, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.drawLine(7, 0, 0, 0, LED_YELLOW); | ||
| + | matrix.writeDisplay(); | ||
| + | delay(100); | ||
| + | |||
| + | matrix.setTextWrap(false); //this will display our score on our matrix | ||
| + | matrix.setTextSize(1); | ||
| + | matrix.setTextColor(LED_YELLOW); | ||
| + | matrix.setRotation(3); | ||
| + | |||
| + | for (int8_t x = 7; x >= -36; x--) { | ||
| + | matrix.clear(); | ||
| + | matrix.setCursor(x, 0); | ||
| + | matrix.print(score); | ||
| + | matrix.writeDisplay(); | ||
| + | delay (100); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | |||
| + | </code> | ||
| ==== Rezultate Obţinute ==== | ==== Rezultate Obţinute ==== | ||
| - | TBA | + | Implementarea proiectului este urmatoarea: |
| + | {{:pm/prj2022/arosca/rezultat_sgabriel_1_resized.jpg}} | ||
| + | {{:pm/prj2022/arosca/rezultat_sgabriel_2_resized.jpg}} | ||
| ===== Concluzii ===== | ===== Concluzii ===== | ||
| - | TBA | ||
| + | Consider ca proiectul de fata implementat, este destul de util pentru o intelegere mai buna a modului de utilizare al unui Arduino, in special functiile sale principale. De asemenea, in implementarea proiectului este folositor pentru a observa si studia modul in care s-a efectuat lucrul cu datele provenite de la mai multe butoane. | ||
| ===== Download ===== | ===== Download ===== | ||
| - | <note warning> | + | * {{ :pm:prj2022:arosca:arhivaplusreadme_sarugabriel333cb.zip | Arhiva cod sursa + comentarii + README }} |
| - | O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectului: surse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-). | + | |
| + | In aceasta sectiune de DOWNLOAD putem gasi arhiva care contine urmatoarele: | ||
| + | |||
| + | * Codul sursa al proiectului; | ||
| + | * README, pentru o explicare mai succinta a functiilor din proiect; | ||
| + | * Libraria accelerometrului; | ||
| - | Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:pm:prj20??:c?** sau **:pm:prj20??:c?:nume_student** (dacă este cazul). **Exemplu:** Dumitru Alin, 331CC -> **:pm:prj2009:cc:dumitru_alin**. | ||
| - | </note> | ||
| ==== Jurnal ==== | ==== Jurnal ==== | ||
| - | Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului. | + | Ca o secțiune de jurnal, in care laborantul să poată urmări progresul proiectului. |
| - **Alegere Tema Proiect** - **12.04.2022** | - **Alegere Tema Proiect** - **12.04.2022** | ||