赞
踩
目录
5.4 使用线程解决贪吃蛇方向移动和刷新界面一起实现面临的问题:
项目运行环境:Linux,基于Ncurse图形库的C语言小游戏
项目的目的和意义:起到承上启下的作用,对于前面学的C语言的基础和数据结构链表做一个比较好的巩固,对于后面的Linux系统编程的开发做铺垫
项目基础要求:C语言基础、Linux基本操作
- /*项目步骤*/
- (1)选择ncurses库的原因
- 在进行贪吃蛇游戏时,贪吃蛇的行进方向需要你按下上下左右键进行操控,如果使用C语言自带的函数,例如:scanf或者getchar之类的,需要你按下回车键,程序才能进行响应,而这显然是十分不方便的,但是ncurses库就很好的解决了这个问题。ncurses库自带的函数getch就能实现迅速便捷的贪吃蛇方向响应。
-
- (2)ncurses库的基本入门
- 对于该项目而言,ncurses库我们不需要进行过于深入的学习,只需要知道一些基本的函数使用即可。下列程序中的函数,就是一个基于ncurses库的基本代码框架。
- #include <curses.h>
-
- int main()
- {
- initscr();//ncurse界面的初始化函数
- printw("this is a curses window\n");//在ncurse模式下的printf
- getch();//等待用户的输入,如果没有这句话,程序就退出了,看不到运行的结果,也就是无法看到上面那句话
- endwin();//程序退出,恢复shell终端的显示,如果没有这句话,shell终端字乱码,坏掉
-
- return 0;
- }
-
- (3)贪吃蛇地图的整体规划
- 整个贪吃蛇地图的大小将它设置成一个20*20的近似正方形,使用"|"来表示左右边框,使用"--"来表示上下边框。
-
- (4)实现贪吃蛇第一个节点的显示
-
- (5)显示贪吃蛇的完整身子
- 注意,在这里,我们设置两个全局变量,struct Snake *head和struct Snake *tail,一个指向贪吃蛇的头,一个指向贪吃蛇的尾。在将第一个节点打印完后,将尾指向头,即:head = tail。每一次节点的添加,我们调用一个单独的函数去执行,并其使用尾插法实现。
-
- (6)实现贪吃蛇的右移
- 贪吃蛇的移动,整体来说就是链表节点的删除与添加。我们首先实现贪吃蛇的右移,每当按键按下时,贪吃蛇右移一格,即左侧的头结点删除head = head->next,右侧再次添加一个新的节点。新节点的坐标应该是行不变,列加一。注意:不要忘记清楚垃圾节点。
-
- (7)实现贪吃蛇的撞墙死亡
- 将贪吃蛇的尾节点坐标进行判断,判断其是否达到边界坐标。满足条件时,将贪吃蛇重新初始化。注意:不要忘记清楚垃圾节点。
-
- (8)实现贪吃蛇的自由行走
- 在这里,我们发现了一个问题,地图需要实时刷新进行贪吃蛇位置的变更,这是一个while(1)的死循环,而获取键值也是一个实时读取的操作,因此也是一个while(1)死循环,代码执行逻辑上出现了问题,所以我们引入了线程的概念。
-
- (9)了解什么是线程
-
- (10)用线程解决上述问题,实现贪吃蛇的分骚走位
- 开辟两个线程,一个用来执行地图刷新操作,一个用来获取键值。
- pthread_create(&t1,NULL,refreshScreen,NULL);
- pthread_create(&t2,NULL,changeDir,NULL);
-
- (11)解决贪吃蛇的不合理走位
- 在这里,我们使用绝对值法来解决问题,abs函数的作用便是取绝对值,我们将上下左右键,两两对应,宏定义为1,-1,2,-2之类的数就能成功解决问题。
-
- (12)实现贪吃蛇食物的打印
-
- (13)实现食物的随机出现
- 取随机数,C语言有一个自带的函数可以解决这个问题,rand()函数可以实现随机取数,我们只要再对它进行取余操作,便可以防止食物出现在地图以外的位置。
-
- (14)实现贪吃蛇咬到自己结束游戏,重新开始的操作
- 当贪吃蛇的尾节点与自身除尾巴节点以外的其他节点进行比较后,若行列数相同,则初始化整个贪吃蛇,注意:不要忘记垃圾节点的清除(我们可以在每次贪吃蛇初始化之前进行这个操作)。

