基于 curses 的贪吃蛇项目

使用 ncurses 制作的贪吃蛇项目

关于 curses

curses的名字起源于"cursor optimization",即光标优化。是一个在Linux/Unix下广泛应用的图形函数库,作用是可以在终端内绘制简单的图形用户界面。 
下载安装方式在CSDN 上有许多大佬写过,就不在此赘述。

 下面是百度百科关于 curses 的用法:
  1. 包含头文件:curses.h 
  2. 编译时应加上链接语句-lcurses,如:gcc temp.c -o temp -lcurses 
  3. 重要的函数: 函数 功能
	 ***本程序中所调用的函数
	 initscr()	初始化curses库和ttty(在开始curses编程之前,必须使用initscr()这个函数来开启curses模式)
	 endwin()	关闭curses并重置tty(结束curses编程时,最后调用的一个函数)
     move(y,x)	将游标移动至 x,y 的位置
     printw(format,str)	curses中的 printf() ,以一定的格式输出至萤幕
     getch()	从键盘读取一个字元。(注意!传回的是整数值)
     refresh()	使屏幕按照你的意图显示。比较工作屏幕和真实屏幕的差异,然后refresh通过终端驱动送出那些能使真实屏幕于工作屏幕一致的字符和控制码。(工作屏幕就像磁盘缓存,curses中的大部分的函数都只对它进行修改)
     keypad()函数 这个函数允许使用功能键,例如:F1、F2、方向键等功能键。几乎所有的交互式程序都需要使用功能键,因为绝大多数用户界面主要用方向键进行操作。使用keypad(stdscr,TURE)就为“标准屏幕”(stdscr)激活了功能键。
     *** 
 	 getyx(win,y,x)	得到目前游标的位置(请注意!是 y,x 而不是&y,&x)
     clear() and erase()	将整个萤幕清除(请注意配合refresh() 使用)
     echochar(ch)	显示某个字元
 	 addch(ch)	在当前位置画字符ch
     mvaddch(y,x,ch)	在(x,y) 上显示某个字元。相当于 move(y,x);addch(ch);
	 addstr(str)	在当前位置画字符串str
     mvaddstr(y,x,str)	在(x,y) 上显示一串字串。相当于 move(y,x);addstr(str);
     mvprintw(y,x,format,str)	在(x,y) 位置上做 printw 的工作。相当於呼叫	  move(y,x);printw(format,str);
     getstr()	从键盘读取一串字元。
     scanw(format,&arg1,&arg2...)	如同 scanf,从键盘读取一串字元。
     beep()	发出一声哔声
     box(win,ch1,ch2)	自动画方框
     standout()	启动standout模式(一般使屏幕发色)
     standend()	关闭standout模式

好了,基于此,我们来写基于 curses 的贪吃蛇游戏。

若要进一步了解curses的初始化 可查看:curses 的具体的初始化

主函数

int main(){
	initscr();                // 进入 curses
	keypad(stdscr,1);         // 玩成 curses 的初始化
	ground();				//	 运行函数,打印地图	  
	getch();          		//   为防止在测试时,程序运行完毕后直接结束了,所以添加这个
	endwin();
	return 0;
}

贪吃蛇首先要有一个地图:

地图函数

封装函数, 我不想让贪吃蛇的地图定死所以添加全局变量;
关于地图的构思,用 | 和 - 来构成地图的边框,显然 - 比 | 短,所以我们用两个 – 。

#include <curses.h>               // 注意头文件
#define s_x 15
#define s_y 15
void ground();
{
	int i=0;
	int hang,lie;
	for(hang =0; hang <=s_y; hang++){
			if(hang == 0 || hang == s_y){
				for(i=0; i < s_x; i++){       // 这里少打印一个,因为是以两个 -- 作一行,以一个 | 可以自己去试一试
					printw("--");         	  // 打印15个 -- 
				}
				printw("\n");
				continue;
			}
			for(lie=0; lie <= s_x; lie++){
		 		if(lie == 0 || lie == s_x ){
					printw("|");
				}
				else{
					printw("  ");   // 注意这里是两个空格
				}
			}
		printw("\n");					// 那么何时换行呢,显然hang+1就换行
	}    // 至此,地图绘制完毕,但是我偏要加自己的署名 哈哈哈
printw(" by Wang Tian Xiao\n");    // 作者此处打成中文会出现乱码,原因未知
}

至此地图绘制完毕,效果如下:
在这里插入图片描述
下一步添加蛇身

创立蛇身

创立蛇身,也就是在地图上进行刷新,所以引入 snake 的结构体,产生蛇身的坐标;

