描述
<div>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">* 1、项目功能介绍</h3>
<hr>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:14px;">基于ESP32的贪吃蛇游戏机,能够使用摇杆控制,能够穿过边界,当蛇头碰到蛇身游戏结束</span></p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*2、项目属性</h3>
<hr>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:14px;">原创项目,未在其他比赛中获奖</span></p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">* 3、开源协议</h3>
<hr>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:14px;">GPL3.0</span></p>
<p> </p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*4、硬件部分</h3>
<hr>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:14px;">使用ESP32开发板,摇杆,微动按键,蜂鸣器,预留IP5306充放电电路。</span></p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*5、软件部分</h3>
<hr>
<div>
<div>#include</div>
<br>
<div>// 定义WS2812B灯板参数</div>
<div>#define LED_PIN 13</div>
<div>#define LED_WIDTH 8</div>
<div>#define LED_HEIGHT 8</div>
<div>#define NUM_LEDS (LED_WIDTH * LED_HEIGHT)</div>
<br>
<div>// 定义摇杆引脚</div>
<div>#define JOYSTICK_X 34</div>
<div>#define JOYSTICK_Y 35</div>
<br>
<div>// 摇杆阈值定义(更灵敏的阈值设置)</div>
<div>#define THRESHOLD 200 // 降低阈值,提高灵敏度</div>
<div>#define CENTER_MIN 512 - THRESHOLD</div>
<div>#define CENTER_MAX 512 + THRESHOLD</div>
<br>
<div>// 创建NeoPixel对象</div>
<div>Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);</div>
<br>
<div>// 游戏参数</div>
<div>int snake[64][2];</div>
<div>int snakeLength = 3;</div>
<div>int food[2];</div>
<div>int dir[2] = {1, 0}; // 当前方向</div>
<div>int nextDir[2] = {1, 0}; // 下一个方向(确保转向后不回退)</div>
<div>bool gameOver = false;</div>
<div>unsigned long lastMoveTime = 0;</div>
<div>int moveDelay = 300;</div>
<div>unsigned long lastReadTime = 0;</div>
<div>int readInterval = 50; // 更高频率检测摇杆输入(50ms一次)</div>
<br>
<div>// 颜色定义</div>
<div>uint32_t snakeColor = strip.Color(0, 255, 0);</div>
<div>uint32_t foodColor = strip.Color(255, 0, 0);</div>
<div>uint32_t bgColor = strip.Color(0, 0, 0);</div>
<div>uint32_t gameOverColor = strip.Color(255, 0, 0);</div>
<br>
<div>void setup() {</div>
<div> strip.begin();</div>
<div> strip.show();</div>
<div> </div>
<div> // 初始化蛇的位置</div>
<div> snake[0][0] = 3; snake[0][1] = 4;</div>
<div> snake[1][0] = 2; snake[1][1] = 4;</div>
<div> snake[2][0] = 1; snake[2][1] = 4;</div>
<div> </div>
<div> generateFood();</div>
<div>}</div>
<br>
<div>void loop() {</div>
<div> if (!gameOver) {</div>
<div> // 高频检测摇杆输入</div>
<div> if (millis() - lastReadTime > readInterval) {</div>
<div> readJoystick();</div>
<div> lastReadTime = millis();</div>
<div> }</div>
<div> </div>
<div> // 定时移动蛇</div>
<div> if (millis() - lastMoveTime > moveDelay) {</div>
<div> moveSnake();</div>
<div> checkCollision();</div>
<div> drawGame();</div>
<div> lastMoveTime = millis();</div>
<div> }</div>
<div> } else {</div>
<div> gameOverAnimation();</div>
<div> int x = analogRead(JOYSTICK_X);</div>
<div> int y = analogRead(JOYSTICK_Y);</div>
<div> if (x < CENTER_MIN || x > CENTER_MAX || y < CENTER_MIN || y > CENTER_MAX) {</div>
<div> restartGame();</div>
<div> }</div>
<div> }</div>
<div>}</div>
<br>
<div>// 摇杆输入读取函数</div>
<div>void readJoystick() {</div>
<div> int xValue = analogRead(JOYSTICK_X);</div>
<div> int yValue = analogRead(JOYSTICK_Y);</div>
<div> </div>
<div> // 优先检测X轴方向(左右)</div>
<div> bool xMoved = false;</div>
<div> if (xValue < CENTER_MIN && dir[0] != 1) { // 左</div>
<div> nextDir[0] = -1;</div>
<div> nextDir[1] = 0;</div>
<div> xMoved = true;</div>
<div> }</div>
<div> else if (xValue > CENTER_MAX && dir[0] != -1) { // 右</div>
<div> nextDir[0] = 1;</div>
<div> nextDir[1] = 0;</div>
<div> xMoved = true;</div>
<div> }</div>
<div> </div>
<div> // 检测Y轴方向(上下),如果X轴没有输入才处理Y轴</div>
<div> if (!xMoved) {</div>
<div> if (yValue < CENTER_MIN && dir[1] != 1) { // 上</div>
<div> nextDir[0] = 0;</div>
<div> nextDir[1] = -1;</div>
<div> }</div>
<div> else if (yValue > CENTER_MAX && dir[1] != -1) { // 下</div>
<div> nextDir[0] = 0;</div>
<div> nextDir[1] = 1;</div>
<div> }</div>
<div> }</div>
<div>}</div>
<br>
<div>// 移动蛇</div>
<div>void moveSnake() {</div>
<div> // 更新方向</div>
<div> dir[0] = nextDir[0];</div>
<div> dir[1] = nextDir[1];</div>
<div> </div>
<div> // 移动身体</div>
<div> for (int i = snakeLength - 1; i > 0; i--) {</div>
<div> snake[i][0] = snake[i-1][0];</div>
<div> snake[i][1] = snake[i-1][1];</div>
<div> }</div>
<div> </div>
<div> // 移动头部并处理穿墙逻辑</div>
<div> snake[0][0] += dir[0];</div>
<div> snake[0][1] += dir[1];</div>
<div> </div>
<div> // 穿墙处理:当蛇头超出边界时,从对面出现</div>
<div> if (snake[0][0] < 0) {</div>
<div> snake[0][0] = LED_WIDTH - 1; // 左边穿出,从右边进入</div>
<div> } else if (snake[0][0] >= LED_WIDTH) {</div>
<div> snake[0][0] = 0; // 右边穿出,从左边进入</div>
<div> }</div>
<div> </div>
<div> if (snake[0][1] < 0) {</div>
<div> snake[0][1] = LED_HEIGHT - 1; // 上边穿出,从下边进入</div>
<div> } else if (snake[0][1] >= LED_HEIGHT) {</div>
<div> snake[0][1] = 0; // 下边穿出,从上边进入</div>
<div> }</div>
<div> </div>
<div> // 检查是否吃到食物</div>
<div> if (snake[0][0] == food[0] && snake[0][1] == food[1]) {</div>
<div> snakeLength++;</div>
<div> generateFood();</div>
<div> if (moveDelay > 100) {</div>
<div> moveDelay -= 10;</div>
<div> }</div>
<div> }</div>
<div>}</div>
<br>
<div>// 检查碰撞(只检测自身碰撞,不检测墙壁碰撞)</div>
<div>void checkCollision() {</div>
<div> // 只检查蛇头是否碰到自己的身体</div>
<div> for (int i = 1; i < snakeLength; i++) {</div>
<div> if (snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1]) {</div>
<div> gameOver = true;</div>
<div> return;</div>
<div> }</div>
<div> }</div>
<div>}</div>
<br>
<div>// 生成食物</div>
<div>void generateFood() {</div>
<div> bool onSnake;</div>
<div> </div>
<div> do {</div>
<div> onSnake = false;</div>
<div> food[0] = random(LED_WIDTH);</div>
<div> food[1] = random(LED_HEIGHT);</div>
<div> </div>
<div> for (int i = 0; i < snakeLength; i++) {</div>
<div> if (snake[i][0] == food[0] && snake[i][1] == food[1]) {</div>
<div> onSnake = true;</div>
<div> break;</div>
<div> }</div>
<div> }</div>
<div> } while (onSnake);</div>
<div>}</div>
<br>
<div>// 绘制游戏</div>
<div>void drawGame() {</div>
<div> for (int i = 0; i < NUM_LEDS; i++) {</div>
<div> strip.setPixelColor(i, bgColor);</div>
<div> }</div>
<div> </div>
<div> for (int i = 0; i < snakeLength; i++) {</div>
<div> int pixelIndex = getPixelIndex(snake[i][0], snake[i][1]);</div>
<div> strip.setPixelColor(pixelIndex, snakeColor);</div>
<div> }</div>
<div> </div>
<div> int foodIndex = getPixelIndex(food[0], food[1]);</div>
<div> strip.setPixelColor(foodIndex, foodColor);</div>
<div> </div>
<div> strip.show();</div>
<div>}</div>
<br>
<div>// 游戏结束动画</div>
<div>void gameOverAnimation() {</div>
<div> static unsigned long lastBlink = 0;</div>
<div> static bool ledState = false;</div>
<div> </div>
<div> if (millis() - lastBlink > 200) {</div>
<div> ledState = !ledState;</div>
<div> lastBlink = millis();</div>
<div> </div>
<div> for (int i = 0; i < NUM_LEDS; i++) {</div>
<div> strip.setPixelColor(i, ledState ? gameOverColor : bgColor);</div>
<div> }</div>
<div> strip.show();</div>
<div> }</div>
<div>}</div>
<br>
<div>// 重新开始游戏</div>
<div>void restartGame() {</div>
<div> snakeLength = 3;</div>
<div> dir[0] = 1; dir[1] = 0;</div>
<div> nextDir[0] = 1; nextDir[1] = 0;</div>
<div> gameOver = false;</div>
<div> moveDelay = 1000;</div>
<div> </div>
<div> snake[0][0] = 3; snake[0][1] = 4;</div>
<div> snake[1][0] = 2; snake[1][1] = 4;</div>
<div> snake[2][0] = 1; snake[2][1] = 4;</div>
<div> </div>
<div> generateFood();</div>
<div> drawGame();</div>
<div> </div>
<div> delay(500);</div>
<div>}</div>
<br>
<div>// 坐标转索引</div>
<div>int getPixelIndex(int x, int y) {</div>
<div> return y * LED_WIDTH + x;</div>
<div>}</div>
</div>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*6、BOM清单</h3>
<hr>
<p style="line-height:1.8;">由原理图导出</p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*7、大赛LOGO验证</h3>
<hr>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"><img src="https://image.lceda.cn/oshwhub/pullImage/d9a9466041544232978f96a726b17994.jpg" alt="" width="577" height="769"></p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">* 8、演示您的项目并录制成视频上传</h3>
<hr>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"> </p>
</div>
评论(0)