IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux操作系统下的贪吃蛇小游戏 -> 正文阅读

[系统运维]Linux操作系统下的贪吃蛇小游戏

? ? 最近在学习Linux操作系统,为了加深自己对于C语言的掌握和理解,这两天写了一个比较复杂的小游戏。贪吃蛇代码量大概有300行左右,基本上运用上了C语言的常见的知识点(指针,链表,结构体,函数封装与调用等),对于自己的C语言能力的加强和逻辑思考能力的提升有较大的帮助。

? ? 啰嗦的话不多说了,先上代码吧!

#include <curses.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#define UP    0403
#define DOWN  0402
#define LEFT  0404
#define RIGHT 0405

#define TURN_UP    1
#define TURN_DOWN -1
#define TURN_RIGHT 2
#define TURN_LEFT -2

struct snake
{
 int hang;
 int lie;
 struct snake *next;
};

struct snake *head=NULL;
struct snake *tail=NULL;
struct snake food;

int key;
int turn;
int now_turn;

void Init_Curses()
{
 initscr();
 keypad(stdscr,1);
 noecho();
}

void Turn_Statu(int now_turn)
{
 if(abs(now_turn)!=abs(turn))
 turn=now_turn;
}

void *Snack_Direct_Control()
{
 while(1)
 {
  key=getch();
  switch(key)
  {
   case UP:
   printw("up\n");
   now_turn=TURN_UP;
   Turn_Statu(now_turn);   
   break;
   case DOWN:
   printw("down\n");
   now_turn=TURN_DOWN;
   Turn_Statu(now_turn);   
   break;
   case LEFT:
   printw("left\n");
   now_turn=TURN_LEFT;
   Turn_Statu(now_turn);   
   break;
   case RIGHT:
   printw("right\n");
   now_turn=TURN_RIGHT;
   Turn_Statu(now_turn);   
   break;
  }
 }
}

void Add_Snake_Node()
{
 struct snake *new=(struct snake*)malloc(sizeof(struct snake));
 switch(turn)
 {
  case TURN_UP:
  new->hang=tail->hang-1;
  new->lie=tail->lie;
  break;
  case TURN_DOWN:
  new->hang=tail->hang+1;
  new->lie=tail->lie;
  break;
  case TURN_LEFT:
  new->hang=tail->hang;
  new->lie=tail->lie-1;
  break;
  case TURN_RIGHT:
  new->hang=tail->hang;
  new->lie=tail->lie+1;
  break;
 }
 new->next=NULL;
 tail->next=new;
 tail=new;
}

void Init_Food()
{
 int x=rand()%19;
 int y=rand()%19;
 food.hang=x;
 food.lie=y;
 food.next=NULL;
}

int Deter_Food(int x,int y)
{
 if(x==food.hang&&y==food.lie)
 return 1;
 else
 return 0;
}

void Init_Snake_Node()
{
 Init_Food();
 turn=TURN_LEFT;
 struct snake *p;
 while(head!=NULL)
 {
  p=head;
  head=head->next;
  free(p);
 }
 head=(struct snake*)malloc(sizeof(struct snake));
 head->hang=1;
 head->lie=17;
 head->next=NULL;
 tail=head;
 Add_Snake_Node();
 Add_Snake_Node();
 Add_Snake_Node();
}

int Deter_Link_Node(int hang,int lie)
{
 struct snake *p=head;
 while(p!=NULL)
 {
  if(p->hang==hang&&p->lie==lie)
  return 1;
  p=p->next;
 }
return 0;
}

void Snack_Picture()
{
 int hang,lie;
 move(0,0);
 for(hang=0;hang<20;hang++)
 {
  if(hang==0)
  {           
   for(lie=0;lie<20;lie++)
   printw("--");
   printw("\n");
  }
  if(hang>=0&&hang<20)
  {
   for(lie=0;lie<=20;lie++)
   {
    if(lie==0||lie==20)
    printw("|");
    else if(Deter_Link_Node(hang,lie))
    printw("[]");
    else if(Deter_Food(hang,lie))
    printw("##");
    else
    printw("  ");
   }
   printw("\n");
  }
  if(hang==19)
  {
   for(lie=0;lie<20;lie++)
   printw("--");
  }
 }
 printw("\npower by Vincent-NJW\n");
}

void Delete_Snake_Node()
{
 struct snake *p;
 p=head;
 head=head->next;
 free(p);
}

int Loop_Snake()
{
 struct snake *p=head;
 while(p->next!=NULL)
 {

  if(tail->hang==p->hang&&tail->lie==p->lie)
  return 1;
  else
  p=p->next;
 }
}

void *Move_Snake()
{
 while(1)
 {	 
  Add_Snake_Node();
  if(Deter_Food(tail->hang,tail->lie))
  Init_Food();
  else
  Delete_Snake_Node();
  Snack_Picture();
  refresh();
  usleep(100000);
  if(tail->hang==-1||tail->hang==20||tail->lie==0||tail->lie==20)
  Init_Snake_Node();
  if(Loop_Snake())
  Init_Snake_Node();
 }
}