因为的按键响应牛逼哄哄
ncurse用的最多的地方是在Linux内核编译之前的内核配置
- 1 #include <curses.h>
- 2
- 3 int main()
- 4 {
- 5 char c;
- 6
- 7 initscr();
- 8 c = getch();
- 9 printw("you Input :%c\n",c);
- 10 getch();
- 11 endwin();
- 12 return 0;
- 13 }
使用ncurse的好处是:按下一个按键不需要按下回车,直接就可以输出c的值,和我们C语言的其他输入函数好用
vi /usr/include/curses.h //查看宏定义.h文件的指令
:q //退出查看
- 1 #include <curses.h>
- 2
- 3 int main()
- 4 {
- 5 int key;
- 6
- 7 initscr();
- 8 keypad(stdscr,1); //这个函数允许使用功能键,例如:F1、F2、方向键等功能键。几乎所有的交互式程序都需要使用功能 键,因为绝大多数用户界面主要用方向键进行操作。使用keypad(stdscr,TURE)就为“标准屏幕”(stdscr)激活了功能键。
- 9
- 10 while(1){
- 11 key = getch();
- 12 switch(key){
- 13 case KEY_DOWN:
- 14 printw("DOWN\n");
- 15 break;
- 16 case KEY_UP:
- 17 printw("up\n");
- 18 break;
- 19 case KEY_LEFT:
- 20 printw("LEFT\n");
- 21 break;
- 22 case KEY_RIGHT:
- 23 printw("RIGHT\n");
- 24 break;
- 25 }
- 26
- 27
- 28 }
- 29 endwin();
- 30 return 0;
- 31 }

我们按下上下左右▲▼◀▶之后,可以获取到上下左右的打印信息
- #include <curses.h>
-
- void initNcurse()
- {
- initscr();
- keypad(stdscr,1);
- }
-
- void gamPic()
- {
- int hang;
- int lie;
-
- for(hang=0; hang<20; hang++){
- if(hang == 0){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- for(lie=0; lie<=20; lie++){
- if(lie == 0 || lie == 20){
- printw("|");
- }else{
- printw(" ");
- }
- }
- }
- }
- }
-
- int main()
- {
- initNcurse(); //初始化Ncurse
- gamPic(); //地图规划显示第一行
-
- getch();
- endwin();
- return 0;
- }

- #include <curses.h>
-
- void initNcurse()
- {
- initscr();
- keypad(stdscr,1);
- }
-
- void gamPic()
- {
- int hang;
- int lie;
-
- for(hang=0; hang<20; hang++){
- if(hang == 0){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- for(lie=0; lie<=20; lie++){
- if(lie == 0 || lie == 20){
- printw("|");
- }else{
- printw(" ");
- }
- }
- printw("\n");
- }
-
- if(hang>0 && hang<=19) {
- for(lie=0; lie<=20; lie++){
- if(lie == 0 || lie == 20){
- printw("|");
- }else{
- printw(" ");
- }
- }
- printw("\n");
- }
-
- if(hang == 19){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- printw("By ShiYaHao!\n");
- }
- }
- }
-
- int main()
- {
- initNcurse(); //初始化Ncurse
- gamPic(); //实现贪吃蛇地图
-
- getch();
- endwin();
- return 0;
- }

- #include <curses.h>
-
- void initNcurse()
- {
- initscr();
- keypad(stdscr,1);
- }
-
- void gamPic()
- {
- int hang;
- int lie;
-
- for(hang=0; hang<20; hang++){
- if(hang == 0){ //第0行打“--”
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- }
-
- if(hang>=0 && hang<=19) { //第0行-19行的第0列和第20列打“|”
- for(lie=0; lie<=20; lie++){
- if(lie == 0 || lie == 20){
- printw("|");
- }else{
- printw(" ");
- }
- }
- printw("\n");
- }
-
- if(hang == 19){ //第19行打“--”
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- printw("By ShiYaHao!\n"); //作者
- }
- }
- }
-
- int main()
- {
- initNcurse();
- gamPic();
-
- getch();
- endwin();
- return 0;
- }
- //实现的贪吃蛇地图和上面一样,只不过是优化了一下代码

- #include <curses.h>
-
- struct Snake
- {
- int hang;
- int lie;
- struct Snake *next;
- };
-
- struct Snake node1 = {2,2,NULL};
-
- void initNcurse()
- {
- initscr();
- keypad(stdscr,1);
- }
-
- void gamPic()
- {
- int hang;
- int lie;
-
- for(hang=0; hang<20; hang++){
- if(hang == 0){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- }
-
- if(hang>=0 && hang<=19) {
- for(lie=0; lie<=20; lie++){
- if(lie == 0 || lie == 20){
- printw("|");
- }else if(node1.hang == hang && node1.lie == lie){
- printw("[]");
- }else{
- printw(" ");
- }
- }
- printw("\n");
- }
-
- if(hang == 19){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- printw("By ShiYaHao!\n");
- }
- }
- }
-
- int main()
- {
- initNcurse();
- gamPic();
-
- getch();
- endwin();
- return 0;
- }

