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   运行结果下图所示:

5.整个的程序的源代码

#include<stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <curses.h>//这个就是我们要用到的额外的ui库
#include <stdlib.h> #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(' ');
}

Linux平台下贪吃蛇游戏的运行的更多相关文章

  1. 用C++实现的贪吃蛇游戏

    我是一个C++初学者,控制台实现了一个贪吃蛇游戏. 代码如下: //"贪吃蛇游戏"V1.0 //李国良于2016年12月29日编写完成 #include <iostream& ...

  2. WebGL实现HTML5的3D贪吃蛇游戏

    js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...

  3. 100行JS实现HTML5的3D贪吃蛇游戏

    js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...

  4. Love2D游戏引擎制作贪吃蛇游戏

    代码地址如下:http://www.demodashi.com/demo/15051.html Love2D游戏引擎制作贪吃蛇游戏 内附有linux下的makefile,windows下的生成方法请查 ...

  5. Qt 学习之路 2(34):贪吃蛇游戏(4)

    Qt 学习之路 2(34):贪吃蛇游戏(4) 豆子 2012年12月30日 Qt 学习之路 2 73条评论 这将是我们这个稍大一些的示例程序的最后一部分.在本章中,我们将完成GameControlle ...

  6. Qt 学习之路 2(33):贪吃蛇游戏(3)

    Qt 学习之路 2(33):贪吃蛇游戏(3) 豆子 2012年12月29日 Qt 学习之路 2 16条评论 继续前面一章的内容.上次我们讲完了有关蛇的静态部分,也就是绘制部分.现在,我们开始添加游戏控 ...

  7. linux平台下防火墙iptables原理(转)

    原文地址:http://www.cnblogs.com/ggjucheng/archive/2012/08/19/2646466.html iptables简介 netfilter/iptables( ...

  8. Windows及Linux平台下的计时函数总结

    本文对Windows及Linux平台下常用的计时函数进行总结,包括精度为秒.毫秒.微秒三种精度的各种函数.比如Window平台下特有的Windows API函数GetTickCount().timeG ...

  9. Thrift在Windows及Linux平台下的安装和使用示例

    本文章也同时发表在个人博客Thrift在Windows及Linux平台下的安装和使用示例上. thrift介绍 Apache Thrift 是 Facebook 实现的一种高效的.支持多种编程语言的R ...

随机推荐

  1. ubuntu下USB连接Android手机

    初始工作:将Android手机通过usb连接到电脑,之后点击VM-Removable Devices-google Android - Connect,即可. 若通过usb连接到电脑,Removabl ...

  2. Android 完整开源应用大全,完整开源项目

    (Antox)聊天的  (new) (OpenKeychain)OpenPGP在android上的实现  (new) (Flock)提供同步服务 (OpenFlappyBird)以前火爆的坑爹鸟 (F ...

  3. sprint3 【每日scrum】 TD助手站立会议第八天

    站立会议 组员 昨天 今天 困难 签到 刘铸辉 (组长) 调整闹钟和整个项目的显示效果,最后做出了微信界面滑动的显示效果 整合原来做过的功能,并做相应的改进,整合其他的功能 在界面的设计和用户交互上始 ...

  4. linux下拷贝隐藏文件

    1.拷贝隐藏文件 把/home/u文件夹中的全部文件(包含隐藏文件)拷贝到/home/user1中  cp   -a   /home/u/.    /home/user1 2.改动主机名: vi /e ...

  5. awk.sed.grep三剑客详解

    事前准备1.主机node1:172.16.133.112.作为实验的文件/etc/passwd /etc/fstab qinqin cp /etc/passwd . cp /etc/fstab . 一 ...

  6. PHP压缩上传图片

    最近手上的项目页面要显示很多图片,虽然用了jQuery的lazyload,但是效果并没理想,滑动到一个区域还要比较长的时间图片才完全显示出来.于是想着将上传上去的900KB+压缩备份一份缩略图. PH ...

  7. Java -- 数字

    @.运用BigDecimal处理Double类型的算术运算的精度问题 原文:https://blog.csdn.net/j754379117/article/details/52238396 可使用 ...

  8. 如何玩转最新的项目的搭配springmvc+mybatis+Redis+Nginx+tomcat+mysql

    上一次完成nginx+tomcat组合搭配,今天我们就说说,这几个软件在项目中充当的角色: 要想完成这几个软件的组合,我们必须知道和熟悉应用这个框架, 一: Nginx:在项目中大多数作为反向代理服务 ...

  9. ListView中加载大量的图片

    情况是这样的:我需要把大约四五十个车标在一个listView中展示出来,一般在用ListView的时候撑死十来个图标,按不同分类使用,这倒好办,在创建view的时候使用R.drawable.xxx指定 ...

  10. shell脚本57问

    [1]交互方式.非交互方式.Shell脚本是什么? 经常与linux打交道,肯定对shell这个词不陌生.不明白shell意思的,可以自行翻译:外壳.去壳. 这个翻译结果怎么可以与计算机系统联系起来呢 ...