全部代码放在全文最后可直接复制
硬件介绍
- arduino mega2560 不多介绍了
- 3.5寸的tft屏(适配arduino)
- 自己焊的四个按钮的洞洞板(很丑勿喷)
游戏说明
本游戏写了两种模式
生存模式 :再触到屏幕边缘时和蛇自身时死亡
无敌模式 :不会死亡,同时按住四个键可以退出
- 开始键为左键
- 上下键可以选择模式
- 上下左右键我自己焊接了四个按键分别对应
成品效果
arduino tft库
和电脑直接用easyx写贪吃蛇不同arduino的库要找,并且我找了个于类似于easyx的库因为我以前用这个写过贪吃蛇。
还有其他很多库可以选 库的下载包我会放在 我的资源 里 直接下载就行
代码讲解
蛇和食物
用两个结构体
#define SNAKE_NUM 500//定义蛇的最大长度为500
struct Snake//定义🐍蛇的结构体
{
int s_size; //蛇的节数
int s_move = 100;//此数值用于定时器的定时
int dir; //蛇的方向,在枚举中列举了
int s_speed; //移动速度
int thickness;//蛇的粗细,即半径
int s_coor[SNAKE_NUM][2];
int grade; //得分
bool islive;//是否活着,,布尔值判断
}snake;
struct Food
{
int x; //食物的横坐标
int y; //食物的纵坐标
int r; //食物大小,(即圆的半径)
bool flag; //食物是否被吃、、布尔值判断
}food;
显示蛇和食物
myGLCD.fillCircle 用于绘制一个圆
myGLCD.setColor 设置颜色
void GameDraw() {//画蛇,食物
// myGLCD.clrScr();
//绘制蛇
myGLCD.setColor(0,255,0); //蓝色
myGLCD.fillCircle(snake.s_coor[0][0],snake.s_coor[0][1], 5);//绘制一个半径为5的圆
myGLCD.setColor(0,255,0);
for (int i = 1; i < snake.s_size; i++)//蛇的每一节都画一个圆
{//
myGLCD.fillCircle(snake.s_coor[i][0], snake.s_coor[i][1], snake.thickness);//画圆,半径为5
}
//绘制食物
if (food.flag)///如果food.flag=true=1时执行下面括号内语句
{
myGLCD.setColor(random(1000) % 256, random(1000) % 256,random(1000) % 256);
myGLCD.fillCircle(food.x, food.y, food.r);//(food.x, food.y, food.r)
}
myGLCD.setColor(255,255,0);
myGLCD.setTextSize(2);
myGLCD.print("grade", 0, 0);
myGLCD.printNumI(snake.grade,80 ,0);//显示得分
}
上下左右实现
对按键进行判断
digitalRead();
在使用输入或输出功能前,你需要先通过pinMode() 函数配置引脚的模式为输入模式或输出模式。
参数: 参数pin为指定读取状态的引脚编号。
返回值: 返回值为获取到的信号状态,1为高电平,0为低电平。
void keyControl()//
{
//判断有无按键
int num=0;
if(digitalRead(47)==0&&digitalRead(49)==1&&digitalRead(51)==1&&digitalRead(53)==1){
num=1;
}
if(digitalRead(47)&&!digitalRead(49)&&digitalRead(51)&&digitalRead(53)){
num=2;
}
if(digitalRead(47)&&digitalRead(49)&&!digitalRead(51)&&digitalRead(53)){
num=3;
}
if(digitalRead(47)&&digitalRead(49)&&digitalRead(51)&&!digitalRead(53)){
num=4;
}
switch (num)//
{
case 1://
if (snake.dir != sDOWN)//
snake.dir = sUP;//
break;//
case 2://
if (snake.dir != sUP)//
snake.dir = sDOWN;//
break;//
case 3://
if (snake.dir != sRIGHT)//
snake.dir = sLEFT;//
break;//
case 4://
if (snake.dir != sLEFT)//
snake.dir = sRIGHT;//
break;///
}
}
移动蛇
蛇头所在点的位置向上或向下或向左右移动10个像素的位置。
蛇身体的每一节移到前一节的位置
最后一节颜色变成背景颜色
- 在无敌模式 时当蛇头移到上边界时显示到下边界
- 在生存模式 里当蛇头移到边界时蛇死亡
void snakeMove_wd()//在无敌模式中蛇的移动
{
int a[1][2];
a[0][0] = snake.s_coor[0][0];
a[0][1] = snake.s_coor[0][1];
switch (snake.dir)//
{
case sUP:
snake.s_coor[0][1] -= 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][1] <= 0)//超出了上边界
{
snake.s_coor[0][1] = HEIGHT;//
}
break;//
case sDOWN://
snake.s_coor[0][1] += 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][1] >= HEIGHT)//超出了下边界
{
snake.s_coor[0][1] = 0;//
}
break;//
case sLEFT://
snake.s_coor[0][0] -= 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][0] <= 0)//超出了左边界
{
snake.s_coor[0][0] = WIDTH;
}
break;//
case sRIGHT://
snake.s_coor[0][0] += 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][0] >= WIDTH)//超出了右边界
{
snake.s_coor[0][0] = 0;
}
break;
}
myGLCD.setColor(15, 206, 235);
myGLCD.fillCircle(snake.s_coor[snake.s_size-1][0], snake.s_coor[snake.s_size-1][1], snake.thickness);//画圆,半径为5
if (snake.islive)//
{
for (int i = snake.s_size - 1; i > 1; i--)
{//让蛇身跟着蛇头移动
snake.s_coor[i][0] = snake.s_coor[i - 1][0];
snake.s_coor[i][1] = snake.s_coor[i - 1][1];
}
snake.s_coor[1][1] = a[0][1];
snake.s_coor[1][0] = a[0][0];
}
}
最终代码
#include <Adafruit_GFX.h>
#include <UTFTGLUE.h> // class methods are in here
UTFTGLUE myGLCD(0x9486,A3,A2,A1,A0,A4);
// Declare which fonts we will be using
#if !defined(SmallFont)
extern uint8_t SmallFont[]; //.kbv GLUE defines as GFXFont ref
#endif
#define HEIGHT 320
#define WIDTH 480
#define SNAKE_NUM 500//定义蛇的最大长度为500
#define INTERVAL 60//定义一个间隔的长度为60在图形化界面里
enum DIR { sUP, sDOWN, sLEFT, sRIGHT, sUPRIGHT };//用枚举列举出蛇的方向
struct Snake//定义🐍蛇的结构体
{
int s_size; //蛇的节数
int s_move = 100;//此数值用于定时器的定时
int dir; //蛇的方向,在枚举中列举了
int s_speed; //移动速度
int thickness;//蛇的粗细,即半径
int s_coor[SNAKE_NUM][2];
int grade; //得分
bool islive;//是否活着,,布尔值判断
}snake;
struct Food
{
int x; //食物的横坐标
int y; //食物的纵坐标
int r; //食物大小,(即圆的半径)
bool flag; //食物是否被吃、、布尔值判断
}food;
int grade[100];//游戏中存档可存档100个数据
int cnt = 0;//未存档时值为0;
char str[1000];
void GameInt();
void GameDraw();
bool IsInSnake(int x, int y);
void keyControl();
void snakeMove_wd();
void snakeMove_sc();
void EatFood();
void MenuInterface();
void Menu();
//*********************************************************************************************
void GameInt()//游戏的初始化,
{
//初始化蛇 一开始有三节
snake.s_size = 4;//定义蛇的节数开始为3节
snake.s_speed = 1;//速度为1
snake.dir = rand() % 4;//rand()重新生成随机数,取余后为随机小于4的数,用来随即蛇的初始方向
snake.grade = 0;//定义蛇的初始分数为0
snake.thickness = 5;//蛇的半径为5,即蛇的粗细为10;
snake.islive = true;//布尔值定义为1(true=1);即蛇存在
//随机初始化蛇头
snake.s_coor[0][0] = random(2000) % (WIDTH - 2 * snake.thickness) + snake.thickness;
snake.s_coor[0][1] = random(2000) % (HEIGHT - 2 * snake.thickness) + snake.thickness;
//初始化食物
do {//
food.x = random(2000) % (WIDTH - 2*food.r) + food.r;
food.y = random(2000) % (HEIGHT - 2*food.r) + food.r;
} while (IsInSnake(food.x, food.y));//
//rand()重新生成随机数,取余后为随机小于256的数,颜色RGB(x,y,z)函数,x<=255,y<255,z<255,每一个数对应一个颜色
food.r = 5;//定义食物的大小
food.flag = true;//布尔值定义为1(true=1);即食物存在
}
//***********************************************************************************************
void GameDraw() {//画蛇,食物
// myGLCD.clrScr();
//绘制蛇
myGLCD.setColor(0,255,0);
myGLCD.fillCircle(snake.s_coor[0][0],snake.s_coor[0][1], 5);//绘制一个半径为5的圆
myGLCD.setColor(0,255,0);
for (int i = 1; i < snake.s_size; i++)//蛇的每一节都画一个圆
{//
myGLCD.fillCircle(snake.s_coor[i][0], snake.s_coor[i][1], snake.thickness);//画圆,半径为5
}
//绘制食物
if (food.flag)///如果food.flag=true=1时执行下面括号内语句
{
myGLCD.setColor(random(1000) % 256, random(1000) % 256,random(1000) % 256);
myGLCD.fillCircle(food.x, food.y, food.r);//(food.x, food.y, food.r)
}
myGLCD.setColor(255,255,0);
myGLCD.setTextSize(2);
myGLCD.print("grade", 0, 0);
myGLCD.printNumI(snake.grade,80 ,0);
}
//***********************************************************************************************
bool IsInSnake(int x, int y)//
{
for (int i = 0; i < snake.s_size; i++)//
{
if (x >= snake.s_coor[i][0] - snake.thickness && x <= snake.s_coor[i][0] + snake.thickness &&//蛇头的坐标在蛇的身体
y >= snake.s_coor[i][1] - snake.thickness && y <= snake.s_coor[i][1] + snake.thickness)//蛇头能否到蛇身体上任意一节圆的上下左右,
return true;//返回true
}
return false;//如果不满足返回false
}
//***********************************************************************************************
void snakeMove_wd()//在无敌模式中蛇的移动
{
int a[1][2];
a[0][0] = snake.s_coor[0][0];
a[0][1] = snake.s_coor[0][1];
switch (snake.dir)//
{
case sUP:
snake.s_coor[0][1] -= 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][1] <= 0)//超出了上边界
{
snake.s_coor[0][1] = HEIGHT;//
}
break;//
case sDOWN://
snake.s_coor[0][1] += 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][1] >= HEIGHT)//超出了下边界
{
snake.s_coor[0][1] = 0;//
}
break;//
case sLEFT://
snake.s_coor[0][0] -= 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][0] <= 0)//超出了左边界
{
snake.s_coor[0][0] = WIDTH;//
}
break;//
case sRIGHT://
snake.s_coor[0][0] += 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][0] >= WIDTH)//超出了右边界
{
snake.s_coor[0][0] = 0;//
}
break;//
}
myGLCD.setColor(15, 206, 235);
myGLCD.fillCircle(snake.s_coor[snake.s_size-1][0], snake.s_coor[snake.s_size-1][1], snake.thickness);//画圆,半径为5
if (snake.islive)//
{
for (int i = snake.s_size - 1; i > 1; i--)//
{//让蛇身跟着蛇头移动
snake.s_coor[i][0] = snake.s_coor[i - 1][0];//
snake.s_coor[i][1] = snake.s_coor[i - 1][1];
}
snake.s_coor[1][1] = a[0][1];//
snake.s_coor[1][0] = a[0][0];//
}
}
//***********************************************************************************************
void snakeMove_sc()//在无敌模式中蛇的移动
{
int a[1][2];
a[0][0] = snake.s_coor[0][0];
a[0][1] = snake.s_coor[0][1];
switch (snake.dir)//
{
case sUP:
if (IsInSnake(snake.s_coor[0][0], snake.s_coor[0][1] - 2 * snake.s_speed * snake.thickness)) {//
snake.islive = false;//
break;//
}
snake.s_coor[0][1] -= 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][1] <= 0)//超出了上边界
{
snake.islive = false;//蛇死亡
}
break;//
case sDOWN://
if (IsInSnake(snake.s_coor[0][0], snake.s_coor[0][1] + 2 * snake.s_speed * snake.thickness))//
{
snake.islive = false;//
break;//
}
snake.s_coor[0][1] += 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][1] >= HEIGHT)//超出了下边界
{
snake.islive = false;//
}
break;//
case sLEFT://
if (IsInSnake(snake.s_coor[0][0] - 2 * snake.s_speed * snake.thickness, snake.s_coor[0][1]))//
{
snake.islive = false;//
break;//
}
snake.s_coor[0][0] -= 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][0] <= 0)//超出了左边界
{
snake.islive = false;//
}
break;//
case sRIGHT://
if (IsInSnake(snake.s_coor[0][0] +2 * snake.s_speed * snake.thickness, snake.s_coor[0][1]))//
{
snake.islive = false;//
break;//
}
snake.s_coor[0][0] += 2 * snake.s_speed * snake.thickness;//
if (snake.s_coor[0][0] >= WIDTH)//超出了右边界
{
snake.islive = false;//
}
break;//
}
myGLCD.setColor(15, 206, 235);
myGLCD.fillCircle(snake.s_coor[snake.s_size-1][0], snake.s_coor[snake.s_size-1][1], snake.thickness);//画圆,半径为5
if (snake.islive)//
{
for (int i = snake.s_size - 1; i > 1; i--)//
{//让蛇身跟着蛇头移动
snake.s_coor[i][0] = snake.s_coor[i - 1][0];//
snake.s_coor[i][1] = snake.s_coor[i - 1][1];
}
snake.s_coor[1][1] = a[0][1];//
snake.s_coor[1][0] = a[0][0];//
}
}
//***********************************************************************************************
//通过按键改变蛇的方向
void keyControl()//
{
//判断有无按键
int num=0;
if(digitalRead(47)==0&&digitalRead(49)==1&&digitalRead(51)==1&&digitalRead(53)==1){
num=1;
}
if(digitalRead(47)&&!digitalRead(49)&&digitalRead(51)&&digitalRead(53)){
num=2;
}
if(digitalRead(47)&&digitalRead(49)&&!digitalRead(51)&&digitalRead(53)){
num=3;
}
if(digitalRead(47)&&digitalRead(49)&&digitalRead(51)&&!digitalRead(53)){
num=4;
}
switch (num)//
{
case 1://
if (snake.dir != sDOWN)//
snake.dir = sUP;//
break;//
case 2://
if (snake.dir != sUP)//
snake.dir = sDOWN;//
break;//
case 3://
if (snake.dir != sRIGHT)//
snake.dir = sLEFT;//
break;//
case 4://
if (snake.dir != sLEFT)//
snake.dir = sRIGHT;//
break;///
}
}
//***********************************************************************************************
void EatFood()//判断蛇吃食物
{
if (food.flag && snake.s_coor[0][0] + snake.thickness >= food.x - food.r && snake.s_coor[0][0] - snake.thickness <= food.x + food.r &&
snake.s_coor[0][1] + snake.thickness >= food.y - food.r && snake.s_coor[0][1] - snake.thickness <= food.y + food.r)//
{
food.flag = false;//
myGLCD.setColor(15, 206, 235);
myGLCD.fillCircle(food.x, food.y, food.r);//(food.x, food.y, food.r)
snake.s_size++;//
snake.grade += 1;//
}
if (!food.flag)//
{//刷新食物
do {//
food.x = random(2000) % (WIDTH - 2 * food.r) + food.r;//
food.y = random(2000) % (HEIGHT - 2 * food.r) + food.r;//
} while (IsInSnake(food.x, food.y));//
myGLCD.setColor(rand() % 255, rand() % 255, rand() % 255);//
food.r = 5;//
food.flag = true;//
}
}
//***********************************************************************************************
void MenuInterface(){
myGLCD.setColor(255, 52, 2);
myGLCD.setTextSize(6);
myGLCD.print("snake", 150, 20);
myGLCD.setTextSize(4);
myGLCD.print("mode live", 100, 120);
myGLCD.print("mode unlive", 100, 180);
}
//***********************************************************************************************
void Menu()//
{//用户界面菜单
myGLCD.setColor(15, 206, 235);
myGLCD.fillRect(0, 0, 480, 320);
int num=0;
int ans=1;
while (1)
{
MenuInterface();//
myGLCD.setColor(0, 0, 0);
if(digitalRead(47)==0&&digitalRead(49)==1&&digitalRead(51)==1&&digitalRead(53)==1){
if(ans==2){
ans--;
}
}
if(digitalRead(47)&&!digitalRead(49)&&digitalRead(51)&&digitalRead(53)){
if(ans==1){
ans++;
}
}
if(ans==1)
myGLCD.drawRoundRect(100, 120,315,150);
if(ans==2)
myGLCD.drawRoundRect(100, 180,360,210);
if(digitalRead(47)&&digitalRead(49)&&!digitalRead(51)&&digitalRead(53)){
if(ans==1)
num=1;
if(ans==2)
num=2;
}
switch (num)//
{
case 1://新游戏
myGLCD.setColor(15, 206, 235);
myGLCD.fillRect(0, 0, 480, 320);
GameInt();//
while(1){
if (snake.islive)//
{
GameDraw();//
snakeMove_sc();//
keyControl();//多次检测键盘输入,提高灵敏度
keyControl();//
keyControl();//
keyControl();//
EatFood();//
delay(snake.s_move);//延迟20毫秒
}
else//
{
myGLCD.setColor(255, 52, 2);
myGLCD.setTextSize(6);
myGLCD.print("gameover", 100, 20);
myGLCD.setTextSize(2);
myGLCD.print("grade", 100, 80);
myGLCD.printNumI(snake.grade,180 ,80);
delay(2000);
myGLCD.setColor(15, 206, 235);
myGLCD.setTextSize(6);
myGLCD.print("gameover", 100, 20);
myGLCD.setTextSize(2);
myGLCD.print("grade", 100, 80);
myGLCD.printNumI(snake.grade,180 ,80);
// myGLCD.clrScr();
// myGLCD.setColor(15, 206, 235);
// myGLCD.fillRect(0, 0, 480, 320);
num=0;
break;//
}
}
break;//
case 2://新游戏
myGLCD.setColor(15, 206, 235);
myGLCD.fillRect(0, 0, 480, 320);
GameInt();//
while(1){
GameDraw();//
snakeMove_wd();//
keyControl();//多次检测键盘输入,提高灵敏度
keyControl();//
keyControl();//
keyControl();//
EatFood();//
delay(snake.s_move);//延迟20毫秒
if(!digitalRead(47)&&!digitalRead(49)&&!digitalRead(51)&&!digitalRead(53)){
myGLCD.setColor(255, 52, 2);
myGLCD.setTextSize(6);
myGLCD.print("gameover", 100, 20);
myGLCD.setTextSize(2);
myGLCD.print("grade", 100, 80);
myGLCD.printNumI(snake.grade,180 ,80);
delay(2000);
// myGLCD.setColor(15, 206, 235);
// myGLCD.setTextSize(6);
// myGLCD.print("gameover", 100, 20);
// myGLCD.setTextSize(2);
// myGLCD.print("grade", 100, 80);
// myGLCD.printNumI(snake.grade,180 ,80);
myGLCD.clrScr();
myGLCD.setColor(15, 206, 235);
myGLCD.fillRect(0, 0, 480, 320);
num=0;
break;//
}
}
break;//
}
}
}
//***********************************************************************************************
void setup()
{
Serial.begin(9600);
pinMode(47,INPUT_PULLUP);
pinMode(49,INPUT_PULLUP);
pinMode(51,INPUT_PULLUP);
pinMode(53,INPUT_PULLUP);
Serial.println("start");
randomSeed(analogRead(5)); //.kbv Due does not like A0
pinMode(A0, OUTPUT); //.kbv mcufriend have RD on A0
digitalWrite(A0, HIGH);
// Setup the LCD
myGLCD.InitLCD();
myGLCD.setFont(SmallFont);
}
//***********************************************************************************************
void loop()
{
myGLCD.setBackColor(15, 206, 235);
Menu();
}
制作不易给个赞吧