Fork me on GitHub

C语言用面向对象的思想写贪吃蛇

  大概一年前这时候,接触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("%d\n", i);
18     return 0;
19 }

 

  

posted @ 2016-04-29 17:48  赵裕(vimerzhao)  阅读(618)  评论(0编辑  收藏  举报