linux系统贪吃蛇主函数,Linux平台下贪吃蛇游戏的运行

1.参考资料说明:

这是一个在Linux系统下实现的简单的贪吃蛇游戏,同学找帮忙,我就直接在Red Hat中调试了一下,参考的是百度文库中“maosuhan”仁兄的文章,结合自己的一些实践遇到的问题,整理后,将解决方案和大家分享一下。

2.开发环境:

linux+gcc+netbeans

3.思路介绍:

多线程处理。一个线程负责逻辑和画图,一个线程监听按键。

3.1 两个线程使用理由:

在c里面,最方便的就是getch方法了,但是这个函数会进行io的阻塞,知道按下了一个键,在这之前这个线程会被阻塞住,蛇也就不会移动了。所以需要开两个线程一 个线程是专门画图的,每隔多长的时间刷一下,另外一个线程是专门负责监听键盘事件的,就算会阻塞也只是影响到的本线程,画图线程不会被阻塞。并且两个线程是通过一个全部的变量input来进行通信的,这个input存储的是按键的键值ascii。

3.2   使用一个线程情况

如果非要用一个线程寄来负责逻辑、画图,又负责按键监听,也可以采用peek函数,peek函数会接受一个数字,比如说是peek(100),100就表示一个特定的调用例程。比如这里的100就是检测键盘的缓冲区有没有按下一个键并且键值是多少,这个是不会阻塞的。虽然这个peek调用看上比较丑陋,但是却可以实现单线程监听按键不阻塞的功能。但我还是认为两个线程比较方便,也符合更多人的逻辑。

言归正传,还是考虑在linux下怎么用c编程吧!

3.3创建监听键盘事件的线程。

void * waitForKey(void *para)

{

while (1)

{

input = getch();

}

}

pthread_t id;//声明一个linux线程,按键等待线程

int ret;

ret = pthread_create(&id, NULL, waitForKey, NULL);//创建线程,其实就是一个函数,有点像java里面的Runnable的感觉。

if (ret != 0) {

exit(1);

}

4.部分函数说明

我还用到了一个库,就是curses,这个是专门用来绘图ui用的。但是在/usr/include里面是没有的,要到网上去下

sudo apt-get installlibncurses-dev

(针对不同的Linux系统有所不同,可以参照下一篇《Linux系统中UI库curse.h不存在问题》)

initscr(); //初始化操作

do_some_drawing();//这里你可以定义你自己的绘图形式

refresh();

endwin();

其中我用到的函数有move(x,y)是把光标定位在某行某列上。还有addStr(s)和addch(c)。是在光标处写字符串和写字符。

还有getch()等待用户按键。还有refresh(),将缓冲的绘图操作都输出到屏幕上。

此外还用到了usleep(int )函数这里的参数是int型的,表示的是微秒数,1秒等于1000000微秒。这里的时间间隔是蛇每次移动时的间隔时间。

还有,在不断地刷新屏幕的时候,没有说把整个屏幕都刷新一遍,再重新全部画点。而是只是重画一部分,像围墙就一直没有重画。而每次paint都是只把整个蛇的身体画出   来,再把最后的一个尾巴清除掉。其实还可以有更好的方法,就是身体都不要动的,只要改变一个头,清除一个尾就可以了,我这里的效率还是不高的。

用gcc编译:gcc Snack.c –o Snack –l pthread –l curses

(如果不包含curses.h头文件,说明你的gcc中没有,可以参照上面curses库安装说明。)

./Snack   运行结果下图所示:

3b16096fa1b87ccec7317f092ae894ed.png

5.整个的程序的源代码

#include

#include

#include

#include //这个就是我们要用到的额外的ui库

#include

#define MAX_X 70 //场地宽

#define MAX_Y 20 //场地长

#define CORNER_X 4 //左上角x坐标

#define CORNER_Y 2 //左上角y坐标

struct point {

int x;

int y;

};

struct point SnakeBody[50];

struct point food;

int Length = 4; //初始蛇长

int life = 1; //是否还活着

int input = 0; //记录键盘按键的ascii

pthread_t id;//声明一个linux线程,按键等待线程

void FoodCheck();//检查是否吃到了食物

void FoodProduce();//生成一个食物

void Initializition();//初始化线程,进行蛇的初始设定,创建第一个食物

void SnakeHeadMovement();//移动蛇

void SnakeBodyMovement();//移动蛇辅助方法

void DeathCheck();//检查是否满足死亡条件

void Paint();//画社画场地画食物

void * waitForKey(void *);//这个是另一个线程的函数定义

void drawDot(int x,int y,char s);//画点喽

