我写的贪吃蛇,请大家多多支持

AAA20090987 2010-10-01 01:39:33
加精
//mysnake1.0.c
//编译命令:cc mysnake1.0.c -lcurses -o mysnake1.0
//用方向键控制蛇的方向
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <signal.h>
#include <sys/time.h>
#define NUM 60

struct direct //用来表示方向的
{
int cx;
int cy;
};
typedef struct node //链表的结点
{
int cx;
int cy;
struct node *back;
struct node *next;
}node;

void initGame(); //初始化游戏
int setTicker(int); //设置计时器
void show(); //显示整个画面
void showInformation(); //显示游戏信息(前两行)
void showSnake(); //显示蛇的身体
void getOrder(); //从键盘中获取命令
void over(int i); //完成游戏结束后的提示信息

void creatLink(); //(带头尾结点)双向链表以及它的操作
void insertNode(int x, int y);
void deleteNode();
void deleteLink();

int ch; //输入的命令
int hour, minute, second; //时分秒
int length, tTime, level; //(蛇的)长度,计时器,(游戏)等级
struct direct dir, food; //蛇的前进方向,食物的位置
node *head, *tail; //链表的头尾结点

int main()
{
initscr();
initGame();
signal(SIGALRM, show);
getOrder();
endwin();
return 0;
}

void initGame()
{
cbreak(); //把终端的CBREAK模式打开
noecho(); //关闭回显
curs_set(0); //把光标置为不可见
keypad(stdscr, true); //使用用户终端的键盘上的小键盘
srand(time(0)); //设置随机数种子
//初始化各项数据
hour = minute = second = tTime = 0;
length = 1;
dir.cx = 1;
dir.cy = 0;
ch = 'A';
food.cx = rand() % COLS;
food.cy = rand() % (LINES-2) + 2;
creatLink();
setTicker(20);
}

//设置计时器(这个函数是书本上的例子,有改动)
int setTicker(int n_msecs)
{
struct itimerval new_timeset;
long n_sec, n_usecs;

n_sec = n_msecs / 1000 ;
n_usecs = ( n_msecs % 1000 ) * 1000L ;
new_timeset.it_interval.tv_sec = n_sec; /* set reload */
new_timeset.it_interval.tv_usec = n_usecs; /* new ticker value */
n_msecs = 1;
n_sec = n_msecs / 1000 ;
n_usecs = ( n_msecs % 1000 ) * 1000L ;
new_timeset.it_value.tv_sec = n_sec ; /* store this */
new_timeset.it_value.tv_usec = n_usecs ; /* and this */
return setitimer(ITIMER_REAL, &new_timeset, NULL);
}

void showInformation()
{
tTime++;
if(tTime >= 1000000) //
tTime = 0;
if(1 != tTime % 50)
return;
move(0, 3);
//显示时间
printw("time: %d:%d:%d %c", hour, minute, second);
second++;
if(second > NUM)
{
second = 0;
minute++;
}
if(minute > NUM)
{
minute = 0;
hour++;
}
//显示长度,等级
move(1, 0);
int i;
for(i=0;i<COLS;i++)
addstr("-");
move(0, COLS/2-5);
printw("length: %d", length);
move(0, COLS-10);
level = length / 3 + 1;
printw("level: %d", level);
}

//蛇的表示是用一个带头尾结点的双向链表来表示的,
//蛇的每一次前进,都是在链表的头部增加一个节点,在尾部删除一个节点
//如果蛇吃了一个食物,那就不用删除节点了
void showSnake()
{
if(1 != tTime % (30-level))
return;
//判断蛇的长度有没有改变
bool lenChange = false;
//显示食物
move(food.cy, food.cx);
printw("@");
//如果蛇碰到墙,则游戏结束
if((COLS-1==head->next->cx && 1==dir.cx)
|| (0==head->next->cx && -1==dir.cx)
|| (LINES-1==head->next->cy && 1==dir.cy)
|| (2==head->next->cy && -1==dir.cy))
{
over(1);
return;
}
//如果蛇头砬到自己的身体,则游戏结束
if('*' == mvinch(head->next->cy+dir.cy, head->next->cx+dir.cx) )
{
over(2);
return;
}
insertNode(head->next->cx+dir.cx, head->next->cy+dir.cy);
//蛇吃了一个“食物”
if(head->next->cx==food.cx && head->next->cy==food.cy)
{
lenChange = true;
length++;
//恭喜你,通关了
if(length >= 50)
{
over(3);
return;
}
//重新设置食物的位置
food.cx = rand() % COLS;
food.cy = rand() % (LINES-2) + 2;
}
if(!lenChange)
{
move(tail->back->cy, tail->back->cx);
printw(" ");
deleteNode();
}
move(head->next->cy, head->next->cx);
printw("*");
}

