C语言之贪吃蛇(ncurses)

声明: 以下内容可能会引起某些读者不适, 请小心阅读. 有些内容并没有详细介绍, 可能简单理解也是错误的, 但是这都是为了尽量简单。

前言: 代码是很久之前写的,属于边想边写的那种,很混乱。

推荐材料:



贪吃蛇应该是我们这代人都玩过的游戏。而如果我们要写一个贪吃蛇最需要考虑的就是贪吃蛇是如何移动的。其实贪吃蛇的移动就是尾部的减少和头部的增加。

这篇文章:

  • 介绍一些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

时间: 2024-10-12 15:21:44

C语言之贪吃蛇(ncurses)的相关文章

C语言实现贪吃蛇之结构链表篇

之前的两篇博客将运用的C语言知识限定在了一般的数组上,但如果已经完整地了解过C语言的话,运用结构和链表会让程序的结构更明了,逻辑更清晰.这篇博客就将介绍如何用结构和链表改善之前的程序. 首先,我们为蛇的节点定义一个结构: typedef struct node{ COORD cor; struct node *next; }node; COORD结构我在上一篇已经介绍过,这里就直接借用了. COORD food = { 3,5 }; node *head; food也相应地由COORD来定义,并

C语言实现贪吃蛇之全靠数组篇

贪吃蛇游戏的设计思路很简单,相信有过一些编程经验的同学都不至于束手无策,可在我刚刚接触编程时,这个小小的贪吃蛇游戏可是让我费了不少脑筋,如今学习编程已经快一年了,前几天又看了一遍K&R,打算写几个贪吃蛇程序巩固一下知识.我打算写若干篇贪吃蛇的博客,从简单粗糙的开始,不断改良,希望能给初学C语言的同学一点借鉴. 话不多说,我们现在就开始吧,首先我们整理一下思路.首先我们要明确,既然贪吃蛇游戏理论上可以无限继续下去,那么游戏主体一定就是一个循环.蛇的移动就在这个循环中完成.如果是初学编程的话,可能会

C语言之贪吃蛇(curses库函数)

上大学学习编程的初始目的就是冲着游戏来的~不过在刚学习C语言的时候,完全无法利用所学知识弄出一个可玩的游戏╮(╯_╰)╭,学了1年后仍然对最简单的贪吃蛇没有思路(当然不是说没有打代码的思路,而是没有办法弄出动态的东西,而且当时往算法那走了~),直到如今大二,利用寒假的一点时间入门Linux的时候,发现了curses库函数!当我看明白它的作用时,拍案而起,TM这玩意不就是我梦寐以求的可实现界面的东东么!当我学了一点点就觉悟到,用一个move()和printw()函数就完全可以把贪吃蛇这种级别的写出

C语言实现贪吃蛇之图形界面篇

这已经是贪吃蛇系列的第五篇了,讲真一直写这个也挺无聊的,所以这一篇博文将是系列的最后一篇.虽然已经介绍了贪吃蛇的几种写法,但说到底我们的游戏还只是在一个黑框框里移动的星号.和我们平时玩的贪吃蛇游戏有不少差距.游戏嘛,画面也是很重要的一环.接下来就是让之前的贪吃蛇游戏脱胎换骨的时候了.话不多说,这就开干吧. 首先,为了摆脱无趣的黑框(控制台),我们这次新建一个win32项目,直接点击完成.初次接触win32项目的同学可能会感到一股扑面而来的伤害,满屏都是意义不明的字符,这TM还是C语言吗!先不要沮

C语言实现贪吃蛇

日期:2018.9.11 用时:150min 项目:贪吃蛇(C语言--数组   结构体实现) 开发工具:vs2013 关键知识:数组,结构体,图形库,键位操作 源代码: 1 #include<stdio.h> 2 #include<graphics.h> 3 #include<stdlib.h> 4 #include<conio.h> 5 #include<time.h> 6 7 #define N 200 8 int i, key; 9 int

C语言之贪吃蛇(conio.h)

写完基于Linux中curses库的贪吃蛇,发现只需要用到一个WIN的API(移动光标那个)改写move(int y, int x)函数,然后加上conio.h(一般编译器都会包含这个头文件)的getch(),就可以在Windows系统运行! Linux版链接:http://blog.csdn.net/u013351484/article/details/43940803 游戏规则: 初始时两条蛇会在中间,一条蛇头是'@',食物是'$':另一条蛇头是'+',食物是'*',蛇身都是'#'.WASD

C语言实现贪吃蛇之局部刷新篇

上一篇博客里,我介绍了如何用数组存储坐标,不断全屏刷新以实现动态效果,这几乎是最显而易见的思路,但带来的副作用也十分明显,那就是始终伴随着游戏的闪烁现象,之所以会造成闪烁现象,原因在于频繁的清空与打印,其实贪吃蛇游戏里我们并不需要重打印整个界面,要实现蛇的移动,我们只要打印出新的蛇头,清除原来的蛇尾就好了.食物只有在被吃掉时才需要重新打印,边界更是只用打印一次.好了,既然我们看到了可提升的地方,就开始动手优化吧.显然,我们将需要一个可以自由移动光标的函数,这样我们才能做到在需要的地方打印.TC上

C语言之贪吃蛇

利用链表的贪吃蛇,感觉自己写的时候还是有很多东西不熟悉, 1.预编译 2.很多关于系统的头文件也不是很熟悉 3.关于内存 第一个是.h头文件 #ifndef _SNAKE_H_H_H #define _SNAKE_H_H_H //调节游戏界面大小,这里设置为15*15 int const COL=15; int const ROW=15; //蛇结点 typedef struct Node { //data域 int x; int y; //指针域 struct Node* pre; struc

架构练习:c语言实现贪吃蛇(三):封装蛇的移动方法

目前进展: 封装蛇的移动方法: typedef struct snakeinfo { int numParts;/* how many parts,蛇身体分多少个段 */ int lenParts[GAME_WIDTH];/* 蛇身体每段的长度 */ int xPartsHead[GAME_WIDTH];/* 蛇身体第i段的x坐标,初始值为1 */ int yPartsHead[GAME_WIDTH];/* 蛇身体第i段的y坐标,初始值为1 */ uchar direction;/* 蛇当前在像