/*
目前有两个游戏(内存不太够),一是控制贪吃蛇吃果子,二是控制果子避免被贪吃蛇吃
未完成的内容还有:
1 游戏二中,dirSnake()函数用于自动确定蛇吃玩家的移动方向(蛇头的方向),不太好用,得重新想想怎么确定蛇移动方向,追逐玩家
2 游戏二中,画蛇的身体的函数drawBitMap(xx, yy,__,7,7,1)用node,还是用tail更好看些,需要决定一下
3 游戏二中,可以的话可以给蛇添一点台词,https://calamitymod.fandom.com/wiki/The_Devourer_of_Gods
4 添加游戏音效
5 添加新的方向控制的方式,方向传感器
6 游戏界面切换动画(可有可无)
P.S.实物的显示屏ssd1306芯片,需要把0x3D改为0x3C,仍然不行的话,需要用02-OLED确认I2C地址,wokwi线上模拟用0x3D
*/
//2022.07.27
//zzy
//***基本库文件
//SSD1306
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//***设定引脚
#define buttonA 10 //设置按键A:确认;
#define buttonB 11 //设置按键B:回退;
#define stick_X A0 //X
#define stick_Y A1 //Y
#define OLED_RESET 4 //重置显示屏//stick_z
//***显示屏参数与实例化
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//***定义枚举变量
typedef enum {
SNAKE = 0,
DEVOURER = 1,
MENU = 2,
} GAME;
GAME yourChoice = MENU;
//*设定游戏状态
typedef enum {
START = 0,
RUNNING = 1,
GAMEOVER = 2,
} State;
State gameState;
//*设定上下左右
typedef enum {
LEFT = 0,
UP = 1,
RIGHT = 2,
DOWN = 3,
NONE = 4,
} Direction;
Direction dir = NONE;
Direction newDir = NONE;
//***界面
//**界面是否完成设定
bool menu_Isset = false;
bool Snake_Isset = false;
bool Devourer_Isset = false;
//**设定循环次数
int Time = 0;
//**菜单界面
//*参数
//因为内存较小,只有两个游戏,贪吃蛇和神明吞噬者追逐玩家
#define MAP_MENU_NUM_X 2
#define MAP_MENU_NUM_Y 1
#define MAP_MENU_SIZE 64
//*位置
struct Position {
int x;
int y;
Direction dir;
};
//框图
Position Menu_MAP_pos[MAP_MENU_NUM_X * MAP_MENU_NUM_Y];
//光标
Position CURSOR_pos;
//*菜单界面函数
void Menu_drawSnake(int xx, int yy);
void Menu_drawDevourer(int xx, int yy);
void Menu_resetYourChioce();
void Menu_moveCursor();
void Menu_drawMap();
void Menu_drawClears();
void Menu_running();
void Menu_setup();
//**贪吃蛇界面
//*参数
#define SNAKE_PIECE_SIZE 3
#define MAX_SNAKE_LENGTH 10
#define MAP_SNAKE_SIZE_X 20
#define MAP_SNAKE_SIZE_Y 20
#define STARTING_SNAKE_SIZE 5
//设置游戏难度
int Snake_level = 1;
int Snake_move_delay[6] = {0, 30, 25, 20, 15, 10};
//设置蛇的参数
Position Snake_pos[MAX_SNAKE_LENGTH];
int Snake_length;
//设置果子的参数
Position FRUIT_pos;
//*贪吃蛇界面函数
bool Snake_moveSnake();
void Snake_resetSnake();
void Snake_checkFruit();
void Snake_generateFruit();
bool Snake_collisionCheck(int x, int y);
void Snake_drawMap();
void Snake_drawScore();
void Snake_drawLevel();
//通用函数
void drawPressToStart();
void drawGameover();
void drawClears() ;
void drawPressToRestart();
void drawBackToMenu();
void Snake_setDirection();
const unsigned char PROGMEM logo[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xf8, 0x00,
0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0xf8, 0x00,
0x00, 0x02, 0x00, 0x00, 0x1f, 0x84, 0x70, 0x00, 0x00, 0x06, 0x00, 0x01, 0xc0, 0xf8, 0x00, 0x00,
0x00, 0x06, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x03, 0x83, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x0e, 0x03, 0x80, 0x00, 0x00, 0x0c, 0x00, 0x03, 0xfc, 0x03, 0x80, 0x00,
0x00, 0x0c, 0x00, 0x05, 0x58, 0x03, 0x80, 0x00, 0x00, 0x0e, 0x00, 0x0a, 0xac, 0x03, 0x80, 0x00,
0x00, 0x06, 0x00, 0x15, 0x54, 0x03, 0x80, 0x00, 0x00, 0x06, 0x00, 0x1a, 0xac, 0x03, 0x80, 0x00,
0x00, 0x07, 0x00, 0x15, 0x54, 0x07, 0x40, 0x00, 0x00, 0x03, 0x00, 0x1a, 0xac, 0x07, 0x40, 0x00,
0x00, 0x03, 0x80, 0x15, 0x54, 0x0e, 0x40, 0x00, 0x00, 0x03, 0x80, 0x1a, 0xac, 0x0e, 0x20, 0x00,
0x00, 0x01, 0xc0, 0x3d, 0x58, 0x1e, 0x20, 0x00, 0x00, 0x01, 0xe0, 0x7f, 0xf0, 0x3c, 0x20, 0x00,
0x00, 0x00, 0xf0, 0xe0, 0x00, 0x38, 0x20, 0x00, 0x00, 0x00, 0xf1, 0xc0, 0x00, 0x78, 0x20, 0x00,
0x00, 0x00, 0xfb, 0x80, 0x00, 0xf0, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x01, 0xe0, 0x60, 0x00,
0x00, 0x00, 0x5e, 0x00, 0x07, 0xc0, 0x60, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x0f, 0x80, 0x40, 0x00,
0x00, 0x0e, 0x67, 0xc0, 0x3e, 0x00, 0xc0, 0x00, 0x00, 0x1f, 0x9b, 0xe0, 0xfc, 0x01, 0x80, 0x00,
0x00, 0x1f, 0x0f, 0xff, 0xf0, 0x01, 0x80, 0x00, 0x00, 0x1f, 0x07, 0xff, 0xc0, 0x07, 0x00, 0x00,
0x00, 0x0e, 0x00, 0xff, 0xc0, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x8c, 0x63, 0x24, 0xc0, 0x00, 0x00, 0x00, 0x02, 0x52, 0x84, 0xbd, 0xe0, 0x00, 0x00, 0x00,
0x02, 0x52, 0xb7, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x02, 0x4c, 0x64, 0xa4, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0x19, 0x0f, 0x79, 0x80, 0x00, 0x00, 0x00, 0x04, 0xa5, 0x04, 0x43, 0xc0,
0x00, 0x00, 0x00, 0x04, 0xa5, 0x24, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x04, 0x99, 0xef, 0x41, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const unsigned char PROGMEM player[] = {
0x01, 0x68, 0x00, 0x0b, 0xfc, 0x00, 0x2f, 0xff, 0x00, 0x3f, 0xff, 0x80, 0x7f, 0xff, 0x80, 0x7f, 0xff, 0x80, 0x7f,
0xff, 0x80, 0x7f, 0xff, 0x80, 0x7f, 0xff, 0x80, 0x5f, 0xff, 0x80, 0x09, 0x9f, 0x00, 0x09, 0x8f, 0x00, 0x09, 0x85,
0x00, 0x18, 0x06, 0x00, 0x10, 0x04, 0x00, 0x18, 0x0e, 0x00, 0x0f, 0xf9, 0x80, 0x1c, 0x88, 0xc0, 0x24, 0x80, 0x40,
0x24, 0x04, 0x40, 0x24, 0x02, 0x40, 0x3c, 0x03, 0xc0, 0x7c, 0x03, 0xc0, 0x44, 0x06, 0x40, 0x44, 0x88, 0x40, 0x4b,
0xf2, 0x40, 0x3b, 0xf1, 0xc0, 0x04, 0x8c, 0x00, 0x04, 0x82, 0x00, 0x04, 0x82, 0x00, 0x04, 0xc2, 0x00, 0x04, 0x41,
0x00, 0x08, 0x41, 0x00, 0x1d, 0xe1, 0x00, 0x1d, 0xfd, 0x00, 0x1f, 0xff, 0x00
};
const unsigned char PROGMEM DoG[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x00, 0x18, 0x38, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0f, 0x86, 0x00, 0xc0, 0x00,
0x03, 0xc0, 0x06, 0x03, 0xdf, 0x82, 0x40, 0x47, 0x00, 0x1f, 0xe8, 0xf0, 0x46, 0x03, 0x00, 0x00,
0x31, 0x19, 0x3c, 0xef, 0x87, 0xc3, 0x01, 0x20, 0x18, 0x41, 0xa4, 0x42, 0x06, 0x09, 0x20, 0x10,
0xb9, 0xf1, 0xe7, 0x8c, 0x3b, 0x20, 0x21, 0x7c, 0x7f, 0xef, 0x79, 0xfb, 0x00, 0x00, 0xce, 0xef,
0xbf, 0xe3, 0x7f, 0x00, 0x00, 0xc7, 0xff, 0x1f, 0xce, 0x3e, 0x00, 0x00, 0x07, 0x9c, 0xe4, 0x99,
0xc9, 0x00, 0x00, 0x07, 0x9c, 0xe4, 0x99, 0xc9, 0x00, 0x00, 0xc7, 0xff, 0x1f, 0xce, 0x3e, 0x00,
0x00, 0xee, 0xef, 0xbf, 0xe3, 0x7f, 0x20, 0x21, 0x7c, 0x7f, 0xef, 0x79, 0xfb, 0x20, 0x10, 0xb9,
0xf3, 0xe7, 0x8c, 0x3b, 0x20, 0x18, 0x41, 0xa4, 0x42, 0x06, 0x09, 0x31, 0x19, 0x3c, 0xef, 0x87,
0xc3, 0x01, 0x1f, 0xe8, 0xf0, 0x46, 0x03, 0x00, 0x00, 0x06, 0x01, 0xbf, 0xc2, 0x40, 0x47, 0x00,
0x0f, 0xc3, 0x00, 0x60, 0x00, 0x03, 0xc0, 0x38, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};
const unsigned char PROGMEM node[4][7] =
{
{ 0x10, 0x38, 0x10, 0x28, 0x10, 0x38, 0x10 },
{ 0x00, 0x00, 0x54, 0xee, 0x54, 0x00, 0x00 },
{ 0x10, 0x38, 0x10, 0x28, 0x10, 0x38, 0x10 },
{ 0x00, 0x00, 0x54, 0xee, 0x54, 0x00, 0x00 },
};
const unsigned char PROGMEM head[4][7] =
{
{ 0xe0, 0x30, 0x10, 0x68, 0x10, 0x30, 0xe0},
{ 0x82, 0x92, 0xd6, 0x6c, 0x10, 0x00, 0x00},
{ 0x0e, 0x18, 0x10, 0x2c, 0x10, 0x18, 0x0e },
{ 0x00, 0x00, 0x10, 0x6c, 0xd6, 0x92, 0x82 },
};
const unsigned char PROGMEM tail[4][7] =
{
{ 0x00, 0x04, 0x18, 0x2e, 0x18, 0x04, 0x00 },
{ 0x00, 0x00, 0x10, 0x28, 0x38, 0x54, 0x10 },
{ 0x00, 0x40, 0x30, 0xe8, 0x30, 0x40, 0x00 },
{ 0x10, 0x54, 0x38, 0x28, 0x10, 0x00, 0x00 },
};
const unsigned char PROGMEM door[] =
{
0xaa, 0x7c, 0xc6, 0x44, 0xc6, 0x7c, 0xaa
};
//***玩家游戏成就
int isMasters[MAP_MENU_NUM_X * MAP_MENU_NUM_Y] {0};
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.drawBitmap(32, 0, logo, 64, 64, 1);
display.display();
delay(1000);
display.clearDisplay();
display.clearDisplay();
pinMode(buttonA, INPUT_PULLUP);
pinMode(buttonB, INPUT_PULLUP);
pinMode(stick_X, INPUT);
pinMode(stick_Y, INPUT);
pinMode(OLED_RESET, INPUT_PULLUP);
}
void loop() {
// put your main code here, to run repeatedly:
switch (yourChoice) { //yourChoice初始设为MENU
case MENU:
if (!menu_Isset) {
Menu_setup();
menu_Isset = true;
}
while (1) {
//如果按下摇杆
//且读取摇杆状态的次数远大于屏幕更新的次数
if (readDirection() && Time > 50) {
Menu_running();
delay(50);
Time = 0;
}
//如果按下B键,退出游戏,关机(未完成)
if (buttonPressB()) {
menu_Isset = false;
delay(50);
Time = 0;
}
//如果按下A键,跳出循环,loop()
if (buttonPressA()) {
Menu_resetYourChoice();
menu_Isset = false;
Time = 0;
delay(50);
break;
}
//循环次数++
Time++;
}
break;
case SNAKE: //Game1
if (!Snake_Isset) {
Snake_setupGame();
Snake_Isset = true;
}
switch (gameState) {
//游戏状态设置为等待
case START:
if (buttonPressA()) {
gameState = RUNNING;
Time = 0;
}
break;
//游戏状态设置为运动
case RUNNING:
readDirection();
if (Time > Snake_move_delay[Snake_level] * 50)
Snake_running();
break;
//游戏状态设置为结束
case GAMEOVER:
Snake_Isset = false; //需要重新设置贪吃蛇的界面
menu_Isset = false; //需要重新设置菜单的界面
//按下A键,重玩游戏
for (;;) {
if (buttonPressA()) {
delay(50);
yourChoice = SNAKE;
Time = 0;
break;
}
//按下B键,返回菜单
if (buttonPressB()) {
delay(50);
yourChoice = MENU;
Time = 0;
break;
}
}
break;
}
Time++;
break;
}
}
//***通用函数
//确认建
bool buttonPressA() {
if (digitalRead(buttonA) == LOW)
return true;
return false;
}
//返回键
bool buttonPressB() {
if (digitalRead(buttonB) == LOW)
return true;
return false;
}
//控制杆
bool readDirection() {
int x = analogRead(stick_X);
int y = analogRead(stick_Y);
if (x > 300 && x < 700 && y > 300 && y < 700)
return false;
else {
if (x > 300 && x < 700 && y > 700)newDir = UP;
if (x > 300 && x < 700 && y < 300)newDir = DOWN;
if (x < 300 && y > 300 && y < 700)newDir = RIGHT;
if (x > 700 && y > 300 && y < 700)newDir = LEFT;
}
return true;
}
//画开始提示
void drawPressToStart() {
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(2, 20);
display.print(F("Press A\nto\nstart!"));
}
//画结束提示
void drawGameover() {
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(2, 50);
display.println(F("GAME OVER"));
}
//画通关提示
void drawClears() {
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(2, 50);
display.println(F("GAME CLEAR"));
}
//画重置提示
void drawPressToRestart() {
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(2, 2);
display.print(F("Press A\nto\nrestart!"));
}
//画返回菜单界面
void drawBackToMenu() {
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(2, 40);
display.print(F("Press B\nto\nmenu!"));
}
//***MENU
void Menu_running() {
//清空图像缓存
display.clearDisplay();
//更新方向
dir = newDir;
//按照新的方向移动光标
Menu_moveCursor();
//绘制选项
Menu_drawDevourer(CURSOR_pos.x, CURSOR_pos.y);
Menu_drawSnake(CURSOR_pos.x, CURSOR_pos.y);
Menu_drawClears(); //绘制游戏成就
display.display(); //重新绘图
}
void Menu_setup() {
display.clearDisplay();
//光标初始位置
CURSOR_pos.x = 0;
CURSOR_pos.y = 0;
//贪吃蛇的位置 玩家控制逃命
Menu_MAP_pos[SNAKE].x = 0;
Menu_MAP_pos[SNAKE].y = 0;
//神吞的位置 玩家控制贪吃蛇
Menu_MAP_pos[DEVOURER].x = 1;
Menu_MAP_pos[DEVOURER].y = 0;
//初始方向
dir = NONE;
newDir = NONE;
//绘制选项
Menu_drawDevourer(CURSOR_pos.x, CURSOR_pos.y);
Menu_drawSnake(CURSOR_pos.x, CURSOR_pos.y);
//绘制游戏成就(暂不)
//Menu_drawClears();
display.display();
delay(50);
}
//绘制选项框与框中图像_贪吃蛇
void Menu_drawSnake(int xx, int yy) {
//被光标指中
bool isCursor = xx == Menu_MAP_pos[SNAKE].x && yy == Menu_MAP_pos[SNAKE].y;
//被光标选中时会变阴阳色
int objt_color = isCursor ? 1 : 0;
//设置背景颜色
display.drawRect(0, 0, 64, 64 - 10, objt_color);
//画玩家
display.drawBitmap(22, 9, player, 20, 36, 1);
//写说明
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(0 + 2, 64 - 10 + 2);
display.println(F("Andrew"));
}
//绘制选项框与框中图像_神明吞噬者
void Menu_drawDevourer(int xx, int yy) {
//被光标指中
bool isCursor = (xx == Menu_MAP_pos[DEVOURER].x && yy == Menu_MAP_pos[DEVOURER].y);
//被光标选中时会变阴阳色
int objt_color = isCursor ? 1 : 0;
display.drawRect(64, 0, 64, 64 - 10, objt_color);
display.drawBitmap(64 + 4, 4, DoG, 56, 46, 1);
//写说明
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(64 + 2, 64 - 10 + 2);
display.println(F("Devourer"));
}
//重置游戏选择
void Menu_resetYourChoice()
{
if (CURSOR_pos.x == Menu_MAP_pos[SNAKE].x && CURSOR_pos.y == Menu_MAP_pos[SNAKE].y)
//扮演蛇
yourChoice = DEVOURER;
if (CURSOR_pos.x == Menu_MAP_pos[DEVOURER].x && CURSOR_pos.y == Menu_MAP_pos[DEVOURER].y)
//扮演向导
yourChoice = SNAKE;
}
//移动光标
void Menu_moveCursor() {
int x = CURSOR_pos.x;
int y = CURSOR_pos.y;
switch (dir) {//changing
case LEFT:
x = (x + MAP_MENU_NUM_X - 1) % MAP_MENU_NUM_X;
break;
case UP:
y = (y + MAP_MENU_NUM_Y - 1) % MAP_MENU_NUM_Y;
break;
case RIGHT:
x = (x + MAP_MENU_NUM_X + 1) % MAP_MENU_NUM_X;
break;
case DOWN:
y = (y + MAP_MENU_NUM_Y + 1) % MAP_MENU_NUM_Y;
break;
default: break;
}
CURSOR_pos.x = x;
CURSOR_pos.y = y;
}
//通关证明
void Menu_drawClears() {
for (int i = 0; i < MAP_MENU_NUM_X * MAP_MENU_NUM_Y; i++)
if (isMasters[i]) {
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(Menu_MAP_pos[i].x, Menu_MAP_pos[i].y);
display.print(F("Clears!"));
}
}
//***SNAKE
void Snake_running() {
Snake_setDirection();
display.clearDisplay();
if (Snake_moveSnake()) { //游戏结束
gameState = GAMEOVER;
Snake_drawMap();
Snake_drawScore();
Snake_drawLevel();
drawGameover();
display.display();
delay(1000);
display.clearDisplay();
display.display();
Snake_drawMap();
drawPressToRestart();
drawBackToMenu();
display.display();
delay(1000);
return;
}
if (Snake_level == 5) {
gameState = GAMEOVER;
Snake_drawMap();
//Snake_drawScore();
//Snake_drawLevel();
drawClears();//通关五个模式的贪吃蛇大师;
isMasters[SNAKE] = 1;//通关证明
display.display();
delay(1000);
display.clearDisplay();
Snake_drawMap();
drawPressToRestart();
drawBackToMenu();
display.display();
delay(1000);
return;
}
Snake_drawMap();
Snake_drawScore();
Snake_drawLevel();
display.display();
Snake_checkFruit();
Time = 0;
delay(10);
}
void Snake_setupGame() {
//设定初始难度等级为1;
Snake_level = 1;
gameState = START;
//设定初始方向
dir = RIGHT;
newDir = RIGHT;
Snake_resetSnake();
Snake_generateFruit();
display.clearDisplay();
Snake_drawMap();
Snake_drawLevel();
drawPressToStart();
display.display();
delay(50);
}
//重置蛇的运动方向
void Snake_setDirection() {
//蛇不能直接折返
if (newDir != (dir + 2) % 4)
dir = newDir;
return;
}
//初始化蛇
void Snake_resetSnake() {
Snake_length = STARTING_SNAKE_SIZE;
for (int i = 0; i < Snake_length; i++) {
Snake_pos[i].x = MAP_SNAKE_SIZE_X / 2 - i;
Snake_pos[i].y = MAP_SNAKE_SIZE_Y / 2;
}
}
//使蛇运动
bool Snake_moveSnake() {
int8_t x = Snake_pos[0].x;
int8_t y = Snake_pos[0].y;
switch (dir) {
case LEFT:
x -= 1;
break;
case UP:
y -= 1;
break;
case RIGHT:
x += 1;
break;
case DOWN:
y += 1;
break;
}
if (Snake_collisionCheck(x, y))
return true;
for (int i = Snake_length - 1; i > 0; i--) {
Snake_pos[i].x = Snake_pos[i - 1].x;
Snake_pos[i].x = Snake_pos[i - 1].y;
Snake_pos[i].dir = Snake_pos[i - 1].dir;
}
Snake_pos[0].x = x;
Snake_pos[0].y = y;
return false;
}
//蛇吃果子
void Snake_checkFruit() {
if (FRUIT_pos.x == Snake_pos[0].x && FRUIT_pos.y == Snake_pos[0].y)
{
if (Snake_length + 1 <= MAX_SNAKE_LENGTH) {
Snake_length++;
Snake_generateFruit();
}
else {
Snake_level++;
Snake_length = STARTING_SNAKE_SIZE;
}
}
}
//生成果子
void Snake_generateFruit() {
bool isOnSnake = false;
do {
isOnSnake = false;
FRUIT_pos.x = random(0, MAP_SNAKE_SIZE_X);
FRUIT_pos.y = random(0, MAP_SNAKE_SIZE_Y);
for (int i = 0; i < Snake_length; i++) { //检查果子是否在蛇的身上
if (FRUIT_pos.x == Snake_pos[i].x && FRUIT_pos.y == Snake_pos[i].y) {
isOnSnake = true;//如果在蛇身上重新产生果子;
continue;
}
}
} while (isOnSnake);
}
//检查蛇是否撞墙
//检查蛇是否自杀
bool Snake_collisionCheck(int8_t x, int8_t y) {
for (int i = 1; i < Snake_length; i++) {
if (x == Snake_pos[i].x && y == Snake_pos[i].y) return true;
}
if (x < 0 || y < 0 || x >= MAP_SNAKE_SIZE_X || y >= MAP_SNAKE_SIZE_Y) return true;
return false;
}
//画图
void Snake_drawMap() {
int MapX0 = 66;
int MapY0 = 2;
//画果子
display.drawRect(FRUIT_pos.x * SNAKE_PIECE_SIZE + MapX0,
FRUIT_pos.y * SNAKE_PIECE_SIZE + MapY0,
SNAKE_PIECE_SIZE,
SNAKE_PIECE_SIZE,
1);
//画框图
display.drawRect(64, 0,
SNAKE_PIECE_SIZE * MAP_SNAKE_SIZE_X + 4,
SNAKE_PIECE_SIZE * MAP_SNAKE_SIZE_Y + 4,
1);
//画蛇
int ss = SNAKE_PIECE_SIZE;
display.drawBitmap(Snake_pos[0].x * ss - 2 - ss / 2, Snake_pos[0].y * ss - 2 - ss / 2 + MapY0, head[Snake_pos[0].dir], ss + 4, ss + 4, 1);
for (int i = 1; i < Snake_length - 1; i++) {
display.drawBitmap(Snake_pos[i].x * SNAKE_PIECE_SIZE + MapX0 - 2 - SNAKE_PIECE_SIZE / 2, Snake_pos[i].y * ss - 2 - ss / 2 + MapY0, tail[Snake_pos[i].dir], ss + 4, ss + 4, 1);
}
display.drawBitmap(Snake_pos[Snake_length - 1].x * ss + MapX0 - 2 - ss / 2, Snake_pos[Snake_length - 1].y * ss - 2 - ss / 2 + MapY0, tail[Snake_pos[Snake_length - 1].dir], ss + 4, ss + 4, 1);
}
//画分数
void Snake_drawScore() {
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(2, 20);
display.print(F("Score:"));
display.println(Snake_length - STARTING_SNAKE_SIZE);
}
//画等级
void Snake_drawLevel() {
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(2, 2);
display.print(F("Level:"));
display.println(Snake_level);
}