一、需要用的头文件以及Linux图形库函数、数据初始化
#include<stdio.h>
#include<curses.h>
#include<stdlib.h>
// 用于调整蛇移动方向,防止蛇移动不合理
#define UP 1
#define DOWN -1
#define LEFT -2
#define RIGHT 2
struct Snake{
int hang; //行
int lie; //列
struct Snake *next; //节点指针
};
struct Snake *head = NULL; //头节点
struct Snake *wei = NULL; //尾巴节点
int direction; // 方向
int key; // 接受方向键的指令
struct Snake food; //控制食物
int cnt =0; //进食分数
(1)关于curses.h图形库函数
1.初始化界面
void initcurses()
{
initscr();
keypad(stdscr,1);
noecho();
}
- initscr() :curses程式必备先呼叫函数,作用是系统将根据终端机的形态并启动 curses模式
- keypad(stdscr,1) :第一个参数stdscr为标准输出荧幕,第二个参数为1(TRUE)/ 0(False),使用keypad目的是为了使用方向键指令
- noecho() : 防止界面产生乱码,图形界面破坏的情况
2.相关函数使用
- getch() :用于从键盘读取一个字元,原理和getchar相似
- endwin() :** 用于结束程式,关闭上述的curses模式
- move(x,y) : 用于在贪吃蛇吃完食物 / 死亡 需要将地图重新生成并且覆盖旧地图,而不是换行重新打印一张新地图
- refresh():用于刷新界面函数,并输出到屏幕
3.使用到curses中的宏建
- KEY_UP 0403 ↑
- KEY_DOWN 0402 ↓
- KEY_LEFT 0404 ←
- KEY_RIGHT 0405 →
二、地图制作
//该地图是20行20列地图
void Map()
{
int hang;
int lie;
move(0,0); //刷新地图,覆盖旧地图
for(hang=0 ; hang<20 ; hang++)
{
if(hang==0)
{
for(lie=0 ;lie<20;lie++)
{
printw("--");
}
printw("\n");
}
else if(hang>0 && hang <19)
{
for(lie=0 ;lie<=20;lie++)
{
if(lie ==0 || lie==20)
{
printw("|");
}
else if(calcSnake(hang,lie)) //生成蛇的身体
{
printw("[]");
}
else if(Eatfood(hang,lie) ) //生成蛇的食物
{
printw("$$");
}
else{
printw(" ");
}
}
printw("\n");
}
else
{
for(lie=0 ; lie<20 ; lie++)
{
printw("--");
}
// 调试信息如下,可以设计添加其他
printw("\n");
printw("The Map is by LiuZheng sir make\n"); // 地图制作者
printw("The food hang = %d,food lie = %d\n",food.hang,food.lie); //记录蛇食物坐标
printw("Alway eat food score = %d\n",cnt); // 记录蛇吃了多少食物
}
}
}
三、蛇身链表的初始化生成
//用于在initsnake中指定方向生成贪吃蛇身体
int calcSnake(int h,int l)
{
struct Snake *p;
p = head;
while(p != NULL)
{
if(p->hang ==h &&p->lie == l)
{
return 1;
}
p = p->next;
}
return 0;
}
//贪吃蛇身体初始化
void initsnake()
{
struct Snake *p;
direction = RIGHT; //规定刚开始蛇朝着右方向移动
if(head !=NULL) //用于清除蛇死亡后残留的数据,清理内存
{
p = head;
head = head->next;
free(p);
}
createfood(); //生成食物
head = (struct Snake*)malloc(sizeof(struct Snake));
head->hang = 2;
head->lie = 2;
head->next = NULL;
wei = head;
//生成蛇的身子
AddNode();
AddNode();
}
四、关于贪吃蛇移动,身体操作
//贪吃蛇身子节点的添加
void AddNode()
{
struct Snake *new;
new = (struct Snake*)malloc(sizeof(struct Snake));
switch(direction)//控制方向上移动
{
case DOWN:
new->hang = wei->hang+1;
new->lie = wei->lie;
break;
case UP:
new->hang = wei->hang-1;
new->lie = wei->lie;
break;
case LEFT:
new->hang = wei->hang;
new->lie = wei->lie-1;
break;
case RIGHT:
new->hang = wei->hang;
new->lie = wei->lie+1;
break;
}
//让新的节点代替之前的尾巴,成为新的尾巴
new->next = NULL;
wei->next = new;
wei = new;
}
//删除贪吃蛇身体节点
void DeleteNode()
{
struct Snake *p =head;
head = head->next;
free(p);
}
//控制贪吃蛇移动的函数
void moveSnake()
{
AddNode();
if(Eatfood(wei->hang,wei->lie) == 1) //如果吃到食物,就重新生成新的食物
{
createfood();
cnt++; //统计贪吃蛇进食分数情况
}
else
{
DeleteNode();
}
if(ifsnakedeath()) //检查移动中贪吃蛇是否撞墙或者自己吃自己,导致死亡
{
initsnake(); //死亡之后需要重新生成贪吃蛇
cnt=0;
}
}
//查看贪吃蛇是否撞墙死亡 / 自己吃自己
int ifsnakedeath()
{
struct Snake *p =head;
if(wei->hang == 0||wei->lie ==0||wei->hang ==19||wei->lie== 19) //检查撞墙
{
return 1;
}
while(p->next != NULL)
{
if(p->hang == wei->hang && p->lie ==wei->lie) // 检查是否自杀
{
return 1;
}
p = p->next;
}
return 0;
}
总结:
无论贪吃蛇朝着那个方向移动,都是头节点删除,尾巴节点添加,从而达到身体移动的目的
五、关于贪吃蛇的食物解析
//用于确定在随机生成的食物坐标中,在地图上打印该食物
int Eatfood(int h,int l)
{
if(food.hang == h && food.lie ==l)
{
return 1;
}
return 0;
}
void createfood()
{
int x = rand()%20; //使用rand()函数随机生成一个坐标值
int y = rand()%20; //使用rand()函数随机生成一个坐标值
if(x==0 || x==19 || y==0 || y==19) //防止食物生成到地图边缘或者离开地图
{
x = rand()%20;
y = rand()%20;
}
food.hang = x;
food.lie = y;
}
六、控制贪吃蛇移动的方向位置
标注:
由于需要地图的刷新,贪吃蛇方向的移动和改变、食物的生成,系统一个线程是忙不过来的,因此我们需要引进线程的概念,创建多个线程来分布执行这些命令操作
线程创建格式:
//创建线程 t1、t2
pthread_t t1;
pthread_t t2;
pthread_create(&t1,NULL,refreshSnake,NULL); //t1进程实现贪吃蛇移动
pthread_create(&t2,NULL,Changedirection,NULL); //t2进程实现贪吃蛇改变方向位置
//用该进程进行贪吃蛇移动
void refreshSnake()
{
while(1)
{
moveSnake();
Map();
refresh(); //刷新界面
usleep(40000); //控制贪吃蛇移动速度,这里是微秒单位
}
}
//防止贪吃蛇位置移动不合理
void Turndirection(int dir)
{
if(abs(direction) != abs(dir))
{
direction = dir;
}
}
void Changedirection()
{
while(1)
{
key = getch();//获取方向键控制贪吃蛇移动指令
switch(key) //发送贪吃蛇方向移动指令
{
case KEY_DOWN: //向上
Turndirection(DOWN);
break;
case KEY_UP: //向下
Turndirection(UP);
break;
case KEY_LEFT: //向左
Turndirection(LEFT);
break;
case KEY_RIGHT: //向右
Turndirection(RIGHT);
break;
}
}
}
七、主函数
int main()
{
pthread_t t1; //建立线程t1
pthread_t t2; //建立线程t2
initcurses();
initsnake();
Map();
pthread_create(&t1,NULL,refreshSnake,NULL);
pthread_create(&t2,NULL,Changedirection,NULL);
while(1); //防止该进程不退出
getch();
endwin();
return 0;
}
八、代码实现
#include<stdio.h>
#include<curses.h>
#include<stdlib.h>
#define UP 1
#define DOWN -1
#define LEFT -2
#define RIGHT 2
void initcurses()
{
initscr();
keypad(stdscr,1);
noecho();
}
struct Snake{
int hang;
int lie;
struct Snake *next;
};
struct Snake *head = NULL;
struct Snake *wei = NULL;
int direction;
int key;
struct Snake food;
int cnt =0;
int calcSnake(int h,int l)
{
struct Snake *p;
p = head;
while(p != NULL)
{
if(p->hang ==h &&p->lie == l)
{
return 1;
}
p = p->next;
}
return 0;
}
int Eatfood(int h,int l)
{
if(food.hang == h && food.lie ==l)
{
return 1;
}
return 0;
}
void createfood()
{
int x = rand()%20;
int y = rand()%20;
if(x==0 || x==19 || y==0 || y==19)
{
x = rand()%20;
y = rand()%20;
}
food.hang = x;
food.lie = y;
}
void Map()
{
int hang;
int lie;
move(0,0);
for(hang=0 ; hang<20 ; hang++)
{
if(hang==0)
{
for(lie=0 ;lie<20;lie++)
{
printw("--");
}
printw("\n");
}
else if(hang>0 && hang <19)
{
for(lie=0 ;lie<=20;lie++)
{
if(lie ==0 || lie==20)
{
printw("|");
}
else if(calcSnake(hang,lie))
{
printw("[]");
}
else if(Eatfood(hang,lie) )
{
printw("$$");
}
else{
printw(" ");
}
}
printw("\n");
}
else
{
for(lie=0 ; lie<20 ; lie++)
{
printw("--");
}
printw("\n");
printw("The Map is by LiuZheng sir make\n");
printw("The food hang = %d,food lie = %d\n",food.hang,food.lie);
printw("Alway eat food score = %d\n",cnt);
}
}
}
void AddNode()
{
struct Snake *new;
new = (struct Snake*)malloc(sizeof(struct Snake));
switch(direction)
{
case DOWN:
new->hang = wei->hang+1;
new->lie = wei->lie;
break;
case UP:
new->hang = wei->hang-1;
new->lie = wei->lie;
break;
case LEFT:
new->hang = wei->hang;
new->lie = wei->lie-1;
break;
case RIGHT:
new->hang = wei->hang;
new->lie = wei->lie+1;
break;
}
new->next = NULL;
wei->next = new;
wei = new;
}
void DeleteNode()
{
struct Snake *p =head;
head = head->next;
free(p);
}
void initsnake()
{
struct Snake *p;
direction = RIGHT;
if(head !=NULL)
{
p = head;
head = head->next;
free(p);
}
createfood();
head = (struct Snake*)malloc(sizeof(struct Snake));
head->hang = 2;
head->lie = 2;
head->next = NULL;
wei = head;
AddNode();
AddNode();
}
void moveSnake()
{
AddNode();
if(Eatfood(wei->hang,wei->lie) == 1)
{
createfood();
cnt++;
}
else
{
DeleteNode();
}
if(ifsnakedeath())
{
initsnake();
cnt=0;
}
}
int ifsnakedeath()
{
struct Snake *p =head;
if(wei->hang == 0||wei->lie ==0||wei->hang ==19||wei->lie== 19)
{
return 1;
}
while(p->next != NULL)
{
if(p->hang == wei->hang && p->lie ==wei->lie)
{
return 1;
}
p = p->next;
}
return 0;
}
void refreshSnake()
{
while(1)
{
moveSnake();
Map();
refresh();
usleep(40000);
}
}
void Turndirection(int dir)
{
if(abs(direction) != abs(dir))
{
direction = dir;
}
}
void Changedirection()
{
while(1)
{
key = getch();
switch(key)
{
case KEY_DOWN:
Turndirection(DOWN);
break;
case KEY_UP:
Turndirection(UP);
break;
case KEY_LEFT:
Turndirection(LEFT);
break;
case KEY_RIGHT:
Turndirection(RIGHT);
break;
}
}
}
int main()
{
pthread_t t1;
pthread_t t2;
initcurses();
initsnake();
Map();
pthread_create(&t1,NULL,refreshSnake,NULL);
pthread_create(&t2,NULL,Changedirection,NULL);
while(1);
getch();
endwin();
return 0;
}
哪里不好,有待提高的地方还望大佬指出,共同进步!感谢你的留言!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68486.html