void main()
{
 Init_Curses();

 pthread_t t1;
 pthread_t t2;

 pthread_create(&t1,NULL,Snack_Direct_Control,NULL);

 Init_Snake_Node();
 Snack_Picture();

 pthread_create(&t2,NULL,Move_Snake,NULL);
 while(1);
 endwin();
}

//Vincent——NJW

效果图:? ? ? ? ??

?

? ? ? ? ? ? ? 由于在ubantu的vim工具下,我不是很清楚怎么打汉字,所以代码段就没有写注释。

重点的配置:

1:对此项目里面我用了Ncurses,目的是为了使用“getch()”函数。此函数区别于“getchar”的特点是在键盘输入字符之后不需要在按回车键来结束这个输入。我们可以想一下,如果我们每次操控贪吃蛇的方向都需要按一下方向键在按一下回车键,操作起来会非常的反人类。另外还用了它的几个函数,比如说move()(设置打印光标移动)还有一些我也不是很懂的函数。大家不需要深究,只需要大概知道这个函数怎么用即可,我们还是要要重点放到对于C语言和Linux上来。

安装Ncurses:命令行下输入sudo apt-gat install?libncurses5-dev

2:第二个是对于Linux多进程函数的初次使用,我之前在学习FreeRTOS的时候学习了多进程的概念。可以这样理解:同一个时间点可以有多个任务在运行(任务指的就是函数)。

对于此项目而言,我们只用了Linux环境下的创建进程的函数:

pthread_t t2;

?pthread_create(&t1,NULL,Snack_Direct_Control,NULL);

目的是为了从键盘获取输入的同时还可以控制贪吃蛇的运动轨迹(两个while(1))。

3:由于我们用了Ncurses和Linux的函数,所以我们在gcc编译的时候就不能像常规的编译那样直接gcc test.c,我们需要加一些后缀,gcc test.c -lcurses -lpthread。

代码思路讲解:

具体的思路就是如下的while(1)循环:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?图片的格式不是很好调,麻烦点开看吧。

第一个while(1)是用来作用蛇的风骚走位。第二个while(1)是用来获取用户从键盘输入的数据,用来决定蛇的风骚走位(上下左右)。这两个while(1)用了Linux的任务调度函数,让这两个while(1)同时一起工作。

第一个while(1)

第一步:增加蛇的一个节点

注意这个节点是尾节点,每次都增加一个节点,但是怎么增加是有讲究的。我们会在第二个while(1)里面获取用户输入的数据,根据这个数据我们来决定蛇的走向,也就是下一个尾节点是在之前一个尾节点的上下左右方向的其中一个。最后把这个最新的尾节点和之前的链表连接上。

?

第二步:判断这个新增的尾节点是否和食物的坐标重合

?如果重合,咋们就用Init_Food()函数从新随机产生一个食物。如果没有就把蛇的头结点删除

这样就会在没有吃食物的情况下保持蛇的长度不变。

Deter_Food(int hang,int lie)函数输入行和列,判断这个行和列坐标下有没有食物,如果有返回1,没有返回0。

Init_Food()函数用来随机产生一个食物,用rand函数实现。

Delete_Snake_Node()函数删除链表头结点。

第三步:刷新界面

Snack_Picture()函数不光绘制了地图的边框,还绘制了蛇的各个节点和食物。具体思路是用for嵌套。我们绘制的地图是20*20的方形。第一个for遍历行,第二个for遍历列,第一行和最后一行是'--'组成,?中间20行的两侧是'|'中间是空白(注意的是第一行是由一行的'-'和两侧的两个'|'组成,最后一行也一样)。

中间的空白我们用多个if语句优先级判断有没有蛇的节点或者食物或者空白,判断有没有食物用函数Deter_Food(int hang,int lie)前面讲过。判断有没有蛇的节点用Deter_Link_Node()函数,内涵是链表遍历的同时判断有没有节点和这个位置的坐标相同。

?

refresh()函数是Ncurse的封装函数用来刷新。

usleep(100000)函数us延时用来决定蛇走的快慢。

第四步:判断蛇是怎么gg的

1:撞墙gg,就是新的尾节点的行列坐标有没有到边界(0,20)。

2:自己咬自己gg,遍历链表的同时把尾节点和各个节点的坐标比较,如果有一样的就gg。

?Loop_Snake()函数用来判断蛇有没有自己咬自己,咬了自己返回1,没有返回0.

?第一个while(1)结束

第二个while(1)

?

这个while(1)就比较简单了,用getch()来获得用户的输入,我在上面也说过这个函数不用在输入之后加回车键结束,这也是它的最大优势。之后的switch就很简单了,学过单片机的肯定都写过这种结构,按键控制灯,那个按键控制那个灯的亮灭,这里我就不具体描述了。

第二个while(1)结束

好了,大致的思路就是这些。但是里面还有一些具体的小细节,大家可以先把代码跑起来,通过现象来慢慢学习本质。

本人也是小白,有讲的不对的,欢迎指正。

NAME:Vincent-NJW? ? ? ? ? ? ? QQ:1504012979

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 想让学习变得简单——Vincent-NJW

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-12-23 16:04:59  更:2021-12-23 16:06:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 5:42:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码