Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2025:fstancu:david_ionut.luca [2025/05/28 08:51]
david_ionut.luca
pm:prj2025:fstancu:david_ionut.luca [2025/05/28 09:53] (current)
david_ionut.luca
Line 1: Line 1:
 ====== Snake Game - Luca David-Ionut 334CD ====== ====== Snake Game - Luca David-Ionut 334CD ======
 +
 +**__MILESTONE 1 - TEMA PROIECT__**
  
 Acest proiect constă într-o implementare a jocului Snake clasic pe platforma Arduino Uno R3.  O caracteristică importantă este controlul vitezei șarpelui prin intermediul unui potențiometru,​ iar scorul obținut de jucător este vizualizat pe un display LCD. Acest proiect constă într-o implementare a jocului Snake clasic pe platforma Arduino Uno R3.  O caracteristică importantă este controlul vitezei șarpelui prin intermediul unui potențiometru,​ iar scorul obținut de jucător este vizualizat pe un display LCD.
Line 95: Line 97:
 Am utilizat funcția map() pentru a converti valorile citite de la ADC într-un interval de milisecunde ajustabil. Am utilizat funcția map() pentru a converti valorile citite de la ADC într-un interval de milisecunde ajustabil.
  
 +
 +    #include <​U8g2lib.h>​
 +    #include <​avr/​io.h>​
 +    #include <​avr/​interrupt.h>​
 +    #include <​Arduino.h>​
 +    ​
 +    const int buttonRight = 2;
 +    const int buttonDown = 3;
 +    const int buttonUp = 4;
 +    const int buttonLeft = 9;
 +    const int analogPin = A0;
 +
 +    #define LEFT 1
 +    #define DOWN 2
 +    #define UP 3
 +    #define RIGHT 4
 +
 +    #define CS_PIN 10
 +    #define RST_PIN 8
 +
 +    U8G2_ST7920_128X64_F_HW_SPI u8g2(U8G2_R0,​ CS_PIN, RST_PIN);
 +
 +    volatile int direction = 0;
 +    int analogValue = 0;
 +    int delay_ms = 0;
 +
 +    int dotX;
 +    int dotY;
 +    int newHeadX;
 +    int newHeadY;
 +    const int dotRadius = 4;
 +    const int moveStep = 4;
 +    const int gameWidth = 96;
 +    ​
 +    #define MAX_SNAKE_LENGTH 50
 +    int snakeX[MAX_SNAKE_LENGTH];​
 +    int snakeY[MAX_SNAKE_LENGTH];​
 +    int snakeLength = 1;
 +
 +    int scoreX;
 +    int scoreY;
 +    int score = 0;
 +    int record = 0;
 +
 +    int manhattanDistance(int x1, int y1, int x2, int y2) {
 +        return abs(x1 - x2) + abs(y1 - y2);
 +    }
 +
 +    int isCloseToSnake(int x, int y) {
 +        for (int i = 0; i < snakeLength;​ i++) {
 +            if (manhattanDistance(x,​ y, snakeX[i], snakeY[i]) < 4) {
 +                return 1;
 +            }
 +        }
 +        return 0;
 +    }
 +
 +    void generateScorePoint() {
 +        int newX, newY;
 +        do {
 +            newX = random(dotRadius,​ gameWidth - dotRadius);
 +            newY = random(dotRadius,​ u8g2.getHeight() - dotRadius);
 +            newX -= newX % moveStep;
 +            newY -= newY % moveStep;
 +        } while (isCloseToSnake(newX,​ newY));
 +
 +        scoreX = newX;
 +        scoreY = newY;
 +    }
 +
 +    void resetGame() {
 +        dotX = gameWidth / 2 - (gameWidth / 2) % moveStep;
 +        dotY = u8g2.getHeight() / 2 - (u8g2.getHeight() / 2) % moveStep;
 +        direction = 0;
 +        score = 0;
 +        snakeLength = 1;
 +        generateScorePoint();​
 +    }
 +
 +    void showGameOver() {
 +        u8g2.clearBuffer();​
 +        u8g2.setFont(u8g2_font_ncenB14_tr);​
 +        const char* gameOverText = "GAME OVER";
 +        int textWidth = u8g2.getStrWidth(gameOverText);​
 +        int textX = (u8g2.getWidth() - textWidth) / 2;
 +        int textY = u8g2.getHeight() / 2;
 +        u8g2.drawStr(textX,​ textY, gameOverText);​
 +        u8g2.sendBuffer();​
 +        delay(3000);​
 +    ​
 +        if (score > record) {
 +            record = score;
 +            u8g2.clearBuffer();​
 +            u8g2.setFont(u8g2_font_ncenB14_tr);​
 +            const char* highScoreText = "​RECORD";​
 +            textWidth = u8g2.getStrWidth(highScoreText);​
 +            textX = (u8g2.getWidth() - textWidth) / 2;
 +            int textY = u8g2.getHeight() / 2;
 +            u8g2.drawStr(textX,​ textY, highScoreText);​
 +            u8g2.sendBuffer();​
 +            delay(3000);​
 +        }
 +    }
 +
 +    int readADC(uint8_t channel) {
 +        ADMUX = (0 << REFS1) | (1 << REFS0) | (channel & 0x07);
 +        ADCSRA |= (1 << ADSC);
 +        while (ADCSRA & (1 << ADSC));
 +        return ADCW;
 +    }
 +
 +    void SPI_MasterInit(void) {
 +        DDRB |= (1 << DDB3) | (1 << DDB5) | (1 << DDB2);
 +        SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
 +    }
 +
 +    void setup() {
 +        DDRD &= ~((1 << PIND2) | (1 << PIND3) | (1 << PIND4));
 +        PORTD |= (1 << PIND2) | (1 << PIND3) | (1 << PIND4);
 +    ​
 +        DDRB &= ~(1 << PINB1);
 +        PORTB |= (1 << PINB1);
 +        ​
 +        UBRR0H = (uint8_t)(51 & 0xF00);
 +        UBRR0L = (uint8_t)(51 & 0x0FF);
 +        UCSR0B = (1 << RXEN0) | (1 << TXEN0);
 +        UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
 +
 +        ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR);
 +        ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
 +
 +        randomSeed(readADC(1));​
 +
 +        EICRA |= (1 << ISC11) | (1 << ISC01);
 +        EIMSK |= (1 << INT1) | (1 << INT0);
 +    ​
 +        PCICR |= (1 << PCIE2) | (1 << PCIE0);
 +        PCMSK0 |= (1 << PCINT1);
 +        PCMSK2 |= (1 << PCINT20);
 +    ​
 +        sei();
 +        Serial.begin(9600);​
 +
 +        SPI_MasterInit(); ​
 +
 +        u8g2.begin();​
 +
 +        resetGame();​
 +    }
 +
 +    ISR(INT0_vect) {
 +        if (direction != LEFT)
 +            direction = RIGHT;
 +        delayMicroseconds(20000);​
 +    }
 +
 +    ISR(INT1_vect) {
 +        if (direction != UP)
 +            direction = DOWN;
 +        delayMicroseconds(20000);​
 +    }
 +
 +    ISR(PCINT2_vect) {
 +        if (!((PIND >> PIND4) & 1)) {
 +            if (direction != DOWN)
 +                direction = UP;
 +        }
 +        delayMicroseconds(20000);​
 +    }
 +
 +    ISR(PCINT0_vect) {
 +        if (!((PINB >> PINB1) & 1)) {
 +            if (direction != RIGHT)
 +                direction = LEFT;
 +        }
 +        delayMicroseconds(20000);​
 +    }
 +
 +    void loop() {
 +        u8g2.clearBuffer();​
 +    ​
 +        analogValue = readADC(0);
 +        delay_ms = map(analogValue,​ 0, 1023, 0, 200);
 +    ​
 +        switch (direction) {
 +            case LEFT:
 +                dotX -= moveStep;
 +                break;
 +            case RIGHT:
 +                dotX += moveStep;
 +                break;
 +            case UP:
 +                dotY -= moveStep;
 +                break;
 +            case DOWN:
 +                dotY += moveStep;
 +                break;
 +        }
 +
 +        if (dotX < 0 || dotX >= gameWidth || dotY < 0 || dotY >= u8g2.getHeight()) {
 +            showGameOver();​
 +            resetGame();​
 +        }
 +
 +        newHeadX = dotX;
 +        newHeadY = dotY;
 +    ​
 +        if (dotX == scoreX && dotY == scoreY) {
 +            score++;
 +            snakeLength++;​
 +            if (snakeLength > MAX_SNAKE_LENGTH) {
 +                snakeLength = MAX_SNAKE_LENGTH;​
 +            }
 +            generateScorePoint();​
 +        }
 +
 +        for (int i = 1; i < snakeLength;​ i++) {
 +            if (snakeX[i] == dotX && snakeY[i] == dotY) {
 +                showGameOver();​
 +                resetGame();​
 +            }
 +        }
 +    ​
 +        for (int i = snakeLength - 1; i > 0; i--) {
 +            snakeX[i] = snakeX[i - 1];
 +            snakeY[i] = snakeY[i - 1];
 +        }
 +        snakeX[0] = newHeadX;
 +        snakeY[0] = newHeadY;
 +
 +        u8g2.setDrawColor(1);​
 +        for (int i = 0; i < snakeLength;​ i++) {
 +            u8g2.drawBox(snakeX[i],​ snakeY[i], dotRadius, dotRadius);
 +        }
 +        u8g2.drawBox(scoreX,​ scoreY, dotRadius, dotRadius);
 +        u8g2.drawVLine(gameWidth,​ 0, u8g2.getHeight());​
 +        u8g2.setFont(u8g2_font_6x10_tf);​
 +        char scoreTextDisplay[10];​
 +        sprintf(scoreTextDisplay,​ "​Scor"​);​
 +        u8g2.drawStr(gameWidth + (u8g2.getWidth() - gameWidth - u8g2.getStrWidth(scoreTextDisplay)) / 2, 10, scoreTextDisplay);​
 +        u8g2.setFont(u8g2_font_7x13_tf);​
 +        char scoreString[5];​
 +        sprintf(scoreString,​ "​%d",​ score);
 +        u8g2.drawStr(gameWidth + (u8g2.getWidth() - gameWidth - u8g2.getStrWidth(scoreString)) / 2, 25, scoreString);​
 +        u8g2.drawHLine(gameWidth,​ u8g2.getHeight() / 2, u8g2.getWidth() - gameWidth);
 +        u8g2.setFont(u8g2_font_6x10_tf);​
 +        char recordText[10];​
 +        sprintf(recordText,​ "​Best"​);​
 +        u8g2.drawStr(gameWidth + (u8g2.getWidth() - gameWidth - u8g2.getStrWidth(recordText)) / 2, u8g2.getHeight() / 2 + 11, recordText);​
 +        u8g2.setFont(u8g2_font_7x13_tf);​
 +        char recordString[5];​
 +        sprintf(recordString,​ "​%d",​ record);
 +        u8g2.drawStr(gameWidth + (u8g2.getWidth() - gameWidth - u8g2.getStrWidth(recordString)) / 2, u8g2.getHeight() / 2 + 26, recordString);​
 +    ​
 +        u8g2.sendBuffer();​
 +        Serial.println(delay_ms);​
 +    ​
 +        delay(100 + delay_ms);
 +    }
  
  
  
pm/prj2025/fstancu/david_ionut.luca.1748411472.txt.gz · Last modified: 2025/05/28 08:51 by david_ionut.luca
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0