声明: 以下内容可能会引起某些读者不适, 请小心阅读. 有些内容并没有详细介绍, 可能简单理解也是错误的, 但是这都是为了尽量简单。
前言: 代码是很久之前写的,属于边想边写的那种,很混乱。
推荐材料:
贪吃蛇应该是我们这代人都玩过的游戏。而如果我们要写一个贪吃蛇最需要考虑的就是贪吃蛇是如何移动的。其实贪吃蛇的移动就是尾部的减少和头部的增加。
这篇文章:
- 介绍一些ncurses库的基础内容
- 贪吃蛇游戏的代码解释
介绍一些ncurses库的基础内容
ncurses
curses是一个在命令行下面的图形函数库,而ncurses的意思是 new curses。
ncurses的一些函数的简单解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <ncurses.h> int main() { int ch; initscr(); /* Start curses mode */ raw(); /* Line buffering disabled */ keypad(stdscr, TRUE); /* We get F1, F2 etc.. */ noecho(); /* Don‘t echo() while we do getch */ printw("Type any character to see it in bold\n"); ch = getch(); /* If raw() hadn‘t been called * we have to press enter before it * gets to the program */ if(ch == KEY_F(1)) /* Without keypad enabled this will */ printw("F1 Key pressed");/* not get to us either */ /* Without noecho() some ugly escape * charachters might have been printed * on screen */ else { printw("The pressed key is "); attron(A_BOLD); printw("%c", ch); attroff(A_BOLD); } refresh(); /* Print it on to the real screen */ getch(); /* Wait for user input */ endwin(); /* End curses mode */ return 0; } |
这是我从这里拿到的一个例子。
我们应该注意到这个程序并没有导入标准输入输出库,而是导入了ncurses.h文件。在这个程序里面也没有使用printf(format printing),而是使用了printw这个函数(print window)就是打印到标准屏幕的意思
- initscr:初始化屏幕,启动curses模式
- raw:关闭行缓冲,一般的我们在命令行中输入数据的时候,只有当我们按下回车之后,才可以把数据提交给程序
- noecho: 负责按键事务,我不太懂
- noecho: 关闭回显(按下一个字符之后,屏幕并不显示。比如说在普通的情况下按下a,a会被显示在屏幕上)
- getch: 获取一个字符
- attron: 在后面的打印中增加打印属性,这里是粗体的意思
- attroff: 移除属性
- refresh:之前的printw只是打印到逻辑屏幕,而refresh函数会依据逻辑屏幕的内容,刷新到物理屏幕。
- endwin:退出curses模式
其他的可以自己慢慢去学习
ncurses库的安装和使用
安装
如果你是使用debian系列的linux发行版,例如ubuntu,应该直接键入命令:
1 |
sudo apt-get install libncurses5-dev |
就可以了。
如果是别的系列的版本,建议下载源码包,编译安装。或者百度搜索正确的答案。
使用
一般的,只需要在gcc编译命令的后面加上-lncurses就可以正确导入ncurses库了。
1 |
gcc -o demo demo.c -std=c99 -lncurses |
-std=c99的意思是使用c99的标准来编译代码。
没有使用过命令行编译操作的同学需要自己去学习。
贪吃蛇的代码解释
从哪里得到
点击这里。这份代码是我写的,也确实写的不好。但也可以随便看看。
代码结构
1 2 3 4 5 6 7 |
|-- hungry_snake // 可执行文件, |-- main.c |-- snake.c |-- snake.h `-- wellcome.h 0 directories, 5 files |
hungry_snake是一个可执行文件,在debian下编译的,在centos下面可能需要重新编译。
main.c是程序的主要逻辑部分。
wellcome.h包含了欢迎界面的代码实现。
snake.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
/* * snake.h */ #ifndef SNAKE_H #define SNAKE_H #include <ncurses.h> // 这个枚举类型我其实没有用 typedef enum state { goleft, goright, goup, godown }state; // 这个是蛇的一节,也就是一个坐标 typedef struct body { int y; int x; struct body *prev; struct body *next; }Body ,*Pbody; // 这个是蛇的结构定义,有一个虚蛇头,蛇头和蛇尾,还有蛇的长度啊,运动状态啊 typedef struct snake { Pbody vir_head; Pbody head; Pbody tail; int length; state movement; // 我没有用 char uping; char downing; char lefting; char righting; }Snake, *Psnake; int FOOD[1000][1000]; // 食物坐标,标记哪个位置有食物 int food_num; // 食物数量 /* ** body part */ Pbody init_body(); // 初始化蛇身 void add_body(Pbody jack, Pbody bd); // 增加一节 Pbody bd(int lines,int cols); // 构造一个蛇节 void print_snake(Pbody jack); // 显示那条蛇 void print_bd(Pbody bd); // 显示蛇节 Pbody get_head(Pbody jack); // 得到蛇头部节点 Pbody add_head(Pbody oldhead,Pbody newhead); // 增加节点到头部 Pbody del_tail(Pbody jack); // 删除蛇尾 Pbody get_tail(Pbody jack); // 得到蛇尾节点指针 /* ** snake part */ Psnake init_snake(); //初始化蛇 int snake_go_right(Psnake snake); // 蛇的移动 int snake_go_left(Psnake jack); void show_snake(Psnake jack); // 屏幕上显示蛇 void init_show_snake(Psnake jack); // 忘了 int snake_go_down(Psnake jack); // 蛇的移动 int snake_go_up(Psnake jack); int snake_can_move(Psnake jack, char ch); // 判断蛇能否往目标方向移动 int body_in_snake(int row, int col, Psnake jack); // 判断蛇身是否覆盖坐标 /* food part */ void putfood(Psnake jack); // 随机投放食物 int count_food(); // 食物技术 /* game_over */ void game_over(Psnake jack); // 游戏结束 #endif // SNAKE_H |
这里有一些结构定义和函数声明。
main.c
下面是程序主体逻辑部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
#include <unistd.h> #include <stdlib.h> #include "snake.h" #include <ncurses.h> #include "wellcome.h" #include <pthread.h> int ch; int GAMEOVER; /* void get_command(void *i) { ch = getch(); } */ int main() { initscr(); start_color(); keypad(stdscr,TRUE); curs_set(0); noecho(); halfdelay(4); init_pair(1,COLOR_WHITE,COLOR_BLACK); init_pair(2,COLOR_BLACK,COLOR_WHITE); print_snake_logo(stdscr); mvprintw(LINES-1,COLS-20,"Producted by Jack"); mvprintw(LINES-4,(COLS-21)/2,"|-> START"); printw(" (? for help)"); refresh(); int choice; char goout = 0; while (!goout){ switch (choice = getch() ){ case ‘q‘: endwin(); return 0; case ‘e‘: goout = 1; break; } } /* pthread_t id; pthread_create(&id,NULL,get_command,NULL); */ Psnake jack = init_snake(); init_show_snake(jack); ch = mvgetch(LINES-1,0); srand((unsigned)time(0)); for (int i = 0; i<10; i++) putfood(jack); refresh(); int noout = 1; int c = 0; while(noout){ ch = getch(); switch (ch){ case KEY_RIGHT: c = snake_go_right(jack); if ( c == -1){ noout = 0; GAMEOVER = 1; break; } continue; case KEY_DOWN : c = snake_go_down(jack); if ( c == -1){ noout = 0; GAMEOVER = 1; break; } continue; case KEY_LEFT: c = snake_go_left(jack); if ( c == -1){ noout = 0; GAMEOVER = 1; break; } continue; case KEY_UP: c = snake_go_up(jack); if ( c == -1){ noout = 0; GAMEOVER = 1; break; } continue; case ‘q‘: game_over(jack); endwin(); return 0; } if (jack->righting){ c = snake_go_right(jack); if (c == -1){ GAMEOVER = 1; break; } } else if (jack->lefting){ c = snake_go_left(jack); if (c == -1){ GAMEOVER = 1; break; } } else if(jack->uping){ c = snake_go_up(jack); if (c == -1){ GAMEOVER = 1; break; } } else if(jack->downing){ c = snake_go_down(jack); if (c == -1){ GAMEOVER = 1; break; } } if (food_num < 30) putfood(jack); mvprintw(LINES-1,2,"-- socre %d --",jack->length); refresh(); } if(GAMEOVER) game_over(jack); refresh(); endwin(); return 0; } |
编译
1 |
gcc -o snake.out snake.h snake.c main.c wellcome.h -lncurses -std=c99 |
小结
这份代码写的太差劲,所以我也没有也不想过多的去说它。
原文地址:https://www.cnblogs.com/litran/p/10541110.html