这学期学了图形交互学,三个星期下来,突然意识到已经可以用c++写一个贪吃蛇了。
于是就用了两天写了这个小游戏。
其中一天写了核心代码,半天找核心代码中的bug,还有半天进行了界面及操作的优化。
但是有些代码写的依旧有些累赘,比如难度选择界面,不停用if语句,代码太杂了,但是也懒得去优化了,毕竟还有很多事情要做。
下面是游戏运行程序,建议在win10下运行,因为找了几个win7win8系统的童鞋貌似都不能运行,给了他们运行库,运行库也安装不上去。
下面是游戏界面截图。
好了接下来就贴出这些代码。仅供参考。
#include "stdafx.h"
#include <time.h>
#include <conio.h>
#include <graphics.h>
#include <iostream>
using namespace std; //bug:运行游戏开始后不能按除方向键和wasd键外的其它键,不然会提示撞墙 /*画窗体边框*/
void drawBorder(bool i, int borderWidth)
{
if (i)
{
setfillcolor(GREEN);
}
else
{
setfillcolor(RED);
}
bar(, , getmaxx(), borderWidth - - );//上边框
bar(, , borderWidth - - , getmaxy());//左边框
bar(getmaxx() - borderWidth + , , getmaxx(), getmaxy());//右边框
bar(, getmaxy() - borderWidth + , getmaxx(), getmaxy());//下边框
} /*贪吃蛇结构体*/
struct Snake
{
int snakeX;
int snakeY;
};
void drawSnake(struct Snake snakeHeadTemp, int snakeR)
{
setfillcolor(WHITE);
solidcircle(snakeHeadTemp.snakeX, snakeHeadTemp.snakeY, snakeR);
}
//擦除蛇尾
bool eraseSnake(struct Snake snakeHeadTemp, struct Snake snakeTail, int snakeR, struct Snake snakeFood)
{
if ((snakeHeadTemp.snakeX == snakeFood.snakeX) && (snakeHeadTemp.snakeY == snakeFood.snakeY))
{
return true;//如果相同,则返回true,说明需要重新绘制一个食物并且不擦除当前蛇尾
}
else
{
setfillcolor(BLACK);
solidcircle(snakeTail.snakeX, snakeTail.snakeY, snakeR);
return false;
}
}
//检测是否和自身相撞
bool checkSnake(struct Snake *snake, struct Snake snakeHeadTemp, int * snakeLenPtr)
{
for (int i = ; i < *snakeLenPtr; i++)
{
if (((snake + i)->snakeX == snakeHeadTemp.snakeX) && ((snake + i)->snakeY == snakeHeadTemp.snakeY))
{
return false;
}
}
return true;
}
//对数组排序
void sortSnake(struct Snake *snake, struct Snake snakeHeadTemp, int * snakeLenPtr)
{
for (int i = *snakeLenPtr - ; i >= ; i--)//妈蛋,i>=0i>=0i>=0罚抄一百遍!这个bug找了整整半天啊卧槽!
{
(snake + i + )->snakeX = (snake + i)->snakeX;
(snake + i + )->snakeY = (snake + i)->snakeY;
}
snake->snakeX = snakeHeadTemp.snakeX;
snake->snakeY = snakeHeadTemp.snakeY;
}
//去除尾巴
void eraseTail(struct Snake snakeTail, int snakeR)
{
setfillcolor(BLACK);
solidcircle(snakeTail.snakeX, snakeTail.snakeY, snakeR);
}
//主函数
int main() {
int screenX = ;//窗口宽
int screenY = ;//窗口高
int borderWidth = ;//游戏边框宽度
int snakeX = ;
int snakeY = ;
int snakeR = ;
int snakeI;//声明食物的横个数
int snakeJ;//声明化食物的纵个数
char ch = 'd';
int foodCount = ;//初始化吃掉的食物个数
TCHAR str[];//用于存储提示文字 initgraph(screenX, screenY);
int speed = ; char choose;
int hard = ; restart:
//初始化开始界面
setfillcolor(BLUE);
bar(, , getmaxx(), getmaxy());
setbkcolor(BLUE);
setcolor(WHITE);
settextstyle(, , TEXT("黑体"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("英雄贪吃蛇"));
settextstyle(, , TEXT("黑体"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("请选择难度,切勿手滑"));
setcolor(YELLOW);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));//
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("脑残模式"));//
setcolor(WHITE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("凡人模式"));//
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("大仙模式"));//
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("自虐模式"));//
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("退出游戏"));//退出
settextstyle(, , TEXT("黑体"));
outtextxy(getmaxx() / - , getmaxy() - , TEXT("版本 v1.1 made by cy")); //选择界面12 -32
while (choose = _getch())
{
if (choose == -) { choose = _getch(); }
if (choose == )
{
if (hard == ) { speed = ; }
if (hard == ) { speed = ; }
if (hard == ) { speed = ; }
if (hard == ) { speed = ; }
if (hard == ) { return ; }
break;
}
if (choose == )
{
if (hard > ) { hard--; }
else{ hard = ; }
}
if (choose == )
{
if (hard < ) { hard++; }
else { hard = ; }
}
if (hard == )
{
settextstyle(, , TEXT("黑体"));
setcolor(BLUE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
setcolor(YELLOW);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("脑残模式"));
setcolor(WHITE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("凡人模式"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("大仙模式"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("自虐模式"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("退出游戏"));
speed = ;
}
if (hard == )
{
settextstyle(, , TEXT("黑体"));
setcolor(BLUE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
setcolor(WHITE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("脑残模式"));
setcolor(YELLOW);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("凡人模式"));
setcolor(WHITE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("大仙模式"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("自虐模式"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("退出游戏"));
speed = ;
}
if (hard == )
{
settextstyle(, , TEXT("黑体"));
setcolor(BLUE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
setcolor(WHITE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("脑残模式"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("凡人模式"));
setcolor(YELLOW);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("大仙模式"));
setcolor(WHITE);
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("自虐模式"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("退出游戏"));
speed = ;
}
if (hard == )
{
settextstyle(, , TEXT("黑体"));
setcolor(BLUE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
setcolor(WHITE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("脑残模式"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("凡人模式"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("大仙模式"));
setcolor(YELLOW);
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("自虐模式"));
setcolor(WHITE);
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("退出游戏"));
speed = ;
}
if (hard == )
{
settextstyle(, , TEXT("黑体"));
setcolor(BLUE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
setcolor(WHITE);
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("脑残模式"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("凡人模式"));
outtextxy(getmaxx() / - , getmaxy() / - , TEXT("大仙模式"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("自虐模式"));
setcolor(YELLOW);
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("->"));
outtextxy(getmaxx() / - , getmaxy() / + , TEXT("退出游戏"));
}
} setfillcolor(BLACK);
settextstyle(, , TEXT("黑体"));
bar(, , getmaxx(), getmaxy());
setcolor(WHITE);
setbkcolor(BLACK);
outtextxy(getmaxx() / - , getmaxy()/-, TEXT("食物还有5秒到达战场,碾碎它们!"));
settextstyle(, , TEXT("黑体"));
outtextxy(getmaxx() / - , getmaxy() / , TEXT("小提示:除了方向键,还可以用wasd键来控制方向哦~"));
Sleep();
bar(, , getmaxx(), getmaxy()); drawBorder(true, borderWidth);
//初始化贪吃蛇
setfillcolor(YELLOW);
int snakeLen = ; int * snakeLenPtr = &snakeLen;//蛇的节点数,默认为1,即游戏一开始就有一个蛇头
struct Snake snake[];
snake->snakeX = borderWidth + ; snake->snakeY = borderWidth + ;//初始化蛇头
solidcircle(snake->snakeX, snake->snakeY, snakeR);//初始化蛇头
struct Snake snakeTail;//定义蛇尾snakeTail以及一个暂存蛇头的变量
struct Snake snakeHeadTemp;//snakeHeadTemp用于在进行数组向后移动的时候保证蛇头不被覆盖
struct Snake snakeFood;//snake的食物,随机产生
//整个游戏思路是,如果蛇头遇到了新的食物,那么不擦除蛇尾,反之则擦除蛇尾 //随机产生一个食物
srand(time(NULL));
snakeI = rand() % + ;
snakeJ = rand() % + ;
snakeFood.snakeX = borderWidth - + * snakeI;
snakeFood.snakeY = borderWidth - + * snakeJ;
setfillcolor(LIGHTRED);
solidcircle(snakeFood.snakeX, snakeFood.snakeY, snakeR); char c;//用于处理方向键控制和wasd键的冲突
while ()
{
if (_kbhit())
{
c = _getch();
if (c == 'a' || c == 'd' || c == 'w' || c == 's') { ch = c; }
else {
ch = _getch();
if (ch == ) { ch = 'a'; }
if (ch == ) { ch = 'd'; }
if (ch == ) { ch = 'w'; }
if (ch == ) { ch = 's'; }
}
}
//存储蛇尾以及待添加的位置的值
snakeTail.snakeX = snake[snakeLen - ].snakeX;
snakeTail.snakeY = snake[snakeLen - ].snakeY; switch (ch)
{
case 'a'://左
snakeHeadTemp.snakeX = snake->snakeX - ;
snakeHeadTemp.snakeY = snake->snakeY;
break;
case 'd'://右
snakeHeadTemp.snakeX = snake->snakeX + ;
snakeHeadTemp.snakeY = snake->snakeY;
break;
case 'w'://上
snakeHeadTemp.snakeY = snake->snakeY - ;
snakeHeadTemp.snakeX = snake->snakeX;
break;
case 's'://下
snakeHeadTemp.snakeY = snake->snakeY + ;
snakeHeadTemp.snakeX = snake->snakeX;
break;
default:
break;
}
//如果撞墙了
if (snakeHeadTemp.snakeX > || snakeHeadTemp.snakeX < || snakeHeadTemp.snakeY < || snakeHeadTemp.snakeY > )
{
drawBorder(false, borderWidth);
setfillcolor(LIGHTGRAY);
bar(, getmaxy() / - , getmaxx(), getmaxy() / + );//提示框
setbkcolor(LIGHTGRAY);
_stprintf_s(str, _T("你撞墙啦!总共吃了%d个食物,5秒后自动重新开始游戏,渣渣⋯⋯"), foodCount);
outtextxy(getmaxx() / - , getmaxy() / , str);
Sleep();
ch='d';
hard = ;
foodCount = ;
goto restart;
}
if (checkSnake(snake, snakeHeadTemp, snakeLenPtr))
{
drawSnake(snakeHeadTemp, snakeR);
sortSnake(snake, snakeHeadTemp, snakeLenPtr);//更新蛇身体内的数据
//如果为真,说明吃到了食物,则需要重新分配一个食物。并且要把snakeTail推入数组
if (eraseSnake(snakeHeadTemp, snakeTail, snakeR, snakeFood))
{
foodCount++;
snake[snakeLen].snakeX = snakeTail.snakeX;
snake[snakeLen].snakeY = snakeTail.snakeY;
snakeLen++;
eraseTail(snakeTail, snakeR);
sortSnake(snake, snakeHeadTemp, snakeLenPtr);//更新蛇身体内的数据
//随机产生一个食物
snakeI = rand() % + ;
snakeJ = rand() % + ;
snakeFood.snakeX = borderWidth - + * snakeI;
snakeFood.snakeY = borderWidth - + * snakeJ;
}
//每一步都刷新一下食物,因为有时会生成在蛇的身体上,如果不刷新就会被蛇的身体遮挡掉
setfillcolor(LIGHTRED);
solidcircle(snakeFood.snakeX, snakeFood.snakeY, snakeR);
}
else
{
drawBorder(false, borderWidth);
setfillcolor(LIGHTGRAY);
bar(, getmaxy() / - , getmaxx(), getmaxy() / + );//提示框
setbkcolor(LIGHTGRAY);
_stprintf_s(str, _T("居然会有人撞到自己!噗笑尿!总共吃了%d个食物,5秒后自动重新开始游戏,渣渣⋯⋯"), foodCount);
outtextxy(getmaxx() / - , getmaxy() / , str);
Sleep();
ch = 'd';
hard = ;
foodCount = ;
goto restart;
}
Sleep(speed);
}
closegraph();
return ;
}