大概一年前这时候,接触C语言一个月,那时候知之甚少,对面向对象只觉”可远观而不可亵玩“,而且会看到很多言论说C语言就是面向过程的语言,C++就是面向对象的语言。不过,不记得什么时候在网上看到过一篇博文,大概是说如何优雅的写C语言。其中颇有印象的就是通过结构的函数指针模拟C++中的类。
今天粗略尝试了一下,写的是之前写过的贪吃蛇。的确,用面向对象的思维写让我的思维变的更加清晰,因为这个游戏(以及大多数显示事物)的天然属性就是对象。
此外,这次从最关键最核心的写起,如此写起来真是越写越轻松。因为如果关键部分写不出来,其他写的再好也没用。所以这次的顺序大概是:能移动的蛇--->能吃食物并变长--->能判断自己是否死亡--->其他修饰功能。
最后,调试无误后。在发布代码前写了写注释。发现自己现在命名编码规范了不少,所以注释也并不多。曾经看到一种观点就是,注释关键部分就足够了,最好的注释就是良好的命名习惯、编码风格和清晰的逻辑。
不过,由于没有太多的规划,都是自己在路上零散构思的,代码还是不够紧凑,逻辑还可以优化。
头文件
1 #ifndef _HEAD_H_
2 #define _HEAD_H_
3 #include <stdio.h>
4 #include <windows.h>//
5 int Score = -1;
6 typedef struct node1
7 {
8 int x;
9 int y;
10 struct node1 *next;
11 }SnakeBody;
12 typedef struct node2
13 {
14 int x;
15 int y;//location
16 char Status;
17 char Direction;
18 void (*MoveUp)(struct node2 *);
19 void (*MoveDown)(struct node2 *);
20 void (*MoveRight)(struct node2 *);
21 void (*MoveLeft)(struct node2 *);
22 void (*GrowUp)(struct node2 *);
23 int (*IsDie)(struct node2 *);
24 SnakeBody *next;
25 }SnakeHead;
26 void HideCursor()
27 {
28 CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
29 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
30 }
31 void SetPosition(int x, int y)
32 {
33 COORD pos;
34 HANDLE hOutput;
35 pos.X = x;
36 pos.Y = y;
37 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
38 SetConsoleCursorPosition(hOutput, pos);
39 }
40 void Print(SnakeHead *H)
41 {
42 SetPosition(H->x, H->y);
43 printf("@");//mean snake head
44 SnakeBody *temp = H->next;
45 while(NULL != temp)
46 {
47 SetPosition(temp->x, temp->y);
48 printf("+");//means snake body
49 temp = temp->next;
50 }
51 }
52 void Move(SnakeHead *H)
53 {
54 SnakeBody *temp = H->next;
55 while (NULL != temp->next->next)
56 {
57 temp = temp->next;
58 }
59 temp->next->next = H->next;
60 H->next = temp->next;
61 SetPosition(temp->next->x, temp->next->y);
62 printf(" ");
63 temp->next = NULL;
64 H->next->x = H->x;
65 H->next->y = H->y;
66 }
67 void _MoveUp(SnakeHead *H)
68 {
69 Move(H);
70 H->y--;
71 }
72 void _MoveDown(SnakeHead *H)
73 {
74 Move(H);
75 H->y++;
76 }
77 void _MoveRight(SnakeHead *H)
78 {
79 Move(H);
80 H->x++;
81 }
82 void _MoveLeft(SnakeHead *H)
83 {
84 Move(H);
85 H->x--;
86 }
87 void _GrowUp(SnakeHead *H)
88 {
89 SnakeBody *temp = (SnakeBody *)malloc(sizeof(SnakeBody));
90 temp->x = H->x;
91 temp->y = H->y;
92 temp->next = H->next;
93 H->next = temp;
94 switch (H->Direction)
95 {
96 case 'U':
97 {
98 H->y--;
99 break;
100 }
101 case 'D':
102 {
103 H->y++;
104 break;
105 }
106 case 'L':
107 {
108 H->x--;
109 break;
110 }
111 case 'R':
112 {
113 H->x++;
114 break;
115 }
116 default:
117 {
118 break;
119 }
120 }
121 Print(H);
122 }
123 const int Left = 3;
124 const int Right = 34;
125 const int Top = 3;
126 const int Bottom = 27;
127 void BuildWall()
128 {
129 for (int x = Left; x <= Right; x++)
130 {
131 SetPosition(x, Top);
132 printf("-");
133 SetPosition(x, Bottom);
134 printf("-");
135 }
136 for (int y = Top; y <= Bottom; y++)
137 {
138 SetPosition(Left, y);
139 printf("|");
140 SetPosition(Right, y);
141 printf("|");
142 }
143 //some hint
144 SetPosition(15, 1);
145 printf("Snake");
146 SetPosition(20, 2);
147 printf("zhaoyu");
148 SetPosition(37, 7);
149 printf("F1:Slow Down");
150 SetPosition(37, 9);
151 printf("F2:Speed Up");
152 SetPosition(37, 11);
153 printf("F3:Speed Up++");
154 SetPosition(37, 15);
155 printf("Score:");
156 }
157 void CreateFood(int *x, int *y, SnakeHead *H)
158 {
159 int flag = 1;
160 int i = 0, j = 0;
161 //make sure in the wall && not on snake
162 SnakeBody *temp = H->next;
163 while (1 == flag)
164 {
165 i = rand()%30;
166 i += 4;
167 j = rand()%24;
168 j += 4;
169 flag = 0;
170 if (i == H->x && j == H->y)
171 {
172 flag = 1;
173 continue;
174 }
175 temp = H->next;
176 while (NULL != temp)
177 {
178 if (i == temp->x && j == temp->y)
179 {
180 flag = 1;
181 break;
182 }
183 temp = temp->next;
184 }
185 }
186
187 *x = i;
188 *y = j;
189 SetPosition(i, j);
190 printf("$");//dollar mead food!
191 SetPosition(45, 15);
192 //once food created ,score plus 1
193 printf("%d", ++Score);
194 }
195 int Die(SnakeHead *H)
196 {
197 //out the wall will die
198 if (H->x <= Left || H->x >= Right || H->y >= Bottom || H->y <= Top)
199 {
200 return 1;//die
201 }
202 // crush into itself will die
203 SnakeBody *temp = H->next;
204 while (NULL !=temp)
205 {
206 if (H->x == temp->x && H->y == temp->y)
207 {
208 return 1;
209 }
210 temp = temp->next;
211 }
212 // 0 mean not die
213 return 0;
214 }
215 #endif
源文件
1 #include "head.h"
2
3
4 void StartGame()
5 {
6 //Create a snake
7 SnakeBody *temp = (SnakeBody *)malloc(sizeof(SnakeBody));
8 SnakeHead *Head = (SnakeHead *)malloc(sizeof(SnakeHead));
9 Head->Direction = 'L';
10 Head->Status = 1;
11 Head->x = 10;
12 Head->y = 10;
13 //assign some functions to snake
14 Head->MoveUp = _MoveUp;
15 Head->MoveDown = _MoveDown;
16 Head->MoveRight = _MoveRight;
17 Head->MoveLeft = _MoveLeft;
18 Head->GrowUp = _GrowUp;
19 Head->IsDie = Die;
20 temp->x = 11;
21 temp->y = 10;
22 temp->next = NULL;
23 Head->next = temp;
24 // create snake body
25 for (int i = 0; i < 5; i++)
26 {
27 SnakeBody *move = (SnakeBody *)malloc(sizeof(SnakeBody));
28 move->x = temp->x + 1;
29 move->y = temp->y;
30 temp->next = move;
31 temp = move;
32 move->next = NULL;
33 }
34 //Init food
35 int Foodx = 0, Foody = 0;
36 CreateFood(&Foodx, &Foody, Head);
37 int Speed = 10;
38 while (1 == Head->Status)
39 {
40 //print the snake
41 Print(Head);
42 //judge is or not die
43 if((*Head->IsDie)(Head))
44 {
45 break;
46 }
47 //get direction
48 if(GetAsyncKeyState(VK_UP) && 'D' != Head->Direction)
49 {
50 Head->Direction = 'U';
51 }
52 else if (GetAsyncKeyState(VK_DOWN) && 'U' != Head->Direction)
53 {
54 Head->Direction = 'D';
55 }
56 else if (GetAsyncKeyState(VK_RIGHT) && 'L' != Head->Direction)
57 {
58 Head->Direction = 'R';
59 }
60 else if (GetAsyncKeyState(VK_LEFT) && 'R' != Head->Direction)
61 {
62 Head->Direction = 'L';
63 }
64 //move
65 switch (Head->Direction)
66 {
67 case 'U':
68 {
69 //judge is there a food
70 if (Head->x == Foodx && Head->y - 1 == Foody)
71 {
72 (*Head->GrowUp)(Head);
73 CreateFood(&Foodx, &Foody, Head);
74 }
75 else//Just move
76 {
77 (*Head->MoveUp)(Head);
78 }
79 break;
80 }
81 case 'D':
82 {
83 if (Head->x == Foodx && Head->y + 1 == Foody)
84 {
85 (*Head->GrowUp)(Head);
86 CreateFood(&Foodx, &Foody, Head);
87 }
88 else
89 {
90 (*Head->MoveDown)(Head);
91 }
92 break;
93 }
94 case 'R':
95 {
96 if (Head->x + 1 == Foodx && Head->y == Foody)
97 {
98 (*Head->GrowUp)(Head);
99 CreateFood(&Foodx, &Foody, Head);
100 }
101 else
102 {
103 (*Head->MoveRight)(Head);
104 }
105
106 break;
107 }
108 case 'L':
109 {
110 if (Head->x - 1 == Foodx && Head->y == Foody)
111 {
112 (*Head->GrowUp)(Head);
113 CreateFood(&Foodx, &Foody, Head);
114 }
115 else
116 {
117 (*Head->MoveLeft)(Head);
118 }
119 break;
120 }
121 default:
122 {
123 break;
124 }
125 }
126 //control
127 if (GetAsyncKeyState(VK_F1) && Speed > 6)
128 {
129 Speed -= 5;
130 }
131 else if (GetAsyncKeyState(VK_F2) && Speed < 30)
132 {
133 Speed += 5;
134 }
135 else if (GetAsyncKeyState(VK_F3))
136 {
137 Speed += 10;
138 }
139 if ('L' == Head->Direction ||'R' == Head->Direction)
140 {
141 Sleep(1000/Speed);
142 }
143 else
144 {
145 Sleep(2000/Speed);
146 }
147 }
148 }
149 int main(int argc, char const *argv[])
150 {
151 //init
152 system("cls");
153 system("mode con cols=50 lines=30");//no space around equal sign
154 BuildWall();
155 HideCursor();
156 StartGame();
157 SetPosition(36, 20);
158 printf("Enter to exit!");
159 getchar();
160 return 0;
161 }
运行:
后记:
1、函数指针与函数名
函数名与函数指针都是一样的,即都是函数指针。函数名是一个函数指针常量,而函数指针是一个函数数指针变量。
一般的C语言书籍都不会谈及这些近乎奇淫技巧的东东。
2、GetAsyncKeyState函数
这个函数按下之后其状态会一直存在,我在写俄罗斯方块就大受其害。以下面代码为例。你只需要按一下F1就可以跳出循环了,而不是1000下。因为按下一次之后其状态就始终为真了,除非你按下别的键。
1 #include <stdio.h>
2 #include <windows.h>
3 int main(int argc, char const *argv[])
4 {
5 int i = 0;
6 while (1)
7 {
8 if (GetAsyncKeyState(VK_F1))
9 {
10 i++;
11 }
12 if (i >= 1000)
13 {
14 break;
15 }
16 }
17 printf("%dn", i);
18 return 0;
19 }
原文链接: https://www.cnblogs.com/zhaoyu1995/p/5447214.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/232664
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!