一、Ncurses简介
curses是一个在命令行下面的图形函数库,而ncurses的意思是 new curses。
当对使用curses函数库的程序进行编译时,你必须在程序中包含头文件curses.h,并在编译命令行中用-lcurses选项来链接curses函数库。
Ncurses相关函数简介
initscr();//ncurse界面的初始化函数,打开curses模式 进入终端
endwin();//程序退出,关闭窗口stdscr。
printw("This is a curses window.\n");//在ncurse模式下的printf,如果没有这句话,程序就退出了
//看不到运行的结果,也就是看不到上面那句话
getch(); //用于获取用户的键盘输入。它将等待用户按下一个键,并返回该键的ASCII码值。
//以下是一个示例:
int dir;
dir = getch();//可以使用getch();来实现交互,等待用户按下任意键后继续执行程序,
//例如本文的按下方向键改变贪吃蛇移动方向。
keypad(stdscr,1);//这个函数允许使用功能键,例如:F1、F2、方向键等功能键。几乎所有的交互式程
//序都需要使用功能键,因为绝大多数用户界面主要用方向键进行操作。
//使用keypad(stdscr,TURE)就为“标准屏幕”(stdscr)激活了功能键。
move();//移动光标的函数,move函数用来将逻辑光标的位置移到指定地点,
//屏幕坐标以左上角(0,0)为起点。
//在贪吃蛇移动时,我们希望地图刷新的位置不变,需要设置光标位置不变
refresh();//刷新屏幕,在绘制或修改界面后,需要使用refresh();函数来刷新终端屏幕,
//以便用户可以看到更新后的内容。
echo();//设置回显模式,当echo模式设置后,它使得在键盘上输入的每一个字符都在终端屏幕上
//当前光标处显示出来,默认是回显模式
noecho(); //关闭回显模式,非回显模式下按键通常用来控制屏幕的操作而不是用来进行字符输入。
//(按下一个方向键后,屏幕并不显示键值)
这两个函数用来控制是否将从键盘输入的字符显示在终端上。调用noecho()函数禁止输入的字符出现在屏幕
上。也许程序员希望用户在进行控制操作时,需要屏蔽掉控制字符(如组合键操作),或调用getch()函数
读取键盘字符时,不想显示输入的字符(如在控制台输入登陆密码)。大多数的交互式应用程序在初始化
时会调用noecho()函数,用于在进行控制操作时不显示输入的控制字符。这两个函数给予程序员很大的灵活
性,使程序员可以在窗口中的任意地方,实现输入字符的显示和屏蔽,而不需要刷新屏幕。
二、贪吃蛇代码实现
贪吃蛇的游戏逻辑很简单,首先要确定游戏地图的边框,然后考虑贪吃蛇如何移动,移动过程中吃到食物身体变长的同时食物重新刷新,然后碰到地图边界或者自己的身体会死亡,死亡后食物要重新复位初始化,食物是在地图上随机刷新。下面,我就根据这个逻辑将贪吃蛇小游戏分为地图界面、贪吃蛇身体显示、控制贪吃蛇移动和食物刷新四个部分来写。
1、贪吃蛇的地图绘制
-
地图规划:大小20×20
-
地图竖直方向上的边界“|”
-
地图水平方向上的边界”–”
#include <curses.h>//ncurses的头文件
void initNcurses()
{
initscr();//ncurses初始化函数
}
void snakeMap()//贪吃蛇地图界面
{
int row,col;
for(row=0; row<20; row++){
if(row == 0){
for(col=0; col<20; col++){
printw("--");//第一行用--代表上边界
}
printw("\n");
}
if(row>=0 || row<=19){
for(col=0; col<=20; col++){
if(col ==0 || col == 20){
//这里为了对齐上边框用21列
printw("|");//第0列和第21列用|代表边界
}else{
printw(" ");//边框中间都用两个空格代替
}
}
printw("\n");
}
if(row == 19){
for(col=0; col<20; col++){
printw("--");//第20行用--代表下边界
}
printw("\n");
printw("By Zhang\n");//地图打印完后,可以自定义一些显示内容
}
}
}
int main()
{
initNcurses();//ncurses初始化
snakeMap();//地图界面
getch();//按下任意键退出地图界面
endwin();//程序退出函数
return 0;
}
2、贪吃蛇身体显示
贪吃蛇的身子用”[ ]”表示。
贪吃蛇显示身体的关键是身体节点坐标和地图左边产生关系:先创建贪吃蛇的一个节点,然后用链表创建多个连在一起的节点构成贪吃蛇的身体。贪吃蛇身体创建完后用地图扫描身体只要和地图坐标相同就显示相关身体节点。
贪吃蛇的节点:
struct Snake{
//贪吃蛇身子节点
int row;//行坐标
int col;//列坐标
struct Snake *next;//下一个节点的位置(地址/指针)
};
显示贪吃蛇的一个节点:设置一个节点位置,假设头节点行列坐标都是2,第一个节点的头即尾,然后把头节点的值赋给尾巴节点。在地图上扫描这个节点如果有就显示[ ]。
struct Snake *head = NULL;//贪吃蛇的头节点
struct Snake *tail = NULL;//贪吃蛇尾巴节点
head->row = 2;
head->col = 2;
head->next = NULL;
tail = head;
if(head->row == row && head->col == col){
printw("[]");
}
头节点创建完成后增加节点和头节点坐标构成关系就成了一条蛇。
#include <curses.h>
#include <stdlib.h>
struct Snake{
//贪吃蛇身子节点
int row;//行坐标
int col;//列坐标
struct Snake *next;//下一个节点的位置(地址/指针)
};
struct Snake *head = NULL;//为了方便操作定义全局变量贪吃蛇的头节点
struct Snake *tail = NULL;//为了方便操作定义全局变量贪吃蛇的尾巴节点
void initNcurses()
{
initscr();
}
int ifHaveSnake(int row, int col)
{
struct Snake *p;//定义一个变量
p = head; //将头节点位置赋给变量,让变量从头节点开始遍历蛇的身体
while(p != NULL){
if(p->row == row && p->col == col){
return 1;//地图扫描蛇身,如果和地图坐标相同就返回1让地图显示蛇身
}
p = p->next;
}
return 0;
}
void addSnakeNode()
{
struct Snake *new = (struct Snake*)malloc(