- #include <curses.h>
-
- struct Snake
- {
- int hang;
- int lie;
- struct Snake *next;
- };
-
- struct Snake node1 = {2,2,NULL};
- struct Snake node2 = {2,3,NULL};
- struct Snake node3 = {2,4,NULL};
- struct Snake node4 = {2,5,NULL};
-
- void initNcurse()
- {
- initscr();
- keypad(stdscr,1);
- }
-
- int hasSnakeNode(int i, int j)
- {
- struct Snake *p = &node1;
-
- while(p != NULL){
- if(p->hang == i && p->lie == j){
- return 1;
- }
- p = p->next;
- }
- return 0;
- }
-
- void gamPic()
- {
- int hang;
- int lie;
-
- for(hang=0; hang<20; hang++){
- if(hang == 0){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- }
-
- if(hang>=0 && hang<=19) {
- for(lie=0; lie<=20; lie++){
- if(lie == 0 || lie == 20){
- printw("|");
- }else if(hasSnakeNode(hang,lie)){
- printw("[]");
- }else{
- printw(" ");
- }
- }
- printw("\n");
- }
-
- if(hang == 19){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- printw("By ShiYaHao!\n");
- }
- }
- }
-
- int main()
- {
- initNcurse();
-
- node1.next = &node2;
- node2.next = &node3;
- node3.next = &node4;
-
- gamPic();
-
- getch();
- endwin();
- return 0;
- }

- #include <curses.h>
- #include <stdlib.h>
-
- struct Snake
- {
- int hang;
- int lie;
- struct Snake *next;
- };
-
- struct Snake *head = NULL; //指向链表头
- struct Snake *tail = NULL; //指向链表尾
-
- void initNcurse()
- {
- initscr();
- keypad(stdscr,1);
- }
-
- int hasSnakeNode(int i, int j)
- {
- struct Snake *p = head;
-
- while(p != NULL){
- if(p->hang == i && p->lie == j){
- return 1;
- }
- p = p->next;
- }
- return 0;
- }
-
- void gamPic() //地图规划
- {
- int hang;
- int lie;
-
- for(hang=0; hang<20; hang++){
- if(hang == 0){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- }
-
- if(hang>=0 && hang<=19) {
- for(lie=0; lie<=20; lie++){
- if(lie == 0 || lie == 20){
- printw("|");
- }else if(hasSnakeNode(hang,lie)){
- printw("[]");
- }else{
- printw(" ");
- }
- }
- printw("\n");
- }
-
- if(hang == 19){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- printw("By ShiYaHao!\n");
- }
- }
- }
-
- void addNode()
- {
- struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake)); //创建新节点
- if(new == NULL){
- printw("malloc error\n");
- }
- new->hang = tail->hang; //新节点的行等于链表尾的行
- new->lie = tail->lie+1; //新节点的行等于链表尾的列+1
- new->next = NULL;
-
- tail->next = new; //从链表尾部插入新节点
- tail = new; //新节点当作尾部
- }
-
- void initSnake()
- {
- head = (struct Snake *)malloc(sizeof(struct Snake)); //创建链表头
- if(head == NULL){
- printw("malloc error\n");
- }
- head->hang = 2;
- head->lie = 2;
- head->next = NULL;
-
- tail = head; //第一个节点链表头和链表尾是一样的
-
- addNode(); //调用一次代表增加一个节点
- addNode();
- addNode();
- }
-
- int main()
- {
- initNcurse();
-
- initSnake();
-
- gamPic();
-
- getch();
- endwin();
- return 0;
- }

- #include <curses.h>
- #include <stdlib.h>
-
- struct Snake
- {
- int hang;
- int lie;
- struct Snake *next;
- };
-
- struct Snake *head = NULL;
- struct Snake *tail = NULL;
-
- void initNcurse()
- {
- initscr();
- keypad(stdscr,1);
- }
-
- int hasSnakeNode(int i, int j)
- {
- struct Snake *p = head;
-
- while(p != NULL){
- if(p->hang == i && p->lie == j){
- return 1;
- }
- p = p->next;
- }
- return 0;
- }
-
- void gamPic()
- {
- int hang;
- int lie;
-
- move(0,0);
-
- for(hang=0; hang<20; hang++){
- if(hang == 0){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- }
-
- if(hang>=0 && hang<=19) {
- for(lie=0; lie<=20; lie++){
- if(lie == 0 || lie == 20){
- printw("|");
- }else if(hasSnakeNode(hang,lie)){
- printw("[]");
- }else{
- printw(" ");
- }
- }
- printw("\n");
- }
-
- if(hang == 19){
- for(lie=0; lie<20; lie++){
- printw("--");
- }
- printw("\n");
- printw("By ShiYaHao!\n");
- }
- }
- }
-
- 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()
- {
- head = (struct Snake *)malloc(sizeof(struct Snake));
- if(head == NULL){
- printw("malloc error\n");
- }
- head->hang = 2;
- head->lie = 2;
- head->next = NULL;
-
- tail = head;
-
- addNode();
- addNode();
- addNode();
- addNode();
- }
-
- void deletNode()
- {
- struct Snake *p;
- p = head;
-
- head = head->next;
- free(p);
- }
-
- void moveSnake()
- {
- addNode(); //增加一个节点
- deletNode(); //删除头节点
- }
-
- int main()
- {
- int con;
-
- initNcurse();
- initSnake();
-
- gamPic();
-
- while(1){
- con = getch(); //con获取键值
- if(con == KEY_RIGHT){ //如果是右键
- moveSnake(); //向右移动
- gamPic(); //必须刷新一下界面,否则看不到声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/463454推荐阅读
相关标签
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。