本文實例為大家分享了C語言實現打飛機小游戲的具體代碼,供大家參考,具體內容如下
編譯環境:vs2019
需求:
在同一個平面內,控制大炮發射的三個方向,空格發射炮彈,敵軍和友軍飛機會一直隨機在天上飛過,擊中天上飛行的敵軍飛機加一分,擊中友軍飛機減一分
思路:
先初始化程序,再畫出說明和地圖,接著進入無限循環,循環中分別實現飛機不停地在天上飛、通過awd空格鍵控制游戲內容、符合游戲條件時加分三個主要步驟。
做法:
首先要實現飛機的動畫效果,本質是要在控制臺上輸出三條x軸上輸出一個字符串,并要讓這三個字符串看起來在同時移動。這里我借助了寫賭馬大賽的經驗:在第一次無限循環內分別循環輸出第1、2、3條的字符串表示走出第一步,然后再自增三個字符串x軸坐標數值,第二次無限循環清除上一次字符串移動痕跡,并再分別輸出三條字符串,表示走出第二步。由于內層for循環沒有休眠函數,這樣看起來就是三個字符串同時移動的效果。這樣就可以通過無限循環表示三架飛機不停地移動了。
接下來是通過getch函數改變大炮炮口指向方向(一個字符),在炮口指向切換的同時,炮彈初始化的位置也同樣會改變,當按下空格時,炮彈(一個字符)會從他的初始化位置沿設定好的路線不停移動,當橫縱軸坐標與飛機坐標相匹配時判斷是否為敵軍飛機|—0>,是則得分加一,否則得分減一。
此外程序里還有很多細節,這里不一一贅述。
難點:
看起來讓三個字符串同時移動。這是一種算法,學會了就應該應該像記住基礎知識一樣牢牢記住他。明白了原理之后,比較容易掌握。
說明:
這是一個簡單的小程序,實現該程序中相同的效果有著很多種方法,而我則大量地使用了數組來存放、統計和使用各種不同的數據,其實類似效果還可以通過單鏈表來實現。在我目前的認知中使用數組和直接輸出字符串的寫法有著簡潔明了的優點。但同時也導致出一個顯示效果上比較致命的缺陷。
注意:
由于編譯器原因程序中_kbhit()和_getch()函數可能在其他編譯器上編譯會出現錯誤,解決辦法是去掉函數前面的 “_”。
運行效果:
代碼實現:
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
|
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <windows.h> #include <time.h> #include <string.h> void HideCursor(); //隱藏光標 void gotoxy( int x, int y); //光標定位 #define R 26 //飛機每次隨機尾x坐標最大值 #define N 20 //通關分數 int ax[3] = { 0 }; //三個飛機尾坐標,全局 int y[3] = { 3,7,11 }; //三個y軸,全局,查表法確定飛機的y軸位置 //因為炮彈的飛行距離是一次加兩個格子,為了奇偶對應這里的y軸必須都是偶數 int i; //循環用變量 int fd[3]; //控制飛機種類 void cshcxhs() //初始化函數 { system ( "title 打飛機小游戲" ); //標題 system ( "mode con cols=100 lines=30" ); //寬100,高30 HideCursor(); //光標隱藏 gotoxy(46, 12); //介紹游戲規則 printf ( "游戲規則:" ); gotoxy(36, 14); printf ( "w a d鍵控制方向,空格鍵發射炮彈" ); gotoxy(26, 16); printf ( "擊中敵軍飛機 |---0> 加一分,擊中友軍飛機 >>>>>> 減一分" ); gotoxy(40, 18); printf ( "累計得分 %d 結束游戲" ,N); Sleep(2800); system ( "cls" ); int k; //循環用變量 gotoxy(40, R); //初始化炮臺 for (k = 0; k < 17; k++) printf ( "_" ); gotoxy(46, R); printf ( "[_O_]" ); gotoxy(48, 25); //中間x:48 printf ( "|" ); int j; srand ((unsigned) time (NULL)); //初始化隨機種子 for (j = 0; j < 3; j++) //初始化飛機的初始x坐標,寫在循環之外 { ax[j] = rand () % R; fd[j] = rand () % 2; } gotoxy(0, R); printf ( " 得分:" ); //分數x坐標9 } void hcfjhs() //畫出飛機函數 { gotoxy(ax[i], y[i]); //首先在飛機尾處輸出整架飛機 if (fd[i] == 1) printf ( "|---0>" ); else printf ( ">>>>>>" ); gotoxy(ax[i] - 1, y[i]); //清除飛機尾部留下的痕跡 printf ( " " ); ax[i]++; //然后飛機尾坐標自增,下次自飛機尾輸出整架飛機 } void dhpdxshs() //畫出飛機,并讓飛機在飛過x94的時候消失 { for (i = 0; i < 3; i++) //每架飛機都走一步 { hcfjhs(); if (ax[i] + 6 >= 94) //判斷每架飛機頭有沒有超過94 { gotoxy(94, y[i]); //滿足條件在每架飛機的94處輸出空格 printf ( " " ); if (ax[i]+6 > 100) //每架飛機的飛機頭超過100,則重置一個隨機數 { ax[i] = rand () % R; //修改為小于R的隨機數 fd[i] = rand () % 2; } } } } int da = 2; //da = 1為最左 默認中間 炮臺方向,全局變量 int yip = 0; //是否開炮,0不開,1,2,3三個方向 int rtde = 1; //是否發射完畢,必須等待炮彈發射完成 int shells_x; //炮彈坐標 int shells_y; void ckkzhs() { char ch; ch = _getch(); if (ch == 'd' || ch == 'D' ) { gotoxy(49, 25); printf ( "/" ); //炮臺右轉 gotoxy(47, 25); printf ( " " ); da = 3; //最右狀態 } if (ch == 'A' || ch == 'a' ) { gotoxy(47, 25); printf ( "\\" ); //轉義轉義字符 gotoxy(48, 25); printf ( " " ); da = 1; //最左狀態 } if (ch == 'W' || ch == 'w' ) { gotoxy(48, 25); printf ( "|" ); gotoxy(47, 25); printf ( " " ); gotoxy(49, 25); printf ( " " ); da = 2; } if (ch == ' ' && rtde == 0) //大炮處于發射完畢狀態,且按下空格 { if (da == 2) //中 炮臺朝向 yip = 2; if (da == 1) //左 { yip = 1; shells_x = 45; //初始化炮彈的坐標 } if (da == 3) //右 { yip = 3; shells_x = 51; } shells_y = 23; //初始化炮彈的坐標 } } void dpfshs() //向三個不同方向發射炮彈 { rtde = 1; //循環,炮彈移動時代表未開炮完畢 if (yip == 2) { shells_x = 48; gotoxy(shells_x, shells_y-=2); printf ( "o" ); gotoxy(shells_x, shells_y+2); printf ( " " ); } if (yip == 1) { gotoxy(shells_x-=2, shells_y-=2); printf ( "o" ); gotoxy(shells_x+2, shells_y+2); printf ( " " ); } if (yip == 3) { gotoxy(shells_x+=2, shells_y-=2); printf ( "o" ); gotoxy(shells_x-2, shells_y+2); printf ( " " ); } if (shells_y <= 1) //炮彈越界,消除炮彈 { yip = 0; //炮彈越界,炮彈停下 gotoxy(48, 1); //并消除 printf ( " " ); gotoxy(23, 1); printf ( " " ); gotoxy(73, 1); printf ( " " ); rtde = 0; //炮彈越界,開炮完畢,可進行下一輪開炮 } } int score; //得分 void pdfsjzhs() //判斷是否擊中和統計信息 { for (i = 0; i < 3; i++) { if (shells_x >= ax[i] && shells_x <= ax[i] + 6 && shells_y == y[i]) //擊中時 { if (fd[i]==1) score++; //擊中一次,得分加一 else { score--; if (score <= 0) score = 0; } rtde = 0; //擊中時,開炮完成 gotoxy(ax[i]-1, y[i]); //擊中后,在原飛機尾巴處消除飛機 printf ( " " ); ax[i] = rand () % R; //修改為小于10的隨機數 fd[i] = rand () % 2; //飛機種類發生變化 gotoxy(shells_x, shells_y); //在擊中飛機的地方輸出空格消除炮彈尸體 printf ( " " ); shells_x = 0, shells_y = 0; //炮彈擊中飛機,炮彈越界,下一次空格將自動初始化炮彈 } } gotoxy(9, R); printf ( "%d" ,score); if (score >= N) //游戲結束判斷 { system ( "cls" ); //清屏 gotoxy(39,15); printf ( "您通關了,最終得分:%d !" , N); gotoxy(0, 29); exit (0); } } void process() //流程 { while (1) { dhpdxshs(); //飛機動畫函數 if (_kbhit()) { ckkzhs(); //操作函數 } dpfshs(); //大炮效果函數 pdfsjzhs(); //判斷是否擊中和統計信息 Sleep(18); } } int main() { cshcxhs(); //初始化程序 process(); //流程 return 0; } void HideCursor() { CONSOLE_CURSOR_INFO cursor_info = { 1, 0 }; SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); } void gotoxy( int x, int y) { COORD pos = { x,y }; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); } |
不足之處:
我在程序中輸出飛機時使用了在飛機尾直接輸出整架飛機,飛機尾x坐標自增的寫法,這是一種很笨但又很簡單的做法。這種做法導致飛機在飛過控制臺最大寬度的同時無法逐個消除飛機機身,飛機頭一旦越過控制臺最大寬度就會出現程序輸出錯誤,所以我為了保留“讓飛機逐節身體地飛出邊界”這個讓飛機消失時看起來比較自然的效果,只好用最后飛機所在y軸最后6個x軸格子作為遮擋飛機的板子,以此來實現類似的效果。
由于該程序出了創意之外,全是由本人靠自己寫的,由于我能力有限,在寫這個程序的同時隱約感覺到我的程序存在著大量代碼復用性、結構嚴謹性、運行效率低下上的問題,同時很多函數和變量標識符我采用了瞎寫、中文拼音組成的做法。
作為一名c語言新手,我對未知的知識始終抱有學習和謙卑的態度,如有貴人能夠對我的程序提出復用性、嚴謹性、運行效率上的建議,我將不勝感激。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/qq_46239972/article/details/104125838