• C语言——贪吃蛇小游戏


    目录

    一、ncurse

    1.1 为什么需要用ncurse:

    1.2 ncurse的输入输出:

    1.2.1 如何使用ncurse:

    1.2.2 编译ncurse的程序:

    1.2.3 测试输入一个按键ncurse的响应速度:

    1.3 ncurse上下左右键获取:

    1.3.1 如何查看宏定义的.h文件:

    1.3.2 ncurse上下左右键获取:

    二、地图规划

    2.1 地图规划算法显示第一行:

    2.2 实现贪吃蛇完整地图:

    2.3 优化贪吃蛇地图:

    三、显示贪吃蛇身子

    3.1 显示贪吃蛇身子的一个节点:

    3.2 显示贪吃蛇完整身子:

    3.3 显示贪吃蛇完整身子改进:

    四、贪吃蛇移动

    4.1 按下▶贪吃蛇向右移动:

    4.2 贪吃蛇撞墙重新开始: 

    4.3 贪吃蛇脱缰自由向右行走

    五、Linux线程引入

    5.1 贪吃蛇方向移动和刷新界面一起实现面临的问题:

    5.2 线程的基本用法:

    5.3 线程demo案例:

    5.4 使用线程解决贪吃蛇方向移动和刷新界面一起实现面临的问题:

    六、贪吃蛇跑起来

    6.1 实现贪吃蛇四方向的风骚走位:

    6.2 用绝对值方式来解决不合理的走位:

    6.3 贪吃蛇吃饭了(食物的位置是随机的):

    七、项目代码


    • 项目运行环境:Linux,基于Ncurse图形库的C语言小游戏

    • 项目的目的和意义:起到承上启下的作用,对于前面学的C语言的基础和数据结构链表做一个比较好的巩固,对于后面的Linux系统编程的开发做铺垫

    • 项目基础要求:C语言基础、Linux基本操作

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

      一、ncurse

      1.1 为什么需要用ncurse:

    • 因为的按键响应牛逼哄哄

    • 1.2 ncurse的输入输出

    • ncurse用的最多的地方是在Linux内核编译之前的内核配置

    • 1.2.1 如何使用ncurse:

    1.2.2 编译ncurse的程序:

    1.2.3 测试输入一个按键ncurse的响应速度:
    1. 1 #include
    2. 2
    3. 3 int main()
    4. 4 {
    5. 5 char c;
    6. 6
    7. 7 initscr();
    8. 8 c = getch();
    9. 9 printw("you Input :%c\n",c);
    10. 10 getch();
    11. 11 endwin();
    12. 12 return 0;
    13. 13 }
    • 使用ncurse的好处是:按下一个按键不需要按下回车,直接就可以输出c的值,和我们C语言的其他输入函数好用

    1.3 ncurse上下左右键获取:

    1.3.1 如何查看宏定义的.h文件:

    vi /usr/include/curses.h    //查看宏定义.h文件的指令
    :q                            //退出查看

    1.3.2 ncurse上下左右键获取:

    1. 1 #include
    2. 2
    3. 3 int main()
    4. 4 {
    5. 5 int key;
    6. 6
    7. 7 initscr();
    8. 8 keypad(stdscr,1); //这个函数允许使用功能键,例如:F1、F2、方向键等功能键。几乎所有的交互式程序都需要使用功能 键,因为绝大多数用户界面主要用方向键进行操作。使用keypad(stdscr,TURE)就为“标准屏幕”(stdscr)激活了功能键。
    9. 9
    10. 10 while(1){
    11. 11 key = getch();
    12. 12 switch(key){
    13. 13 case KEY_DOWN:
    14. 14 printw("DOWN\n");
    15. 15 break;
    16. 16 case KEY_UP:
    17. 17 printw("up\n");
    18. 18 break;
    19. 19 case KEY_LEFT:
    20. 20 printw("LEFT\n");
    21. 21 break;
    22. 22 case KEY_RIGHT:
    23. 23 printw("RIGHT\n");
    24. 24 break;
    25. 25 }
    26. 26
    27. 27
    28. 28 }
    29. 29 endwin();
    30. 30 return 0;
    31. 31 }

    • 我们按下上下左右▲▼◀▶之后,可以获取到上下左右的打印信息

    二、地图规划

    2.1 地图规划算法显示第一行:

    1. #include
    2. void initNcurse()
    3. {
    4. initscr();
    5. keypad(stdscr,1);
    6. }
    7. void gamPic()
    8. {
    9. int hang;
    10. int lie;
    11. for(hang=0; hang<20; hang++){
    12. if(hang == 0){
    13. for(lie=0; lie<20; lie++){
    14. printw("--");
    15. }
    16. printw("\n");
    17. for(lie=0; lie<=20; lie++){
    18. if(lie == 0 || lie == 20){
    19. printw("|");
    20. }else{
    21. printw(" ");
    22. }
    23. }
    24. }
    25. }
    26. }
    27. int main()
    28. {
    29. initNcurse(); //初始化Ncurse
    30. gamPic(); //地图规划显示第一行
    31. getch();
    32. endwin();
    33. return 0;
    34. }

    2.2 实现贪吃蛇完整地图:

    1. #include
    2. void initNcurse()
    3. {
    4. initscr();
    5. keypad(stdscr,1);
    6. }
    7. void gamPic()
    8. {
    9. int hang;
    10. int lie;
    11. for(hang=0; hang<20; hang++){
    12. if(hang == 0){
    13. for(lie=0; lie<20; lie++){
    14. printw("--");
    15. }
    16. printw("\n");
    17. for(lie=0; lie<=20; lie++){
    18. if(lie == 0 || lie == 20){
    19. printw("|");
    20. }else{
    21. printw(" ");
    22. }
    23. }
    24. printw("\n");
    25. }
    26. if(hang>0 && hang<=19) {
    27. for(lie=0; lie<=20; lie++){
    28. if(lie == 0 || lie == 20){
    29. printw("|");
    30. }else{
    31. printw(" ");
    32. }
    33. }
    34. printw("\n");
    35. }
    36. if(hang == 19){
    37. for(lie=0; lie<20; lie++){
    38. printw("--");
    39. }
    40. printw("\n");
    41. printw("By ShiYaHao!\n");
    42. }
    43. }
    44. }
    45. int main()
    46. {
    47. initNcurse(); //初始化Ncurse
    48. gamPic(); //实现贪吃蛇地图
    49. getch();
    50. endwin();
    51. return 0;
    52. }

    2.3 优化贪吃蛇地图:

    1. #include
    2. void initNcurse()
    3. {
    4. initscr();
    5. keypad(stdscr,1);
    6. }
    7. void gamPic()
    8. {
    9. int hang;
    10. int lie;
    11. for(hang=0; hang<20; hang++){
    12. if(hang == 0){ //第0行打“--”
    13. for(lie=0; lie<20; lie++){
    14. printw("--");
    15. }
    16. printw("\n");
    17. }
    18. if(hang>=0 && hang<=19) { //第0行-19行的第0列和第20列打“|”
    19. for(lie=0; lie<=20; lie++){
    20. if(lie == 0 || lie == 20){
    21. printw("|");
    22. }else{
    23. printw(" ");
    24. }
    25. }
    26. printw("\n");
    27. }
    28. if(hang == 19){ //第19行打“--”
    29. for(lie=0; lie<20; lie++){
    30. printw("--");
    31. }
    32. printw("\n");
    33. printw("By ShiYaHao!\n"); //作者
    34. }
    35. }
    36. }
    37. int main()
    38. {
    39. initNcurse();
    40. gamPic();
    41. getch();
    42. endwin();
    43. return 0;
    44. }
    45. //实现的贪吃蛇地图和上面一样,只不过是优化了一下代码

    三、显示贪吃蛇身子

    3.1 显示贪吃蛇身子的一个节点:

    1. #include
    2. struct Snake
    3. {
    4. int hang;
    5. int lie;
    6. struct Snake *next;
    7. };
    8. struct Snake node1 = {2,2,NULL};
    9. void initNcurse()
    10. {
    11. initscr();
    12. keypad(stdscr,1);
    13. }
    14. void gamPic()
    15. {
    16. int hang;
    17. int lie;
    18. for(hang=0; hang<20; hang++){
    19. if(hang == 0){
    20. for(lie=0; lie<20; lie++){
    21. printw("--");
    22. }
    23. printw("\n");
    24. }
    25. if(hang>=0 && hang<=19) {
    26. for(lie=0; lie<=20; lie++){
    27. if(lie == 0 || lie == 20){
    28. printw("|");
    29. }else if(node1.hang == hang && node1.lie == lie){
    30. printw("[]");
    31. }else{
    32. printw(" ");
    33. }
    34. }
    35. printw("\n");
    36. }
    37. if(hang == 19){
    38. for(lie=0; lie<20; lie++){
    39. printw("--");
    40. }
    41. printw("\n");
    42. printw("By ShiYaHao!\n");
    43. }
    44. }
    45. }
    46. int main()
    47. {
    48. initNcurse();
    49. gamPic();
    50. getch();
    51. endwin();
    52. return 0;
    53. }

    3.2 显示贪吃蛇完整身子:

    1. #include
    2. struct Snake
    3. {
    4. int hang;
    5. int lie;
    6. struct Snake *next;
    7. };
    8. struct Snake node1 = {2,2,NULL};
    9. struct Snake node2 = {2,3,NULL};
    10. struct Snake node3 = {2,4,NULL};
    11. struct Snake node4 = {2,5,NULL};
    12. void initNcurse()
    13. {
    14. initscr();
    15. keypad(stdscr,1);
    16. }
    17. int hasSnakeNode(int i, int j)
    18. {
    19. struct Snake *p = &node1;
    20. while(p != NULL){
    21. if(p->hang == i && p->lie == j){
    22. return 1;
    23. }
    24. p = p->next;
    25. }
    26. return 0;
    27. }
    28. void gamPic()
    29. {
    30. int hang;
    31. int lie;
    32. for(hang=0; hang<20; hang++){
    33. if(hang == 0){
    34. for(lie=0; lie<20; lie++){
    35. printw("--");
    36. }
    37. printw("\n");
    38. }
    39. if(hang>=0 && hang<=19) {
    40. for(lie=0; lie<=20; lie++){
    41. if(lie == 0 || lie == 20){
    42. printw("|");
    43. }else if(hasSnakeNode(hang,lie)){
    44. printw("[]");
    45. }else{
    46. printw(" ");
    47. }
    48. }
    49. printw("\n");
    50. }
    51. if(hang == 19){
    52. for(lie=0; lie<20; lie++){
    53. printw("--");
    54. }
    55. printw("\n");
    56. printw("By ShiYaHao!\n");
    57. }
    58. }
    59. }
    60. int main()
    61. {
    62. initNcurse();
    63. node1.next = &node2;
    64. node2.next = &node3;
    65. node3.next = &node4;
    66. gamPic();
    67. getch();
    68. endwin();
    69. return 0;
    70. }

    3.3 显示贪吃蛇完整身子改进:

    1. #include
    2. #include
    3. struct Snake
    4. {
    5. int hang;
    6. int lie;
    7. struct Snake *next;
    8. };
    9. struct Snake *head = NULL; //指向链表头
    10. struct Snake *tail = NULL; //指向链表尾
    11. void initNcurse()
    12. {
    13. initscr();
    14. keypad(stdscr,1);
    15. }
    16. int hasSnakeNode(int i, int j)
    17. {
    18. struct Snake *p = head;
    19. while(p != NULL){
    20. if(p->hang == i && p->lie == j){
    21. return 1;
    22. }
    23. p = p->next;
    24. }
    25. return 0;
    26. }
    27. void gamPic() //地图规划
    28. {
    29. int hang;
    30. int lie;
    31. for(hang=0; hang<20; hang++){
    32. if(hang == 0){
    33. for(lie=0; lie<20; lie++){
    34. printw("--");
    35. }
    36. printw("\n");
    37. }
    38. if(hang>=0 && hang<=19) {
    39. for(lie=0; lie<=20; lie++){
    40. if(lie == 0 || lie == 20){
    41. printw("|");
    42. }else if(hasSnakeNode(hang,lie)){
    43. printw("[]");
    44. }else{
    45. printw(" ");
    46. }
    47. }
    48. printw("\n");
    49. }
    50. if(hang == 19){
    51. for(lie=0; lie<20; lie++){
    52. printw("--");
    53. }
    54. printw("\n");
    55. printw("By ShiYaHao!\n");
    56. }
    57. }
    58. }
    59. void addNode()
    60. {
    61. struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake)); //创建新节点
    62. if(new == NULL){
    63. printw("malloc error\n");
    64. }
    65. new->hang = tail->hang; //新节点的行等于链表尾的行
    66. new->lie = tail->lie+1; //新节点的行等于链表尾的列+1
    67. new->next = NULL;
    68. tail->next = new; //从链表尾部插入新节点
    69. tail = new; //新节点当作尾部
    70. }
    71. void initSnake()
    72. {
    73. head = (struct Snake *)malloc(sizeof(struct Snake)); //创建链表头
    74. if(head == NULL){
    75. printw("malloc error\n");
    76. }
    77. head->hang = 2;
    78. head->lie = 2;
    79. head->next = NULL;
    80. tail = head; //第一个节点链表头和链表尾是一样的
    81. addNode(); //调用一次代表增加一个节点
    82. addNode();
    83. addNode();
    84. }
    85. int main()
    86. {
    87. initNcurse();
    88. initSnake();
    89. gamPic();
    90. getch();
    91. endwin();
    92. return 0;
    93. }

    四、贪吃蛇移动

    4.1 按下▶贪吃蛇向右移动:

    1. #include
    2. #include
    3. struct Snake
    4. {
    5. int hang;
    6. int lie;
    7. struct Snake *next;
    8. };
    9. struct Snake *head = NULL;
    10. struct Snake *tail = NULL;
    11. void initNcurse()
    12. {
    13. initscr();
    14. keypad(stdscr,1);
    15. }
    16. int hasSnakeNode(int i, int j)
    17. {
    18. struct Snake *p = head;
    19. while(p != NULL){
    20. if(p->hang == i && p->lie == j){
    21. return 1;
    22. }
    23. p = p->next;
    24. }
    25. return 0;
    26. }
    27. void gamPic()
    28. {
    29. int hang;
    30. int lie;
    31. move(0,0);
    32. for(hang=0; hang<20; hang++){
    33. if(hang == 0){
    34. for(lie=0; lie<20; lie++){
    35. printw("--");
    36. }
    37. printw("\n");
    38. }
    39. if(hang>=0 && hang<=19) {
    40. for(lie=0; lie<=20; lie++){
    41. if(lie == 0 || lie == 20){
    42. printw("|");
    43. }else if(hasSnakeNode(hang,lie)){
    44. printw("[]");
    45. }else{
    46. printw(" ");
    47. }
    48. }
    49. printw("\n");
    50. }
    51. if(hang == 19){
    52. for(lie=0; lie<20; lie++){
    53. printw("--");
    54. }
    55. printw("\n");
    56. printw("By ShiYaHao!\n");
    57. }
    58. }
    59. }
    60. void addNode()
    61. {
    62. struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));
    63. new->hang = tail->hang;
    64. new->lie = tail->lie+1;
    65. new->next = NULL;
    66. tail->next = new;
    67. tail = new;
    68. }
    69. void initSnake()
    70. {
    71. head = (struct Snake *)malloc(sizeof(struct Snake));
    72. if(head == NULL){
    73. printw("malloc error\n");
    74. }
    75. head->hang = 2;
    76. head->lie = 2;
    77. head->next = NULL;
    78. tail = head;
    79. addNode();
    80. addNode();
    81. addNode();
    82. addNode();
    83. }
    84. void deletNode()
    85. {
    86. struct Snake *p;
    87. p = head;
    88. head = head->next;
    89. free(p);
    90. }
    91. void moveSnake()
    92. {
    93. addNode(); //增加一个节点
    94. deletNode(); //删除头节点
    95. }
    96. int main()
    97. {
    98. int con;
    99. initNcurse();
    100. initSnake();
    101. gamPic();
    102. while(1){
    103. con = getch(); //con获取键值
    104. if(con == KEY_RIGHT){ //如果是右键
    105. moveSnake(); //向右移动
    106. gamPic(); //必须刷新一下界面,否则看不到🐍移动
    107. }
    108. }
    109. getch();
    110. endwin();
    111. return 0;
    112. }

    4.2 贪吃蛇撞墙重新开始: 

    1. #include
    2. #include
    3. struct Snake
    4. {
    5. int hang;
    6. int lie;
    7. struct Snake *next;
    8. };
    9. struct Snake *head = NULL;
    10. struct Snake *tail = NULL;
    11. void initNcurse()
    12. {
    13. initscr();
    14. keypad(stdscr,1);
    15. }
    16. int hasSnakeNode(int i, int j)
    17. {
    18. struct Snake *p = head;
    19. while(p != NULL){
    20. if(p->hang == i && p->lie == j){
    21. return 1;
    22. }
    23. p = p->next;
    24. }
    25. return 0;
    26. }
    27. void gamPic()
    28. {
    29. int hang;
    30. int lie;
    31. move(0,0);
    32. for(hang=0; hang<20; hang++){
    33. if(hang == 0){
    34. for(lie=0; lie<20; lie++){
    35. printw("--");
    36. }
    37. printw("\n");
    38. }
    39. if(hang>=0 && hang<=19) {
    40. for(lie=0; lie<=20; lie++){
    41. if(lie == 0 || lie == 20){
    42. printw("|");
    43. }else if(hasSnakeNode(hang,lie)){
    44. printw("[]");
    45. }else{
    46. printw(" ");
    47. }
    48. }
    49. printw("\n");
    50. }
    51. if(hang == 19){
    52. for(lie=0; lie<20; lie++){
    53. printw("--");
    54. }
    55. printw("\n");
    56. printw("By ShiYaHao!\n");
    57. }
    58. }
    59. }
    60. void addNode()
    61. {
    62. struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));
    63. if(new == NULL){
    64. printw("malloc error\n");
    65. }
    66. new->hang = tail->hang;
    67. new->lie = tail->lie+1;
    68. new->next = NULL;
    69. tail->next = new;
    70. tail = new;
    71. }
    72. void initSnake()
    73. {
    74. struct Snake *p;
    75. while(head != NULL){ 判断蛇是否为空,清理内存
    76. p = head;
    77. head = head->next;
    78. free(p);
    79. }
    80. head = (struct Snake *)malloc(sizeof(struct Snake));
    81. if(head == NULL){
    82. printw("malloc error\n");
    83. }
    84. head->hang = 1;
    85. head->lie = 1;
    86. head->next = NULL;
    87. tail = head;
    88. addNode();
    89. addNode();
    90. addNode();
    91. addNode();
    92. }
    93. void deletNode()
    94. {
    95. struct Snake *p;
    96. p = head;
    97. head = head->next;
    98. free(p);
    99. }
    100. void moveSnake()
    101. {
    102. addNode();
    103. deletNode();
    104. //判断蛇的尾巴碰到上下左右的四个边框后就重新开始
    105. if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){
    106. initSnake();
    107. }
    108. }
    109. int main()
    110. {
    111. int con;
    112. initNcurse();
    113. initSnake();
    114. gamPic();
    115. while(1){
    116. con = getch();
    117. if(con == KEY_RIGHT){
    118. moveSnake();
    119. gamPic();
    120. }
    121. }
    122. getch();
    123. endwin();
    124. return 0;
    125. }

    4.3 贪吃蛇脱缰自由向右行走

    1. #include
    2. #include
    3. struct Snake
    4. {
    5. int hang;
    6. int lie;
    7. struct Snake *next;
    8. };
    9. struct Snake *head = NULL;
    10. struct Snake *tail = NULL;
    11. void initNcurse()
    12. {
    13. initscr();
    14. keypad(stdscr,1);
    15. }
    16. int hasSnakeNode(int i, int j)
    17. {
    18. struct Snake *p = head;
    19. while(p != NULL){
    20. if(p->hang == i && p->lie == j){
    21. return 1;
    22. }
    23. p = p->next;
    24. }
    25. return 0;
    26. }
    27. void gamPic()
    28. {
    29. int hang;
    30. int lie;
    31. move(0,0);
    32. for(hang=0; hang<20; hang++){
    33. if(hang == 0){
    34. for(lie=0; lie<20; lie++){
    35. printw("--");
    36. }
    37. printw("\n");
    38. }
    39. if(hang>=0 && hang<=19) {
    40. for(lie=0; lie<=20; lie++){
    41. if(lie == 0 || lie == 20){
    42. printw("|");
    43. }else if(hasSnakeNode(hang,lie)){
    44. printw("[]");
    45. }else{
    46. printw(" ");
    47. }
    48. }
    49. printw("\n");
    50. }
    51. if(hang == 19){
    52. for(lie=0; lie<20; lie++){
    53. printw("--");
    54. }
    55. printw("\n");
    56. printw("By ShiYaHao!\n");
    57. }
    58. }
    59. }
    60. void addNode()
    61. {
    62. struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));
    63. if(new == NULL){
    64. printw("malloc error\n");
    65. }
    66. new->hang = tail->hang;
    67. new->lie = tail->lie+1;
    68. new->next = NULL;
    69. tail->next = new;
    70. tail = new;
    71. }
    72. void initSnake()
    73. {
    74. struct Snake *p;
    75. while(head != NULL){
    76. p = head;
    77. head = head->next;
    78. free(p);
    79. }
    80. head = (struct Snake *)malloc(sizeof(struct Snake));
    81. if(head == NULL){
    82. printw("malloc error\n");
    83. }
    84. head->hang = 1;
    85. head->lie = 1;
    86. head->next = NULL;
    87. tail = head;
    88. addNode();
    89. addNode();
    90. addNode();
    91. addNode();
    92. }
    93. void deletNode()
    94. {
    95. struct Snake *p;
    96. p = head;
    97. head = head->next;
    98. free(p);
    99. }
    100. void moveSnake()
    101. {
    102. addNode();
    103. deletNode();
    104. if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){
    105. initSnake();
    106. }
    107. }
    108. int main()
    109. {
    110. int con;
    111. initNcurse();
    112. initSnake();
    113. gamPic();
    114. while(1){ //之前受方向键控制,现在自由行走
    115. moveSnake();
    116. gamPic();
    117. refresh(); //刷新界面
    118. usleep(100000); //延时100ms
    119. }
    120. getch();
    121. endwin();
    122. return 0;
    123. }

    五、Linux线程引入

    5.1 贪吃蛇方向移动和刷新界面一起实现面临的问题:

    1. #include
    2. #include
    3. struct Snake
    4. {
    5. int hang;
    6. int lie;
    7. struct Snake *next;
    8. };
    9. struct Snake *head = NULL;
    10. struct Snake *tail = NULL;
    11. void initNcurse()
    12. {
    13. initscr();
    14. keypad(stdscr,1);
    15. }
    16. int hasSnakeNode(int i, int j)
    17. {
    18. struct Snake *p = head;
    19. while(p != NULL){
    20. if(p->hang == i && p->lie == j){
    21. return 1;
    22. }
    23. p = p->next;
    24. }
    25. return 0;
    26. }
    27. void gamPic()
    28. {
    29. int hang;
    30. int lie;
    31. move(0,0);
    32. for(hang=0; hang<20; hang++){
    33. if(hang == 0){
    34. for(lie=0; lie<20; lie++){
    35. printw("--");
    36. }
    37. printw("\n");
    38. }
    39. if(hang>=0 && hang<=19) {
    40. for(lie=0; lie<=20; lie++){
    41. if(lie == 0 || lie == 20){
    42. printw("|");
    43. }else if(hasSnakeNode(hang,lie)){
    44. printw("[]");
    45. }else{
    46. printw(" ");
    47. }
    48. }
    49. printw("\n");
    50. }
    51. if(hang == 19){
    52. for(lie=0; lie<20; lie++){
    53. printw("--");
    54. }
    55. printw("\n");
    56. printw("By ShiYaHao!\n");
    57. }
    58. }
    59. }
    60. void addNode()
    61. {
    62. struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));
    63. if(new == NULL){
    64. printw("malloc error\n");
    65. }
    66. new->hang = tail->hang;
    67. new->lie = tail->lie+1;
    68. new->next = NULL;
    69. tail->next = new;
    70. tail = new;
    71. }
    72. void initSnake()
    73. {
    74. struct Snake *p;
    75. while(head != NULL){
    76. p = head;
    77. head = head->next;
    78. free(p);
    79. }
    80. head = (struct Snake *)malloc(sizeof(struct Snake));
    81. if(head == NULL){
    82. printw("malloc error\n");
    83. }
    84. head->hang = 1;
    85. head->lie = 1;
    86. head->next = NULL;
    87. tail = head;
    88. addNode();
    89. addNode();
    90. addNode();
    91. addNode();
    92. }
    93. void deletNode()
    94. {
    95. struct Snake *p;
    96. p = head;
    97. head = head->next;
    98. free(p);
    99. }
    100. void moveSnake()
    101. {
    102. addNode();
    103. deletNode();
    104. if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){
    105. initSnake();
    106. }
    107. }
    108. int main()
    109. {
    110. int key;
    111. initNcurse();
    112. initSnake();
    113. gamPic();
    114. while(1){
    115. moveSnake();
    116. gamPic();
    117. refresh();
    118. usleep(100000);
    119. }
    120. while(1){
    121. key = getch();
    122. switch(key){
    123. case KEY_DOWN:
    124. printw("DOWN\n");
    125. break;
    126. case KEY_UP:
    127. printw("UP\n");
    128. break;
    129. case KEY_LEFT:
    130. printw("LEFT\n");
    131. break;
    132. case KEY_RIGHT:
    133. printw("RIGHT\n");
    134. break;
    135. }
    136. }
    137. getch();
    138. endwin();
    139. return 0;
    140. }
    • 在上面的程序中main函数中有两个while(1)循环,这样就会出现问题,程序运行的现象是:获取按键值的这个while循环根本不会执行,那该如何解决?于是引入“Linux线程”!

    • 在贪吃蛇运动过程中,我们需要改变蛇的移动方向,这是就需要不停扫描键盘输入的值来判断方向,同时还需要不停的刷新界面,为了多个while循环并存这里需要引入linux线程。

    5.2 线程的基本用法:

    1. #include // 头文件
    2. pthread_t:当前Linux中可理解为:typedef unsigned long int pthread_t;
    3. 如:pthread_t t1; //多线程定义
    4. pthread_create(&t1,NULL,refreshInterface,NULL);
    5. 参数1:传出参数,保存系统为我们分配好的线程ID
    6. 参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
    7. 参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。
    8. 参数4:线程主函数执行期间所使用的参数,如要传多个参数, 可以用结构封装。
    9. 使用多线程的函数必须返回指针型,如void *refreshInterface()
    10. 注:gcc xxx.c -lcurses -lpthead //编译需要连接pthead库

    5.3 线程demo案例:

    1. /*
    2. 在这个程序当中只有func1一个函数会被执行,func2函数根本不会执行
    3. 想要解决这个问题就需要引入Linux的线程
    4. */
    5. #include
    6. void pfunc1()
    7. {
    8. while(1){
    9. printf("this is a pfunc1\n");
    10. sleep(1);
    11. }
    12. }
    13. void pfunc2()
    14. {
    15. while(1){
    16. printf("this is a pfunc2\n");
    17. sleep(1);
    18. }
    19. }
    20. int main()
    21. {
    22. pfunc1();
    23. pfunc2();
    24. return 0;
    25. }
    1. /*
    2. 引入Linux线程修改代码,func1和func2两个函数都可以执行
    3. */
    4. #include
    5. #include //线程头文件
    6. void* func1()
    7. {
    8. while(1){
    9. printf("this is a func1\n");
    10. sleep(1);
    11. }
    12. }
    13. void* func2()
    14. {
    15. while(1){
    16. printf("this is a func2\n");
    17. sleep(1);
    18. }
    19. }
    20. int main()
    21. {
    22. pthread_t th1; //定义一个th1线程
    23. pthread_t th2; //定义一个th2线程
    24. pthread_create(&th1, NULL, func1, NULL);
    25. pthread_create(&th2, NULL, func2, NULL);
    26. while(1);
    27. return 0;
    28. }

    5.4 使用线程解决贪吃蛇方向移动和刷新界面一起实现面临的问题:

    1. #include
    2. #include
    3. struct Snake
    4. {
    5. int hang;
    6. int lie;
    7. struct Snake *next;
    8. };
    9. struct Snake *head = NULL;
    10. struct Snake *tail = NULL;
    11. int key;
    12. void initNcurse()
    13. {
    14. initscr();
    15. keypad(stdscr,1);
    16. }
    17. int hasSnakeNode(int i, int j)
    18. {
    19. struct Snake *p = head;
    20. while(p != NULL){
    21. if(p->hang == i && p->lie == j){
    22. return 1;
    23. }
    24. p = p->next;
    25. }
    26. return 0;
    27. }
    28. void gamPic()
    29. {
    30. int hang;
    31. int lie;
    32. move(0,0);
    33. for(hang=0; hang<20; hang++){
    34. if(hang == 0){
    35. for(lie=0; lie<20; lie++){
    36. printw("--");
    37. }
    38. printw("\n");
    39. }
    40. if(hang>=0 && hang<=19) {
    41. for(lie=0; lie<=20; lie++){
    42. if(lie == 0 || lie == 20){
    43. printw("|");
    44. }else if(hasSnakeNode(hang,lie)){
    45. printw("[]");
    46. }else{
    47. printw(" ");
    48. }
    49. }
    50. printw("\n");
    51. }
    52. if(hang == 19){
    53. for(lie=0; lie<20; lie++){
    54. printw("--");
    55. }
    56. printw("\n");
    57. printw("By ShiYaHao!key = %d\n",key);
    58. }
    59. }
    60. }
    61. void addNode()
    62. {
    63. struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));
    64. new->hang = tail->hang;
    65. new->lie = tail->lie+1;
    66. new->next = NULL;
    67. tail->next = new;
    68. tail = new;
    69. }
    70. void initSnake()
    71. {
    72. struct Snake *p;
    73. while(head != NULL){
    74. p = head;
    75. head = head->next;
    76. free(p);
    77. }
    78. head = (struct Snake *)malloc(sizeof(struct Snake));
    79. head->hang = 1;
    80. head->lie = 1;
    81. head->next = NULL;
    82. tail = head;
    83. addNode();
    84. addNode();
    85. addNode();
    86. addNode();
    87. }
    88. void deletNode()
    89. {
    90. struct Snake *p;
    91. p = head;
    92. head = head->next;
    93. free(p);
    94. }
    95. void moveSnake()
    96. {
    97. addNode();
    98. deletNode();
    99. if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){
    100. initSnake();
    101. }
    102. }
    103. void* refreshJieMian()
    104. {
    105. while(1){
    106. moveSnake();
    107. gamPic();
    108. refresh();
    109. usleep(100000);
    110. }
    111. }
    112. void* changeDir()
    113. {
    114. while(1){
    115. key = getch();
    116. switch(key){
    117. case KEY_DOWN:
    118. printw("DOWN\n");
    119. break;
    120. case KEY_UP:
    121. printw("UP\n");
    122. break;
    123. case KEY_LEFT:
    124. printw("LEFT\n");
    125. break;
    126. case KEY_RIGHT:
    127. printw("RIGHT\n");
    128. break;
    129. }
    130. }
    131. }
    132. int main()
    133. {
    134. initNcurse();
    135. initSnake();
    136. //注意:线程创建要放在初始化后面,不然就会导致程序段错误(答疑老师解决)
    137. pthread_t t1;
    138. pthread_t t2;
    139. pthread_create(&t1, NULL, refreshJieMian, NULL);
    140. pthread_create(&t2, NULL, changeDir, NULL);
    141. gamPic();
    142. while(1);
    143. getch();
    144. endwin();
    145. return 0;
    146. }

    • 蛇在向右移动的同时也可以按方向键,这就是引入线程之后的牛逼之处!

    六、贪吃蛇跑起来

    6.1 实现贪吃蛇四方向的风骚走位:
    1. #include
    2. #include
    3. #include
    4. #define UP 1
    5. #define DOWN 2
    6. #define LEFT 3
    7. #define RIGHT 4
    8. struct Snake
    9. {
    10. int hang;
    11. int lie;
    12. struct Snake *next;
    13. };
    14. struct Snake *head = NULL;
    15. struct Snake *tail = NULL;
    16. int key;
    17. int dir;
    18. void initNcurse()
    19. {
    20. initscr();
    21. keypad(stdscr,1);
    22. }
    23. int hasSnakeNode(int i, int j)
    24. {
    25. struct Snake *p = head;
    26. while(p != NULL){
    27. if(p->hang == i && p->lie == j){
    28. return 1;
    29. }
    30. p = p->next;
    31. }
    32. return 0;
    33. }
    34. void gamPic()
    35. {
    36. int hang;
    37. int lie;
    38. move(0,0);
    39. for(hang=0; hang<20; hang++){
    40. if(hang == 0){
    41. for(lie=0; lie<20; lie++){
    42. printw("--");
    43. }
    44. printw("\n");
    45. }
    46. if(hang>=0 && hang<=19) {
    47. for(lie=0; lie<=20; lie++){
    48. if(lie == 0 || lie == 20){
    49. printw("|");
    50. }else if(hasSnakeNode(hang,lie)){
    51. printw("[]");:
    52. }else{
    53. printw(" ");
    54. }
    55. }
    56. printw("\n");
    57. }
    58. if(hang == 19){
    59. for(lie=0; lie<20; lie++){
    60. printw("--");
    61. }
    62. printw("\n");
    63. printw("By ShiYaHao!key = %d\n",key);
    64. }
    65. }
    66. }
    67. void addNode()
    68. {
    69. struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));
    70. new->hang = tail->hang;
    71. new->lie = tail->lie+1;
    72. new->next = NULL;
    73. switch(dir){
    74. case UP:
    75. new->hang = tail->hang-1;
    76. new->lie = tail->lie;
    77. break;
    78. case DOWN:
    79. new->hang = tail->hang+1;
    80. new->lie = tail->lie;
    81. break;
    82. case LEFT:
    83. new->hang = tail->hang;
    84. new->lie = tail->lie-1;
    85. break;
    86. case RIGHT:
    87. new->hang = tail->hang;
    88. new->lie = tail->lie+1;
    89. break;
    90. }
    91. tail->next = new;
    92. tail = new;
    93. }
    94. void initSnake()
    95. {
    96. struct Snake *p;
    97. dir = RIGHT;
    98. while(head != NULL){
    99. p = head;
    100. head = head->next;
    101. free(p);
    102. }
    103. head = (struct Snake *)malloc(sizeof(struct Snake));
    104. head->hang = 1;
    105. head->lie = 1;
    106. head->next = NULL;
    107. tail = head;
    108. addNode();
    109. addNode();
    110. addNode();
    111. addNode();
    112. }
    113. void deletNode()
    114. {
    115. struct Snake *p;
    116. p = head;
    117. head = head->next;
    118. free(p);
    119. }
    120. void moveSnake()
    121. {
    122. addNode();
    123. deletNode();
    124. if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){
    125. initSnake();
    126. }
    127. }
    128. void* refreshJieMian()
    129. {
    130. while(1){
    131. moveSnake();
    132. gamPic();
    133. refresh();
    134. usleep(100000);
    135. }
    136. }
    137. void* changeDir()
    138. {
    139. while(1){
    140. key = getch();
    141. switch(key){
    142. case KEY_DOWN:
    143. dir = DOWN;
    144. break;
    145. case KEY_UP:
    146. dir = UP;
    147. break;
    148. case KEY_LEFT:
    149. dir = LEFT;
    150. break;
    151. case KEY_RIGHT:
    152. dir = RIGHT;
    153. break;
    154. }
    155. }
    156. }
    157. int main()
    158. {
    159. pthread_t t1;
    160. pthread_t t2;
    161. initNcurse();
    162. initSnake();
    163. gamPic();
    164. pthread_create(&t1, NULL, refreshJieMian, NULL);
    165. pthread_create(&t2, NULL, changeDir, NULL);
    166. while(1);
    167. getch();
    168. endwin();
    169. return 0;
    170. }

    6.2 用绝对值方式来解决不合理的走位:

    1. #include
    2. #include
    3. #define UP 1
    4. #define DOWN -1
    5. #define LEFT 2
    6. #define RIGHT -2
    7. struct Snake
    8. {
    9. int hang;
    10. int lie;
    11. struct Snake *next;
    12. };
    13. struct Snake *head = NULL;
    14. struct Snake *tail = NULL;
    15. int key;
    16. int dir;
    17. void initNcurse()
    18. {
    19. initscr();
    20. keypad(stdscr,1);
    21. noecho();
    22. }
    23. int hasSnakeNode(int i, int j)
    24. {
    25. struct Snake *p = head;
    26. while(p != NULL){
    27. if(p->hang == i && p->lie == j){
    28. return 1;
    29. }
    30. p = p->next;
    31. }
    32. return 0;
    33. }
    34. void gamPic()
    35. {
    36. int hang;
    37. int lie;
    38. move(0,0);
    39. for(hang=0; hang<20; hang++){
    40. if(hang == 0){
    41. for(lie=0; lie<20; lie++){
    42. printw("--");
    43. }
    44. printw("\n");
    45. }
    46. if(hang>=0 && hang<=19) {
    47. for(lie=0; lie<=20; lie++){
    48. if(lie == 0 || lie == 20){
    49. printw("|");
    50. }else if(hasSnakeNode(hang,lie)){
    51. printw("[]");
    52. }else{
    53. printw(" ");
    54. }
    55. }
    56. printw("\n");
    57. }
    58. if(hang == 19){
    59. for(lie=0; lie<20; lie++){
    60. printw("--");
    61. }
    62. printw("\n");
    63. printw("By ShiYaHao!key = %d\n",key);
    64. }
    65. }
    66. }
    67. void addNode()
    68. {
    69. struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));
    70. new->hang = tail->hang;
    71. new->lie = tail->lie+1;
    72. new->next = NULL;
    73. switch(dir){
    74. case UP:
    75. new->hang = tail->hang-1;
    76. new->lie = tail->lie;
    77. break;
    78. case DOWN:
    79. new->hang = tail->hang+1;
    80. new->lie = tail->lie;
    81. break;
    82. case LEFT:
    83. new->hang = tail->hang;
    84. new->lie = tail->lie-1;
    85. break;
    86. case RIGHT:
    87. new->hang = tail->hang;
    88. new->lie = tail->lie+1;
    89. break;
    90. }
    91. tail->next = new;
    92. tail = new;
    93. }
    94. void initSnake()
    95. {
    96. struct Snake *p;
    97. dir = RIGHT;
    98. while(head != NULL){
    99. p = head;
    100. head = head->next;
    101. free(p);
    102. }
    103. head = (struct Snake *)malloc(sizeof(struct Snake));
    104. head->hang = 1;
    105. head->lie = 1;
    106. head->next = NULL;
    107. tail = head;
    108. addNode();
    109. addNode();
    110. addNode();
    111. addNode();
    112. }
    113. void deletNode()
    114. {
    115. struct Snake *p;
    116. p = head;
    117. head = head->next;
    118. free(p);
    119. }
    120. void moveSnake()
    121. {
    122. addNode();
    123. deletNode();
    124. if(tail->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){
    125. initSnake();
    126. }
    127. }
    128. void refreshJieMian()
    129. {
    130. while(1){
    131. moveSnake();
    132. gamPic();
    133. refresh();
    134. usleep(100000);
    135. }
    136. }
    137. void turn(int direction) 通过绝对值判断相反方向不触发
    138. {
    139. if(abs(dir) != abs(direction)){
    140. dir = direction;
    141. }
    142. }
    143. void changeDir()
    144. {
    145. while(1){
    146. key = getch();
    147. switch(key){
    148. case KEY_DOWN:
    149. turn(DOWN);
    150. break;
    151. case KEY_UP:
    152. turn(UP);
    153. break;
    154. case KEY_LEFT:
    155. turn(LEFT);
    156. break;
    157. case KEY_RIGHT:
    158. turn(RIGHT);
    159. break;
    160. }
    161. }
    162. }
    163. int main()
    164. {
    165. pthread_t t1;
    166. pthread_t t2;
    167. initNcurse();
    168. initSnake();
    169. gamPic();
    170. pthread_create(&t1, NULL, refreshJieMian, NULL);
    171. pthread_create(&t2, NULL, changeDir, NULL);
    172. while(1);
    173. getch();
    174. endwin();
    175. return 0;
    176. }

    6.3 贪吃蛇吃饭了(食物的位置是随机的):

    1. #include
    2. #include
    3. #include
    4. #define UP 1
    5. #define DOWN -1
    6. #define LEFT 2
    7. #define RIGHT -2
    8. struct Snake
    9. {
    10. int hang;
    11. int lie;
    12. struct Snake *next;
    13. };
    14. struct Snake *head = NULL;
    15. struct Snake *tail = NULL;
    16. int key;
    17. int dir;
    18. struct Snake food;
    19. void initFood()
    20. {
    21. int x = rand()%20;
    22. int y = rand()%20;
    23. food.hang = x;
    24. food.lie = y;
    25. }
    26. void initNcurse()
    27. {
    28. initscr();
    29. keypad(stdscr,1);
    30. noecho();
    31. }
    32. int hasSnakeNode(int i, int j)
    33. {
    34. struct Snake *p = head;
    35. while(p != NULL){
    36. if(p->hang == i && p->lie == j){
    37. return 1;
    38. }
    39. p = p->next;
    40. }
    41. return 0;
    42. }
    43. int hasFood(int i, int j)
    44. {
    45. if(food.hang == i && food.lie == j){
    46. return 1;
    47. }
    48. return 0;
    49. }
    50. void gamPic()
    51. {
    52. int hang;
    53. int lie;
    54. move(0,0);
    55. for(hang=0; hang<20; hang++){
    56. if(hang == 0){
    57. for(lie=0; lie<20; lie++){
    58. printw("--");
    59. }
    60. printw("\n");
    61. }
    62. if(hang>=0 && hang<=19) {
    63. for(lie=0; lie<=20; lie++){
    64. if(lie == 0 || lie == 20){
    65. printw("|");
    66. }else if(hasSnakeNode(hang,lie)){
    67. printw("[]");
    68. }else if(hasFood(hang,lie)){
    69. printw("##");
    70. }else{
    71. printw(" ");
    72. }
    73. }
    74. printw("\n");
    75. }
    76. if(hang == 19){
    77. for(lie=0; lie<20; lie++){
    78. printw("--");
    79. }
    80. printw("\n");
    81. printw("By ShiYaHao! food.hang = %d,food.lie = %d\n",food.hang,food.lie);
    82. }
    83. }
    84. }
    85. void addNode()
    86. {
    87. struct Snake *new =(struct Snake *) malloc(sizeof(struct Snake));
    88. new->hang = tail->hang;
    89. new->lie = tail->lie+1;
    90. new->next = NULL;
    91. switch(dir){
    92. case UP:
    93. new->hang = tail->hang-1;
    94. new->lie = tail->lie;
    95. break;
    96. case DOWN:
    97. new->hang = tail->hang+1;
    98. new->lie = tail->lie;
    99. break;
    100. case LEFT:
    101. new->hang = tail->hang;
    102. new->lie = tail->lie-1;
    103. break;
    104. case RIGHT:
    105. new->hang = tail->hang;
    106. new->lie = tail->lie+1;
    107. break;
    108. }
    109. tail->next = new;
    110. tail = new;
    111. }
    112. void initSnake()
    113. {
    114. struct Snake *p;
    115. dir = RIGHT;
    116. while(head != NULL){
    117. p = head;
    118. head = head->next;
    119. free(p);
    120. }
    121. initFood();
    122. head = (struct Snake *)malloc(sizeof(struct Snake));
    123. head->hang = 1;
    124. head->lie = 1;
    125. head->next = NULL;
    126. tail = head;
    127. addNode();
    128. addNode();
    129. addNode();
    130. addNode();
    131. }
    132. void deletNode()
    133. {
    134. struct Snake *p;
    135. p = head;
    136. head = head->next;
    137. free(p);
    138. }
    139. void moveSnake()
    140. {
    141. addNode();
    142. if(hasFood(tail->hang,tail->lie)){
    143. initFood();
    144. }else{
    145. deletNode();
    146. }
    147. if(tail->hang < 0 || tail->lie == 0 || tail->hang == 20 || tail->lie == 20){
    148. initSnake();
    149. }
    150. }
    151. void* refreshJieMian()
    152. {
    153. while(1){
    154. moveSnake();
    155. gamPic();
    156. refresh();
    157. usleep(100000);
    158. }
    159. }
    160. void turn(int direction)
    161. {
    162. if(abs(dir) != abs(direction)){
    163. dir = direction;
    164. }
    165. }
    166. void* changeDir()
    167. {
    168. while(1){
    169. key = getch();
    170. switch(key){
    171. case KEY_DOWN:
    172. turn(DOWN);
    173. break;
    174. case KEY_UP:
    175. turn(UP);
    176. break;
    177. case KEY_LEFT:
    178. turn(LEFT);
    179. break;
    180. case KEY_RIGHT:
    181. turn(RIGHT);
    182. break;
    183. }
    184. }
    185. }
    186. int main()
    187. {
    188. pthread_t t1;
    189. pthread_t t2;
    190. initNcurse();
    191. initSnake();
    192. gamPic();
    193. pthread_create(&t1, NULL, refreshJieMian, NULL);
    194. pthread_create(&t2, NULL, changeDir, NULL);
    195. while(1);
    196. getch();
    197. endwin();
    198. return 0;
    199. }

    七、项目代码

    1. #include
    2. #include
    3. #include
    4. #define UP 1
    5. #define DOWN -1
    6. #define LEFT 2
    7. #define RIGHT -2
    8. struct Snake{
    9. int hang;
    10. int lie;
    11. struct Snake *next;
    12. };
    13. struct Snake *head = NULL;
    14. struct Snake *tail = NULL;
    15. struct Snake food;
    16. int key;
    17. int dir;
    18. void addNode(); /*从尾部插入新节点*/
    19. //void initNcurses(); /*ncurses库的初始化函数*/
    20. //void gameMap(); /*贪吃蛇地图的初始化*/
    21. //int printSnakeNode(int i,int j); /*在地图上打印贪吃蛇的节点*/
    22. //void initSnake(); /*初始化贪吃蛇*/
    23. //void deletNode(); /*删除头结点*/
    24. //void moveSnake(); /*实现贪吃蛇的移动*/
    25. //void *refreshScreen(); /*线程实现图像刷新*/
    26. //void *changeDir(); /*线程实现贪吃蛇方向的改变*/
    27. //void turn(int direction); /*防止出现不合理走位*/
    28. //void creatFood(); /*随机出现食物*/
    29. //int hasFood(int i,int j); /*打印食物*/
    30. //int ifSnakeDie(); /*判断贪吃蛇是否死亡*/
    31. /*随机出现食物*/
    32. void creatFood()
    33. {
    34. int x = rand()%20;
    35. int y = rand()%19+1;
    36. food.hang = x;
    37. food.lie = y;
    38. }
    39. int hasFood(int i,int j)
    40. {
    41. if(food.hang == i && food.lie == j){
    42. return 1;
    43. }
    44. return 0;
    45. }
    46. /*ncurses库的初始化函数*/
    47. void initNcurses()
    48. {
    49. initscr();//ncurse界面的初始化函数
    50. keypad(stdscr,1);//使用keypad函数,才可以使用键盘功能键
    51. noecho();//防止打印无关键值
    52. }
    53. /*贪吃蛇地图的初始化*/
    54. void gameMap()
    55. {
    56. int hang;
    57. int lie;
    58. move(0,0);//把光标的位置移到头,实现地图刷新时的覆盖
    59. for(hang=0;hang<20;hang++){
    60. if(hang == 0){
    61. for(lie=0;lie<20;lie++){
    62. printw("--");
    63. }
    64. printw("\n");
    65. }
    66. if(hang>=0 && hang<=19){
    67. for(lie=0;lie<=20;lie++){
    68. if(lie == 0 || lie == 20){
    69. printw("|");
    70. }else if(printSnakeNode(hang,lie)){
    71. printw("[]");
    72. }else if(hasFood(hang,lie)){
    73. printw("##");
    74. }else{
    75. printw(" ");
    76. }
    77. }
    78. printw("\n");
    79. }
    80. if(hang == 19){
    81. for(lie=0;lie<20;lie++){
    82. printw("--");
    83. }
    84. printw("\n");
    85. }
    86. }
    87. printw("By ShiYaHao!,food.hang = %d,food.lie = %d\n",food.hang,food.lie);
    88. }
    89. /*在地图上打印贪吃蛇的节点*/
    90. int printSnakeNode(int i,int j)
    91. {
    92. struct Snake *p = head;
    93. while(p != NULL){
    94. if(p->hang == i && p->lie == j){
    95. return 1;
    96. }
    97. p = p->next;
    98. }
    99. return 0;
    100. }
    101. /*初始化贪吃蛇*/
    102. void initSnake()
    103. {
    104. struct Snake *p = NULL;
    105. if(head != NULL){ //当贪吃蛇死亡后,把多余节点释放
    106. p = head;
    107. head = head->next;
    108. free(p);
    109. }
    110. creatFood();
    111. dir = RIGHT;
    112. head = (struct Snake *)malloc(sizeof(struct Snake));
    113. head->hang = 1;
    114. head->lie = 1;
    115. head->next = NULL;
    116. tail = head;
    117. addNode();
    118. addNode();
    119. addNode();
    120. }
    121. /*从尾部插入新节点*/
    122. void addNode()
    123. {
    124. struct Snake *new = (struct Snake *)malloc(sizeof(struct Snake));
    125. switch(dir){
    126. case UP:
    127. new->hang = tail->hang-1;
    128. new->lie = tail->lie;
    129. break;
    130. case DOWN:
    131. new->hang = tail->hang+1;
    132. new->lie = tail->lie;
    133. break;
    134. case LEFT:
    135. new->hang = tail->hang;
    136. new->lie = tail->lie-1;
    137. break;
    138. case RIGHT:
    139. new->hang = tail->hang;
    140. new->lie = tail->lie+1;
    141. break;
    142. }
    143. new->next = NULL;
    144. tail->next = new;
    145. tail = new;
    146. }
    147. /*删除头结点*/
    148. void deletNode()
    149. {
    150. struct Snake *p = head;
    151. head = head->next;
    152. free(p);
    153. }
    154. /*判断贪吃蛇是否死亡*/
    155. int ifSnakeDie()
    156. {
    157. struct Snake *p;
    158. p = head;
    159. if(tail->hang < 0 || tail->hang == 20 || tail->lie == 0 || tail->lie == 20){
    160. return 1;
    161. }
    162. while(p->next != NULL){
    163. if(p->hang == tail->hang && p->lie == tail->lie){
    164. return 1;
    165. }
    166. p = p->next;
    167. }
    168. return 0;
    169. }
    170. /*实现贪吃蛇的移动*/
    171. void moveSnake()
    172. {
    173. addNode();
    174. if(hasFood(tail->hang,tail->lie)){
    175. creatFood();
    176. }else{
    177. deletNode();
    178. }
    179. if(ifSnakeDie()){
    180. initSnake();
    181. }
    182. }
    183. /*线程实现图像刷新*/
    184. void *refreshScreen()
    185. {
    186. usleep(100000);
    187. while(1){
    188. moveSnake();
    189. gameMap();//刷新地图
    190. refresh();//界面刷新函数
    191. usleep(100000);
    192. }
    193. }
    194. /*防止不合理走位*/
    195. void turn(int direction)
    196. {
    197. if(abs(dir) != abs(direction)){
    198. dir = direction;
    199. }
    200. }
    201. /*线程实现贪吃蛇方向的改变*/
    202. void *changeDir()
    203. {
    204. while(1){
    205. key = getch();
    206. switch(key){
    207. case KEY_UP:
    208. turn(UP);
    209. break;
    210. case KEY_DOWN:
    211. turn(DOWN);
    212. break;
    213. case KEY_LEFT:
    214. turn(LEFT);
    215. break;
    216. case KEY_RIGHT:
    217. turn(RIGHT);
    218. break;
    219. }
    220. }
    221. }
    222. int main()
    223. {
    224. pthread_t t1;
    225. pthread_t t2;
    226. initNcurses();
    227. initSnake();
    228. gameMap();
    229. pthread_create(&t1,NULL,refreshScreen,NULL);
    230. pthread_create(&t2,NULL,changeDir,NULL);
    231. while(1);
    232. getch();//等待用户的输入,如果没有这句话,程序就退出了,看不到运行的结果,也就是无法看到上面那句话
    233. endwin();//程序退出,恢复shell终端的显示,如果没有这句话,shell终端字乱码,坏掉
    234. return 0;
    235. }

  • 相关阅读:
    基于QT实现的图形软件图片编辑器
    使用scroll-view实现滑块视图可能遇到的问题及其解决方法
    c++获取当前时间的字符串
    C/S架构学习之使用epoll实现TCP特大型并发服务器
    Zabbix自动监控windows端口(主动监控方式)
    SSM框架整合
    常用的二十种设计模式(上)-C++
    idea2023根据表自动生成+springboot跑起来
    Stage #14 XSS注入:利用CSS内联注释突破防御
    Python数据结构:列表(list)、元组(tuple)、字典(dict)
  • 原文地址:https://blog.csdn.net/weixin_54859557/article/details/132948307