void clearDot(int x,int y);//清楚点喽

void end();//程序的结束工作

//主函数

int main(int argc,char** argv)

{

Initializition();

refresh();//刷新画布

while (life) {

Paint();

usleep(200000);//刷新频率是0.2秒

SnakeHeadMovement();//移动蛇,在这个方法里执行了foodCheck方法。其实这里的逻辑稍微混乱了点

DeathCheck();//判断是否死亡

}

end();

return 0;

}

void * waitForKey(void *para)

{

while (1)

{

usleep(1000);//为什么要加这个,不知道什么原因,在curses下,如果建了这个线程并且不加这句话的话就会出现花屏现象。很难看

input = getch();

}

}

void end()

{

move(1, 0);

addstr("Press any key to quit!");

refresh();

getch();

endwin();

}

//食物的随机产生

void FoodProduce()

{

int superposition = 0;

int i;

srand(time(NULL));

do {

food.x = (rand() % ((MAX_X-2) / 2))*2+2; //2 to MAX_X-2 and is 偶数

food.y =rand() % (MAX_Y-1)+1; //1 to MAX_Y-1

for (i = 0; i < Length; i++) {

if (food.x == SnakeBody[i].x && food.y == SnakeBody[i].y)

superposition = 1;

}

}while (superposition);/*直到没有重合*/

}

//蛇身和食物的初始化 初始化的蛇身为4节长度

void Initializition()

{

initscr();//curses初始化

noecho();//默认不将输入的字符显示在屏幕上

int i;

for (i = 3; i <= 6; i++) {//初始化蛇

SnakeBody[6 - i].x = 4;

SnakeBody[6 - i].y = i;

}

FoodProduce();

int ret;

ret = pthread_create(&id, NULL, waitForKey, NULL);//创建线程

if (ret != 0)

{

exit(1);

}

for ( i = 0; i <= MAX_X; i+=2)

{ //画围墙

drawDot(i, 0,'*');

drawDot(i, MAX_Y,'*');

}

for (i = 0; i <= MAX_Y; i++)

{

drawDot(0, i,'*');

drawDot(MAX_X, i,'*');

}

}

//蛇移动,依次从尾巴到头赋值

void SnakeBodyMovement()

{

int i;

for (i = Length - 1; i > 0; i--)

{

SnakeBody[i].x = SnakeBody[i - 1].x;

SnakeBody[i].y = SnakeBody[i - 1].y;

}

}

void SnakeHeadMovement()

{

clearDot(SnakeBody[Length - 1].x, SnakeBody[Length - 1].y);

int directionX, directionY;/*定义原本蛇前进的方向,可通过蛇头坐标减去蛇的第二部分*/

int newX, newY;

newX = SnakeBody[0].x;

newY = SnakeBody[0].y;

directionX = SnakeBody[0].x - SnakeBody[1].x;

directionY = SnakeBody[0].y - SnakeBody[1].y;

if (input =='w' && directionY<=0)//不走回头路

newY--;

else if (input =='s' && directionY>=0 )

newY++;

else if (input =='a' && directionX<=0)

newX -= 2;/*因为字符高是宽的两倍*/

else if (input =='d' && directionX>=0)

newX += 2;

else

{

newX += directionX;

newY += directionY;

}

FoodCheck();

SnakeBodyMovement();

SnakeBody[0].x = newX;

SnakeBody[0].y = newY;

}

//判断是否吃到食物,以及吃到后长度变长还有产生新的食物

void FoodCheck()

{

if (food.x == SnakeBody[0].x && food.y == SnakeBody[0].y)

{

Length = Length + 1;

FoodProduce();

}

}

//判断是否死亡

void DeathCheck() {

int i;

if (SnakeBody[0].x <=1 || SnakeBody[0].x >= MAX_X || SnakeBody[0].y <= 0 || SnakeBody[0].y >=MAX_Y)

life = 0;

for (i = 4; i < Length; i++)

if (SnakeBody[0].x == SnakeBody[i].x && SnakeBody[0].y == SnakeBody[i].y)

life = 0;

}

//排序和打印

void Paint() {

int i = 0;

drawDot(SnakeBody[i].x, SnakeBody[i].y,'@');

for (i=1; i < Length; i++) {

drawDot(SnakeBody[i].x, SnakeBody[i].y,'*');

}

drawDot(food.x, food.y,'$');

move(0,0);

refresh();//刷新画布

}

void drawDot(int x,int y,char s) {

move(y+CORNER_Y, x+CORNER_X);

addch(s);

}

void clearDot(int x,int y) {

move(y+CORNER_Y, x+CORNER_X);

addch(' ');

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值