struct snake
{	
	int hang;
	int lie;	
	struct snake * next;
};
struct snake * head = NULL;     // 创立一个链表头,链表尾,作为蛇身的头和尾
struct sanke * tail = NULL;		// 由于后面其他的子涵数,如移动蛇身等也会用到,故将其定义为全局变量
void addnode()				  // 这是一个子函数,由于声明的原因,必须放置于 initsnake 之前,请先阅读 initsnake();
{
		struct snake * new  = (struct snake *)malloc(sizeof(struct snake));
		new->next = NULL;
		// 这里我们要考虑一个问题,就是当添加蛇身的时候,是将其坐标添加到那个方向? 在之后的 移动蛇身代码中,显然会有这个问题,但在此处,我们暂且搁置
		new->hang = tail->hang;
		new->lie = tail->lie+1;
		tail->next = new;
		tail = new;
}
void initsnake()
{
	struct snake * p;
	head = (struct snake*)malloc(sizeof(struct snake));
	head->hang = 1;
	head->lie = 1;
	head->next = NULL;
	tail = head;              // 我们在这里写一个子函数,用于添加蛇的身体,同样的 
	addnode();				// 显然,此处的子函数 addnode() 应当写在 initsnake() 之前
	addnode();
	addnode();				
}

至此我们已有了蛇的身体坐标,下一步就是打印蛇的身体坐标,很明显,地图代码要发生改变,直接粘贴复制:

void ground();
{
	int i=0;
	int hang,lie;
	for(hang =0; hang <=s_y; hang++){
			if(hang == 0 || hang == s_y){
				for(i=0; i < s_x; i++){       // 这里少打印一个,因为是以两个 -- 作一行,以一个 | 可以自己去试一试
					printw("--");         	  // 打印15个 -- 
				}
				printw("\n");
				continue;
			}
			for(lie=0; lie <= s_x; lie++){
		 		if(lie == 0 || lie == s_x ){
					printw("|");
				}
				//	显然,如果要打印代码,一定会是在 空格区 中
				// 写起来有点小麻烦呐,这样吧,我们做一个函数来判断这个节点是不是蛇身;
				else if ( snakenode(hang,lie) == 1){
					printw("[]");
					}
				else{
					printw("  ");   // 注意这里是两个空格
				}
			}
		printw("\n");					// 那么何时换行呢,显然hang+1就换行
	}    // 至此,地图绘制完毕,但是我偏要加自己的署名 哈哈哈
  printw(" by Wang Tian Xiao\n");    // 作者此处打成中文会出现乱码,原因未知
}
int snakenode(int x,int y)
{
	struct snake * p;     	// 引入新的指针 p 用P 来进行遍历,防止影响到 head;
	p = head;
	while( p!= NULL){
		if(p->hang == x && p->lie == y){
			return 1;
		}
		p = p->next;
	}
	return 0;
}

显然,主函数也要发生变化

int main()
{
	initscr();
	keypad(stdscr,1);
	initsnake();
	
	ground();	
	while(1);  // 防止程序退出
	endwin();
	
	return 0;
}

#include <curses.h>
#include <stdlib.h>
#define s_x 30
#define s_y 30

void initNcurses(){
initscr();
}

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

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

void addnode()
{
struct snake * new = (struct snake * )malloc(sizeof(struct snake));
new->hang = tail->hang;
new->lie = tail->lie+1;
new->next = NULL;

tail->next = new;
tail = new;

}

void initsnake()
{
struct snake * p;
while(head != NULL){
p = head;
free§;
head = head->next;
}
head = (struct snake *)malloc(sizeof(struct snake));
head->hang = 1;
head->lie = 1;
head->next = NULL;

tail = head;
addnode();
addnode();
addnode();
addnode();

}

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

void ground()
{
move(0,0);

int hang;
int lie;
int i=0;
for(hang = 0;hang <= s_x; hang ++){
	if(hang == 0 || hang == s_x ){
		for(i=0;i< s_y ;i++)
		printw("--");
		printw("\n");
		continue;
	}
	
	for(lie = 0;lie<= s_y ; lie++){
		if(lie == 0 || lie == s_y ){
		  printw("|");	
		}
		else if (snakenode(hang,lie) == 1){
			printw("[]");
		}
		else{
			printw("  ");		
		}
	}
	
printw("\n");
}
for(i=0; i<= s_x; i++) printw(" ");
printw("------ BY Wang Tian Xiao\n");

}

void subnode()
{
// struct sanke * p;
// p = head;
head= head -> next;
// free§;
}

void movesnake()
{
addnode();
subnode();

if(tail->lie == s_x || tail->hang == s_y || tail->lie == 0 || tail->hang == 0)
{
	initsnake();	
}

}

int main()
{
initscr();

initsnake();

ground();

int key;

keypad(stdscr,1);

while(1){
	key = getch();
	if(key == KEY_RIGHT){
		movesnake();
		ground();
	}
	else if(key == KEY_LEFT){

	}
	else if(key == KEY_UP){

	}
	else if(key == KEY_DOWN){
		
	}	
}



getch();
endwin();

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值