void show()
{
signal(SIGALRM, show); //设置中断信号
showInformation();
showSnake();
refresh(); //刷新真实屏幕
}

void getOrder()
{
//建立一个死循环,来读取来自键盘的命令
while(1)
{
ch = getch();
if(KEY_LEFT == ch)
{
dir.cx = -1;
dir.cy = 0;
}
else if(KEY_UP == ch)
{
dir.cx = 0;
dir.cy = -1;
}
else if(KEY_RIGHT == ch)
{
dir.cx = 1;
dir.cy = 0;
}
else if(KEY_DOWN == ch)
{
dir.cx = 0;
dir.cy = 1;
}
setTicker(20);
}
}

void over(int i)
{
//显示结束原因
move(0, 0);
int j;
for(j=0;j<COLS;j++)
addstr(" ");
move(0, 2);
if(1 == i)
addstr("Crash the wall. Game over");
else if(2 == i)
addstr("Crash itself. Game over");
else if(3 == i)
addstr("Mission Complete");
setTicker(0); //关闭计时器
deleteLink(); //释放链表的空间
}

//创建一个双向链表
void creatLink()
{
node *temp = (node *)malloc( sizeof(node) );
head = (node *)malloc( sizeof(node) );
tail = (node *)malloc( sizeof(node) );
temp->cx = 5;
temp->cy = 10;
head->back = tail->next = NULL;
head->next = temp;
temp->next = tail;
tail->back = temp;
temp->back = head;
}

//在链表的头部(非头结点)插入一个结点
void insertNode(int x, int y)
{
node *temp = (node *)malloc( sizeof(node) );
temp->cx = x;
temp->cy = y;
temp->next = head->next;
head->next = temp;
temp->back = head;
temp->next->back = temp;
}

//删除链表的(非尾结点的)最后一个结点
void deleteNode()
{
node *temp = tail->back;
node *bTemp = temp->back;
bTemp->next = tail;
tail->back = bTemp;
temp->next = temp->back = NULL;
free(temp);
temp = NULL;
}

//删除整个链表
void deleteLink()
{
while(head->next != tail)
deleteNode();
head->next = tail->back = NULL;
free(head);
free(tail);
}


学LINUX差不多一个月了,就写一个curses版的贪吃蛇来练习一下吧,同时谢谢CSDN上的朋友对我的帮助
这个程序不难,但也算是我的一个作品吧,呵呵

如果你觉得这个程序写得好,就支持一下,如果觉得不好,就提点改进意见吧。
我也是初学者,大家共同学习,共同进步,呵呵

说一下这个程序的不足之吧(自我感觉)
1:数据封装做得不好,大量使用全局变量,存在安全隐患。(以前用C++用得多了,用回C语言反而不习惯了)
2:这个游戏没有存档功能。(因为我不知该怎样实现)
3:蛇上下行走与左右行走的速度不同。
4:没有使用多线程,多线程技术我现在用得还不是很熟练,如果有机会做2.0版本的话,我会加上多线程机制的。

如果大家发现了这个程序的BUG的话,请和我说一声,我会尽力改正的,
也欢迎大家多提意见,还是那句话,大家共同学习,共同进步。

最后,祝大家国庆节快乐!!
...全文
10291 382 打赏 收藏 转发到动态 举报
写回复
用AI写文章
382 条回复
切换为时间正序
请发表友善的回复…
发表回复
u011143919 2013-06-26
  • 打赏
  • 举报
