打小球游戏(Brick & Ball)最终完美版:C语言实现

这是一个用C语言编写的简单游戏,灵感来源于Motorola Mobile C289中的类似游戏。这是作者的第一个真正的C语言程序,游戏包括砖块、球和挡板等元素,玩家通过移动挡板反弹球来击打砖块得分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1 /*
2 * Brick & Ball
3 * by Jerry Fleming <jerryfleming2006@gmail.com>
4 *
5 * This is a small game inspired from similar one in Motorola Mobile C289,
6 * and my first REAL program in C :) Please tell me if you have a better
7 * implementation or any suggestions.
8 *
9 * HISTORY:
10 * 2006-10-25: third (current) version with c language
11 * 2006-10-01: second version with tkinter
12 * 2006-04-19: first version with curses
13 *
14 * TODO:
15 * Nothing to do right now. :) If you have any ideas to improve or enhance it,
16 * please contact me.
17 */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <ncurses.h>
22 #include <stdlib.h> /* for exit(), rand(), abs() */
23 #include <stddef.h> /* for NULL */
24 #include <unistd.h> /* for sleep() */
25 #include <signal.h> /* for SIGWINCH */
26 #include <assert.h> /* for DEBUG */
27
28 #define NORMAL 1 /* status of game */
29 #define PAUSE 2
30 #define OVER 3
31 #define QUIT 4
32 #define BLOCK 1 /* color pairs */
33 #define TXT 2
34 #define BAR 3
35 #define BALL 4
36 #define CLEAR 5
37
38 /*
39 * globals
40 */
41 int speed = 10;
42 int cnt = 0; /* bricks yet remain on board */
43 int score = 0;
44 int level = 0;
45 int width = 40;
46 int height = 50; /* for the board */
47 short state = NORMAL; /* see define */
48 char *statestr = "Normal"; /* additional str to explain the game status */
49 const int bw = 7; /* brick width */
50 const char brick[] = " ";
51 int bricks[100][3];
52 int pad;
53 int ball[2];
54 int dir[2] = { 1, -1 };
55 int ch = 0; /* user command */
56
57 /*
58 * text strings {{{
59 */
60 const char *tStart[] = {
61 " ______ _ _ ___ ______ _ _ ",
62 " (____ // (_) | | / _ // (____ // | | | ",
63 " ____) ) ____ _ ____| | _ ( (_) ) ____) )_____| | | ",
64 " | __ ( / ___) |/ ___) |_/ ) ) _ ( | __ ((____ | | | ",
65 " | |__) ) | | ( (___| _ ( ( (/ // | |__) ) ___ | | | ",
66 " |______/|_| |_|//____)_| //_) //__///_) |______///_____|//_)_) ",
67 " ",
68 " ",
69 " ",
70 " by Jerry Fleming <jerryfleming2006@gmail.com> ",
71 " ",
72 " ",
73 " GAME STARTING! PRESS ANY KEY TO GO ON ... ",
74 " ",
75 " ------------------------------------------------------------ ",
76 "| P: Pause / Resume <-, ->: Move Right / Left Y:Yes N: No | ",
77 " ------------------------------------------------------------ ",
78 ""
79 };
80
81 const char *tExit[] = {
82 " 88888 88888",
83 "88888888888 88 ad88888ba 88 8b d8 d8 88",
84 "88 /"/" ,d d8/" /"8b 88 Y8, ,8P ,8P' 88",
85 "88 88 /"/" a8P 88 Y8, ,8P d8/" 88",
86 "88aaaaa 8b, ,d8 88 MM88MMM ,a8P/" 88 /"8aa8/" ,8P' 8b,dPPYba, 88",
87 "88/"/"/"/"/" `Y8, ,8P' 88 88 d8/" 88 `88' d8/" 88P' `/"8a 88",
88 "88 )888( 88 88 /"/" 88 88 ,8P' 88 88 88",
89 "88 ,d8/" /"8b, 88 88, aa 88 88 d8/" 88 88 88",
90 "88888888888 8P' `Y8 88 /"Y888 88 88 88 8P' 88 88 88",
91 " 88888 88888",
92 ""
93 };
94
95 const char *tOver[] = {
96 " ,ad8888ba, 88",
97 " d8/"' `/"8b 88",
98 "d8' 88",
99 "88 ,adPPYYba, 88,dPYba,,adPYba, ,adPPYba, ,adPPYba, 8b d8 ,adPPYba, 8b,dPPYba, 88",
100 "88 88888 /"/" `Y8 88P' /"88/" /"8a a8P_____88 a8/" /"8a `8b d8' a8P_____88 88P' /"Y8 88",
101 "Y8, 88 ,adPPPPP88 88 88 88 8PP/"/"/"/"/"/"/" 8b d8 `8b d8' 8PP/"/"/"/"/"/"/" 88 /"/"",
102 " Y8a. .a88 88, ,88 88 88 88 /"8b, ,aa /"8a, ,a8/" `8b,d8' /"8b, ,aa 88 aa",
103 " `/"Y88888P/" `/"8bbdP/"Y8 88 88 88 `/"Ybbd8/"' `/"YbbdP/"' /"8/" `/"Ybbd8/"' 88 88",
104 ""
105 };
106
107 const char *tGoon[] = {
108 " 88888 88888",
109 " ,ad8888ba, ad88888ba 88 8b d8 d8 88",
110 " d8/"' `/"8b d8/" /"8b 88 Y8, ,8P ,8P' 88",
111 "d8' /"/" a8P 88 Y8, ,8P d8/" 88",
112 "88 ,adPPYba, ,adPPYba, 8b,dPPYba, ,a8P/" 88 /"8aa8/" ,8P' 8b,dPPYba, 88",
113 "88 88888 a8/" /"8a a8/" /"8a 88P' `/"8a d8/" 88 `88' d8/" 88P' `/"8a 88",
114 "Y8, 88 8b d8 8b d8 88 88 /"/" 88 88 ,8P' 88 88 88",
115 " Y8a. .a88 /"8a, ,a8/" /"8a, ,a8/" 88 88 aa 88 88 d8/" 88 88 88",
116 " `/"Y88888P/" `/"YbbdP/"' `/"YbbdP/"' 88 88 88 88 88 8P' 88 88 88",
117 " 88888 88888",
118 ""
119 };
120
121 const char *tHelp =
122 "Use left and right arrow keys to move the pad and bounce the ball so that it won't hit the ground. Hit the brick and score.";
123 /*
124 * string variables }}}
125 */
126
127 /*
128 * change sceen size, exit if too small
129 */
130 void resizescr(int sig)
131 {
132 statestr = "Screen resized.";
133 getmaxyx(stdscr, height, width);
134 } /* resizescr() */
135
136 /*
137 * print msg on center of screen
138 * y_n_key: exit on pressing Y or N (key is true) or any char (key false)
139 * clearmsg: clear the msg window (when 1, or 2 and Y, or 3 and N)
140 */
141 bool print_msg(const char *msg[], const bool y_n_key, const int clearmsg)
142 {
143 WINDOW *txtwin = NULL;
144 int length = 0;
145 int tmplength = 0;
146 int line = 0;
147 int i;
148 int left;
149 int top;
150 char emptymsg[width];
151
152 for (;;) {
153 tmplength = strlen(msg[line]);
154 if (tmplength == 0)
155 break;
156 if (length < tmplength)
157 length = tmplength;
158 line++;
159 }
160 assert(length < width);
161 assert(line != 0);
162 top = (height - line) / 2;
163 left = (width - length) / 2;
164 txtwin = newwin(line, length, top, left);
165 wattrset(txtwin, COLOR_PAIR(TXT));
166 assert(txtwin != NULL);
167 for (i = 0; i < line; i++) {
168 mvwaddstr(txtwin, i, 0, msg[i]);
169 }
170 wrefresh(txtwin);
171
172 timeout(3000);
173 for (;;) {
174 ch = getch();
175 if (y_n_key)
176 break;
177 else {
178 if (ch == ERR || ch == 'y' || ch == 'Y') {
179 ch = 'Y';
180 break;
181 }
182 if (ch == 'n' || ch == 'N') {
183 ch = 'N';
184 break;
185 }
186 }
187 }
188
189 if (clearmsg == 1
190 || (clearmsg == 2 && ch == 'Y')
191 || (clearmsg == 3 && ch == 'N')
192 ) {
193 for (i = 0; i < length; i++)
194 emptymsg[i] = ' ';
195 wattrset(txtwin, COLOR_PAIR(TXT));
196 for (i = 0; i < line; i++) {
197 mvwaddstr(txtwin, i, 0, emptymsg);
198 }
199 wrefresh(txtwin);
200 delwin(txtwin);
201 }
202 i = ch, ch = 0; /* clear input for later use */
203 timeout(100);
204
205 if (i == 'N')
206 return FALSE;
207 return TRUE;
208 } /* print_msg() */
209
210 /*
211 * draw pad, ball, bricks, and bar together
212 */
213 void draw_board(void)
214 {
215 int i, j;
216 char barstr[width];
217
218 level++;
219 cnt = 0;
220 dir[0] = 1, dir[1] = -1;
221
222 /* brick */
223 i = width % (bw + 1) / 2; /* width -1 + gap */
224 j = 1;
225 attrset(COLOR_PAIR(BLOCK));
226 for (;;) {
227 mvaddstr(j, i, brick);
228 bricks[cnt][0] = i;
229 bricks[cnt][1] = j;
230 bricks[cnt][2] = 1;
231 i = i + bw + 1;
232 cnt++;
233 if (i >= width - bw) {
234 if (cnt > 50)
235 break;
236 i = width % (bw + 1) / 2;
237 j += 2;
238 }
239 }
240 bricks[cnt][2] = -1; /* mark the end or all bricks */
241
242 if (level == 1) {
243 /* pad */
244 attrset(COLOR_PAIR(BLOCK));
245 pad = rand() % (width - bw - 1);
246 mvaddstr(height - 2, pad, brick);
247
248 /* bar */
249 for (i = 0; i < width; i++)
250 barstr[i] = ' ';
251 attrset(COLOR_PAIR(BAR));
252 mvaddstr(height - 1, 0, barstr);
253 mvprintw(height - 1, 0, "SCORE: %03d LEVEL: %d STATE: %-9s", score,
254 level, statestr);
255 }
256
257 /* ball */
258 attrset(COLOR_PAIR(BALL));
259 ball[0] = pad, ball[1] = height - 3;
260 while (abs(ball[0] - pad) < 15)
261 ball[0] = rand() % (width - bw - 1);
262 mvaddstr(ball[1], ball[0], " ");
263
264 refresh();
265 } /* draw_board() */
266
267 /*
268 * try to stop game
269 */
270 void quit_game(const int ch)
271 {
272 if (ch == 'q') {
273 if (cnt < 0 /* do not want another level */
274 || (cnt > 0 && print_msg(tExit, FALSE, 3)) /* really meant to
275 * exit */
276 ) {
277 state = QUIT;
278 statestr = "Quit game";
279 }
280 } else if (ch == 'o') {
281 state = OVER;
282 statestr = "Game over";
283 print_msg(tOver, TRUE, 0);
284 } else if (state == PAUSE) {
285 state = NORMAL;
286 statestr = "Normal";
287 } else {
288 state = PAUSE;
289 statestr = "Pause";
290 }
291 /* bar */
292 attrset(A_NORMAL | COLOR_PAIR(BAR));
293 mvprintw(height - 1, 0, "SCORE: %03d LEVEL: %d STATE: %-9s", score, level,
294 statestr);
295 refresh();
296 } /* quit_game() */
297
298 /*
299 * move the ball forward, turn if necessary, add scores, and quite if hit ground
300 */
301 void move_ball()
302 {
303 int i;
304 int tmpball[] = { ball[0], ball[1] };
305
306 if (state != NORMAL)
307 return;
308
309 /* ball */
310 attrset(A_REVERSE | COLOR_PAIR(BALL));
311 mvaddstr(ball[1], ball[0], " ");
312 /* restore pad after hit */
313 attrset(A_NORMAL | COLOR_PAIR(BLOCK));
314 mvaddstr(height - 2, pad, brick);
315 tmpball[0] += dir[0], tmpball[1] += dir[1];
316
317 /* change direction */
318 if (tmpball[1] < 0)
319 dir[1] = -dir[1];
320 if (tmpball[0] < 0 || tmpball[0] > width)
321 dir[0] = -dir[0];
322
323 /* hit bricks */
324 attrset(A_REVERSE | COLOR_PAIR(BLOCK));
325 for (i = 0;; i++) {
326 if (bricks[i][2] == -1)
327 break;
328 if (bricks[i][2] == 0)
329 continue;
330 if (bricks[i][0] <= tmpball[0]
331 && bricks[i][0] + bw >= tmpball[0]
332 && bricks[i][1] == tmpball[1]
333 ) {
334 bricks[i][2] = 0;
335 /*
336 * tricky: make sure the direction is top-down
337 */
338 dir[1] = abs(dir[1]);
339 score += 10;
340 cnt--;
341 refresh();
342 mvaddstr(bricks[i][1], bricks[i][0], brick);
343 if (cnt <= 0) { /* another level */
344 if (print_msg(tGoon, FALSE, 2)) {
345 draw_board();
346 } else {
347 quit_game('q');
348 }
349 }
350 }
351 }
352
353 /* hit pad */
354 if (tmpball[1] == height - 2) {
355 if (tmpball[0] < pad || tmpball[0] > pad + bw)
356 quit_game('o');
357 /*
358 * for some reason, the ball may enter the pad, and change dir will not
359 * get it out, so use abs() to turn back
360 */
361 dir[1] = -abs(dir[1]);
362 if (tmpball[0] == pad || tmpball[0] == pad + bw) { /* on both ends */
363 dir[0] = -dir[0];
364 }
365 }
366
367 /* bar */
368 attrset(A_NORMAL | COLOR_PAIR(BAR));
369 mvprintw(height - 1, 0, "SCORE: %03d LEVEL: %d STATE: %-9s", score, level,
370 statestr);
371
372 ball[0] += dir[0], ball[1] += dir[1];
373 attrset(A_NORMAL | COLOR_PAIR(BALL));
374 mvaddstr(ball[1], ball[0], " ");
375 refresh();
376 } /* move_ball() */
377
378 /*
379 * move pad to left or right according to command
380 */
381 int move_pad(const int ch)
382 {
383 int move;
384
385 switch (ch) {
386 case KEY_LEFT:
387 move = -2;
388 break;
389 case KEY_RIGHT:
390 move = 2;
391 break;
392 case 'q':
393 quit_game(ch);
394 break;
395 case 'p':
396 quit_game(ch);
397 break;
398 default:
399 return 0;
400 }
401 attrset(A_REVERSE | COLOR_PAIR(BLOCK));
402 mvaddstr(height - 2, pad, brick);
403 pad = pad + move;
404 if (pad < 0)
405 pad = 0;
406 if (pad > width - bw)
407 pad = width - bw;
408 attrset(A_NORMAL | COLOR_PAIR(BLOCK));
409 mvaddstr(height - 2, pad, brick);
410
411 refresh();
412 return 0;
413 } /* move_pad() */
414
415 /*
416 * main
417 */
418 int main(void)
419 {
420 initscr();
421 start_color();
422 init_pair(BLOCK, COLOR_BLACK, COLOR_RED); /* for bricks and pad */
423 init_pair(TXT, COLOR_CYAN, COLOR_BLACK); /* for text strings */
424 init_pair(BAR, COLOR_WHITE, COLOR_BLUE); /* for bar */
425 init_pair(BALL, COLOR_BLACK, COLOR_WHITE); /* for ball */
426 noecho();
427 raw(); /* disable line buffering */
428 timeout(100);
429 cbreak();
430 keypad(stdscr, TRUE);
431 curs_set(0);
432 getmaxyx(stdscr, height, width);
433 signal(SIGWINCH, resizescr);
434
435 if (height >= 20 && width >= 80) {
436 refresh();
437 print_msg(tStart, TRUE, 0);
438 clear();
439 draw_board();
440 for (;;) {
441 ch = getch();
442 move_ball();
443 if (ch != ERR)
444 move_pad(ch);
445 if (state == OVER || state == QUIT)
446 break;
447 }
448 } else { /* screen too small, exit with complaint */
449 state = QUIT;
450 statestr = "Screen too small. Game aborted.";
451 }
452 refresh();
453 sleep(1), flash();
454 sleep(1), flash();
455 sleep(1), flash();
456 curs_set(1);
457 keypad(stdscr, FALSE);
458 nocbreak();
459 notimeout(stdscr, TRUE);
460 noraw();
461 echo();
462 endwin();
463 puts(statestr);
464 exit(0);
465 } /* main() */
466
467 /*
468 * Local variables:
469 * tab-width: 4
470 * indent-tabs-mode: nil
471 * c-basic-offset: 4
472 * End:
473 * VIM: tw=80:sw=4:sts=4:fdm=marker
474 */
在C语言中设计这样的游戏界面并利用Visual Studio作为开发环境,你需要了解基本的图形用户界面(GUI)操作和游戏循环结构。以下是一个简化的示例,展示了如何开始编写这样的程序: ```c #include &lt;stdio.h&gt; #include &lt;conio.h&gt; // 这里用于键盘输入 // 定义屏幕大小和游戏元素 #define SCREEN_WIDTH 80 #define SCREEN_HEIGHT 20 #define PADDLE_WIDTH 5 #define BALL_RADIUS 2 #define BRICK_SIZE 3 typedef struct { int x; int y; } Block; void draw_paddle(int paddle_x) { for (int i = 0; i &lt; PADDLE_WIDTH; i++) { printf(&quot;|&quot;); } printf(&quot; %d &quot;, paddle_x); } void draw_ball(int ball_x, int ball_y) { printf(&quot;@&quot;); } void draw_brick(Block brick) { for (int i = 0; i &lt; BRICK_SIZE; i++) { printf(&quot;*&quot;); } } void game_loop() { int paddle_x = 0; int ball_x = SCREEN_WIDTH / 2 - BALL_RADIUS; int ball_y = SCREEN_HEIGHT - 2 * BALL_RADIUS; while (true) { // 更新输入处理 if (_kbhit()) { char key = _getch(); if (key == &#39;A&#39;) { paddle_x--; } else if (key == &#39;D&#39;) { paddle_x++; } } // 检查边界和碰撞 if (ball_x &lt;= 0 || ball_x &gt;= SCREEN_WIDTH - BALL_RADIUS) { ball_y -= 2; } if (ball_y &lt;= 0) { ball_y = 1; } // 碰到挡板或其他物体的逻辑 if (ball_x + BALL_RADIUS == paddle_x + PADDLE_WIDTH || ball_y == paddle_x) { ball_y += 1; } // 打砖块逻辑(这里简化,实际可能需要遍历所有砖块) if (ball_x + BALL_RADIUS &gt; brick.x &amp;&amp; ball_x &lt; brick.x + BRICK_SIZE &amp;&amp; ball_y + BALL_RADIUS &gt; brick.y &amp;&amp; ball_y &lt; brick.y + BRICK_SIZE) { brick.x = -BRICK_SIZE; // 将砖块移出屏幕表示消失 } // 绘制当前状态 clear_screen(); // 清除上一轮画面 draw_paddle(paddle_x); draw_ball(ball_x, ball_y); for (Block block : bricks) { // 假设bricks是一个砖块数组 draw_brick(block); } refresh(); // 刷新显示 } } int main() { Block bricks[] = {...}; // 初始化砖块位置 game_loop(); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值