贪吃蛇是一个简单的游戏
就先写一个试试水吧
在写程序之前,先要想一下程序的大体构造
我的思路是有以下功能
开始界面
选择难度
游戏主体
初始化地图
读入处理
移动
游戏结束画面
这样子就可以围绕此框架来设计程序了
基本上就是按部就班的写了
但是还是有一些重点问题需要提一下
如何使每一次输出画面后清屏再输出下一个画面呢?
我们可以调用 windows.h 中的 system(“cls”)
如下
#include
system("cls");
而在Linux下就简单许多
直接
printf("\033[2J");
当使用了清屏后
你会发现游戏过程屏幕一直在闪
这是因为你没有让光标定位
这里给上光标定位的代码
windows下
同样在windows.h中
CONSOLE_CURSOR_INFO cursor_info = {1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
Linux 下
printf("\033[%d;%dH", (1), (0));
这是流畅的玩游戏的关键
在windows中比较简单
使用 conio.h 的kbhit() 和 getch() 就行
include
kbhit();
getch();
而 Linux 下,要实现 kbhit()
就要加入以下代码
#include
#include
#include
#include
#include
#include
#include
static struct termios ori_attr, cur_attr;
static __inline
int tty_reset(void)
{
if (tcsetattr(STDIN_FILENO, TCSANOW, &ori_attr) != 0)
return -1;
return 0;
}
static __inline
int tty_set(void)
{
if ( tcgetattr(STDIN_FILENO, &ori_attr) )
return -1;
memcpy(&cur_attr, &ori_attr, sizeof(cur_attr) );
cur_attr.c_lflag &= ~ICANON;
// cur_attr.c_lflag |= ECHO;
cur_attr.c_lflag &= ~ECHO;
cur_attr.c_cc[VMIN] = 1;
cur_attr.c_cc[VTIME] = 0;
if (tcsetattr(STDIN_FILENO, TCSANOW, &cur_attr) != 0)
return -1;
return 0;
}
static __inline
int kbhit(void)
{
fd_set rfds;
struct timeval tv;
int retval;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1) {
perror("select()");
return 0;
} else if (retval)
return 1;
/* FD_ISSET(0, &rfds) will be true. */
else
return 0;
return 0;
}
int main()
{
//设置终端进入非缓冲状态
int tty_set_flag;
tty_set_flag = tty_set();
//恢复终端设置
if(tty_set_flag == 0)
tty_reset();
return 0;
}
这里应该是最重要的地方了
详细说一下
肯定是要写个框架先
初始化地图
WHILE 没死 DO
停顿至 设定时间或键盘输入
IF 键盘输入
方向=输入
END IF
CASE 方向
w 向上移动
s 向下移动
d 向右移动
a 向左移动
END CASE
IF 死亡 BREAK
END WHILE
这就是大概框架了
之后的任务就好办了
下面就贴出我的贪吃蛇的代码
/*
---------------------------------------------------------------
snake.cpp
sanke
Created by Cynosure_ on 2017-12-20
---------------------------------------------------------------
思路:
将当前地图情况存在数组中
记录蛇头、蛇尾坐标
以及蛇身每一块的下一块(更趋于头的一块)的坐标用以更新蛇尾
每次动作更新蛇头与蛇尾即可
---------------------------------------------------------------
*/
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define snake_head 'H'
#define snake_body 'X'
#define blank_cell ' '
#define snake_food '$'
#define wall_cell '*'
int end_game=0; // 判断游戏是否结束的bool值
int speed,start,if_hit;
char ch; // 存储输入
char direction,if_start_game;
char map1[15][20]=
{
"******************",
"*XXXXH *",
"* *", //初始地图
"* *", //打表初始化
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"******************",
};
char map[15][20];
int headx=1,heady=5,tailx=1,taily=1;
int nextx1[15][20]={
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, //记录每一个节点的下一个节点的x坐标
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
int nexty1[15][20]=
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,2,3,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, //记录每一个节点的下一个节点的y坐标
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
int nextx[15][20],nexty[15][20];
void print_map(){ // 从 map[][] 中打印当前地图
for (int i=0;i<15;i++){
for (int j=0;j<20;j++){
printf("%c",map[i][j]);
}
printf("\n");
}
}
void put_food(){ // 随机加入食物
srand(time(0)); // 初始化伪随机
int x,y;
while (1) { // 一直循环随机出可行坐标
x=rand() % 15;y=rand() % 20; // 随机一个坐标
if (map[x][y]==blank_cell) { // 若此坐标为空白格
map[x][y]=snake_food; // 改为食物
return; // 跳出
}
}
}
void move(int xx,int yy){ // 移动 (蛇头x坐标+xx,y坐标+yy)
int if_eat=0; // 记录是否吃到食物的 bool
int x,y;
if (map[headx+xx][heady+yy]==snake_food) { // 判断 判断蛇头移动至的位置是否食物
if_eat=1; // 若是更新状态
}
if (!if_eat) { // 若没有吃到食物则蛇尾向前缩一格
map[tailx][taily]=blank_cell; // 将蛇尾变为空白格
x=nextx[tailx][taily];y=nexty[tailx][taily]; // 用 x、y 暂存新的蛇尾(蛇尾坐标下一个的节点坐标)
tailx=x;taily=y; // 更新蛇尾坐标
}
if (map[headx+xx][heady+yy]==wall_cell||map[headx+xx][heady+yy]==snake_body) { // 判断蛇头移动至的位置是否墙或蛇身
end_game=1; // 若是墙或蛇身则游戏结束
return; // 跳出
}
x=headx+xx;y=heady+yy; // // 用 x、y 暂存新的蛇头(蛇蛇头x坐标+xx,y坐标+yy)
nextx[headx][heady]=x;nexty[headx][heady]=y; // 设置旧蛇头的的下一个节点
map[x][y]=snake_head; // 旧蛇头位置变为蛇身
map[headx][heady]=snake_body; // 新蛇头位置变成蛇头
headx=x;heady=y; // 更新蛇头坐标
if (if_eat) { // 如果吃过食物则生成新的食物
put_food();
}
}
void reset_map(){
memcpy(map,map1,sizeof(map1));
memcpy(nextx,nextx1,sizeof(nextx1));
memcpy(nexty,nexty1,sizeof(nexty1));
headx=1,heady=5,tailx=1,taily=1;
}
int game(){
system("cls");
reset_map();
put_food(); // 生成一开始的食物
print_map(); // 输出初始地图
direction='d';
end_game=0;
while (!end_game) { // 一直循环至游戏结束
start=clock();
ch=direction;
if_hit=1;
while ((if_hit=(clock()-start<=speed))&&!kbhit());
if (if_hit) {
ch=getch();
direction=ch;
}
switch (ch){
case 'a' :
move(0,-1); //向左前进一步
break;
case 'd':
move(0,1); // 向右前进一步
break;
case 'w':
move(-1,0); // 向上前进一步
break;
case 's':
move(1,0); // 向后前进一步
break;
}
system("cls");
print_map();//输出此时地图
}
}
void choose_hard(){
system("cls");
cout << "\n\n\n\t\t<1> 难度1";
cout << "\n\n\t\t<2> 难度2";
cout << "\n\n\t\t<3> 难度3";
cout << "\n\n\t\t<4> 难度4";
cout << "\n\n\t\t<5> 难度5";
cout << "\n\n\t\t<6> 难度6";
char hard=getch();
switch (hard) {
case '1':
speed=1200;
break;
case '2':
speed=900;
break;
case '3':
speed=600;
break;
case '4':
speed=300;
break;
case '5':
speed=200;
break;
case '6':
speed=50;
break;
}
}
int main(){
CONSOLE_CURSOR_INFO cursor_info = {1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
cout << "\n\n\n\n\t\t欢迎来到贪吃蛇游戏\n\n\n\n\t\t按任意键继续";
getch();
if_start_game='y';
while (if_start_game=='y') {
choose_hard();
game();
system("cls");
cout << "\n\n\n\n\t\t哇哦你死了哦\n\n\n\n\t\t是否继续呢(输入'y'继续,输入'n'结束 >";
cin >> if_start_game;
}
}
windows下运行哦