回复
引用 107 楼 gao453068615yan 的回复:
有个提议,将每次的行位移设置为2,就能保证上下/左右的移动速度一致了~~不过为保证游戏不出错还得改点参数: 首先,void getOrder()里的 if(KEY_LEFT == ch) { dir.cx = -1; dir.cy = 0; } else if(KEY_RIGHE == ch) { dir.cx = 1; dir.cy = 0; } 改为: if(KEY_LEFT == ch) { dir.cx = -2; dir.cy = 0; } else if(KEY_RIGHE == ch) { dir.cx = 2; dir.cy = 0; } 然后,void intiGame()里 dir.cx = 1; 改为 dir.cx = 2; food.cx = rand() % COLS; 改为: food.cx = (rand() % COLS)/2*2; void showSnake()里也有上面这一句,也要改; void creatLink()里面的 temp->cx = 5; 改为: temp->cx = 6;(偶数就行) 这样改完看起来上下左右速度就一样拉~~ 一点个人想法,仅供参考~呵呵
这样修改结果是,在左右撞墙时不会死掉,时间在走,蛇出现BUG
u011143919 2013-06-24
  • 打赏
  • 举报
回复
food.cx = rand() % COLS; food.cy = rand() % (LINES-2) + 2; 中的 COLS和LINES来自何方?求详解,速回。谢了
chshfei 2012-11-26
  • 打赏
  • 举报
回复
lz真心强大啊,才学linux一个月就可以独立编写一个小软件了 想请问下楼主,之前应该有C的基础,有几年C的编程经验吧?
fzamygsd 2012-11-25
  • 打赏
  • 举报
回复
AAA20090987 2012-11-01
  • 打赏
  • 举报
回复
[Quote=引用 418 楼 的回复:]

这位大师:问一个我不理解的地方
void show()
{
signal(SIGALRM, show); //设置中断信号
showInformation();
showSnake();
refresh(); //刷新真实屏幕
}

其中的 signal(SIGALRM, show); 不理……
[/Quote]

你的理解没错,的确是个死循环
游戏嘛,肯定得来个死循环,
否则程序一闪而过,那还玩个毛啊,呵呵。
Tom_殇子 2012-11-01
  • 打赏
  • 举报
回复
不错…… 有时间学习一下…… 可以玩玩……
jdwq33 2012-10-17
  • 打赏
  • 举报
回复
这位大师:问一个我不理解的地方
void show()
{
signal(SIGALRM, show); //设置中断信号
showInformation();
showSnake();
refresh(); //刷新真实屏幕
}

其中的 signal(SIGALRM, show); 不理解 为什么它要自己嵌套自己 那不是永远嵌套了啊
我不知道这个问题问得是不是很小白 但是真的不理解啊 要命啊
麻烦大师指点
adrogy 2012-09-22
  • 打赏
  • 举报
回复
挺不错的,很有条理,学习了
落枫 2011-09-17
  • 打赏
  • 举报
回复
Linux学习之路还很漫长阿,谢谢楼主无私的分享
yyyjsyz 2011-09-17
  • 打赏
  • 举报
回复
我也是初学者,看着有点难。顶下lz
menghuandpa1 2011-08-27
  • 打赏
  • 举报
回复
不错 学习中
mrhellhell 2011-06-22
  • 打赏
  • 举报
回复
难道是笔记本的方向键不能用?
leighjian 2011-05-29
  • 打赏
  • 举报
回复
mark````
astrotycoon 2011-04-25
  • 打赏
  • 举报
回复
正在看《umix/linux编程实践教程》
leotody 2011-03-11
  • 打赏
  • 举报
回复
太牛B了,linux写贪吃蛇应该比Windows要难很多吧?
有个小小建议,在贪吃蛇改变方向的时候有4个方向可以选择,而且反向的话会当作碰到自己的身体来处理。貌似可以优化一下。
gfenghappy 2011-02-25
  • 打赏
  • 举报
回复
真是强大啊!
dark_ice_rain 2011-01-29
  • 打赏
  • 举报
回复
感觉好多地方看不懂呢~
数据结构有课的,还没有开始呢~
dtthwl 2010-12-29
  • 打赏
  • 举报
回复
写得很好
秦剑 2010-12-26
  • 打赏
  • 举报
回复
人才,向你学习。
小小小鸟2 2010-11-22
  • 打赏
  • 举报
回复
写的真不错,很正宗。。
加载更多回复(362)

23,125

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