再来一次的C语言贪吃蛇小游戏(二)
5.游戲地圖
貪吃蛇的游戲地圖由一個(gè)個(gè)方格組成,每一格方格可以表示地面,墻,食物,蛇的身體等等,蛇只能在地面上行動(dòng),吃到食物則生長(zhǎng)一節(jié)蛇身,撞到墻就GG。
我們可以同樣可以使用枚舉來(lái)表示地圖上的不同物體
//game.h typedef enum stuff_mark {wall_mark,ground_mark,food_mark,snake_mark }Stuff_Mark;為了便于表示我們創(chuàng)建一個(gè)物品結(jié)構(gòu)體,用來(lái)保存地圖上每個(gè)物理的位置,和物體的類別
//game.h typedef struct stuff {int pos_x;int pos_y;Stuff_Mark mark; }Stuff;這樣一來(lái)整個(gè)游戲的表示框架就定好了。
//game.h //游戲當(dāng)前狀態(tài) typedef enum state {in_menu,gaming,to_quit }State;//WIDTH, HEIGHT為宏定義的地圖寬高,根據(jù)喜好設(shè)置 struct game {int score;Stuff map[HEIGHT][WIDTH];Stuff *food;State state; };為什么要單獨(dú)保存食物在游戲結(jié)構(gòu)體中呢?map中不是保存了地圖上所有相關(guān)信息嗎?不急,預(yù)計(jì)下下一篇揭曉哈。
關(guān)于游戲中的操作,暫時(shí)我們定義操作行為可以有:
- 上移:move_up,對(duì)應(yīng)w鍵
- 下移:move_down,對(duì)應(yīng)s鍵
- 左移:move_left,對(duì)應(yīng)a鍵
- 右移:move_right,對(duì)應(yīng)d鍵
- 退出:esc,對(duì)應(yīng)Esc鍵
- 無(wú)操作:no_option
為了對(duì)操作進(jìn)行規(guī)范,我們也定義為枚舉類型
//game.h typedef enum option {move_up = 'w',move_left = 'a',move_down = 's',move_right = 'd',esc = 27,no_option = 0 }Option;6. 初始化游戲,在win32控制臺(tái)顯示出來(lái)
關(guān)于游戲中要展示的物體,我們都已經(jīng)定義好了,那么怎么樣展示出來(lái)呢?
//game.h void start_game(); void init_map(struct game* Game); void display_map(struct game* Game); void display_snake(struct game *Game, Snake *snake); void display_mark(Stuff *stuff); void grow_food(struct game*Game); void snake_move(struct game*Game, Snake* snake, Direction dir); void judge_move_input(struct game*Game, Snake* snake, int* input, int* last_input);首先解釋一下這個(gè)display_mark這個(gè)方法,這個(gè)方法的唯一功能就是在一個(gè)物體所在的地方,輸出表示該物體的符號(hào),通過(guò)調(diào)用此方法,我們可以展示游戲中的所有內(nèi)容,set_cursor_positon,set_console_color分別實(shí)我自定義的控制臺(tái)函數(shù),用來(lái)設(shè)置控制臺(tái)輸出位置和顏色。相關(guān)代碼在本系列(三)所提供的源碼中。
//game.c void display_mark(Stuff *stuff) {set_cursor_position(stuff->pos_x, stuff->pos_y);switch (stuff->mark){case wall_mark:set_console_color(6, 0);printf("##");break;case ground_mark:set_console_color(7, 0);printf(" ");break;case food_mark:set_console_color(4, 0);printf("@");break;case snake_mark:set_console_color(2, 0);printf("■");break;default:break;} }游戲初始化操作
//game.h void init_map(struct game* Game) {for (int i = 0; i < WIDTH; i++) {for (int j = 0; j < HEIGHT; j++){Game->map[j][i].pos_x = i;Game->map[j][i].pos_y = j;if (j == 0 || j == HEIGHT-1 || i==0 || i==WIDTH-1){Game->map[j][i].mark = wall;}else Game->map[j][i].mark = ground;}} }void grow_food(struct game* Game) {int pos_x = rand() % WIDTH;int pos_y = rand() % HEIGHT;Stuff *stuff = &Game->map[pos_y][pos_x];stuff->mark = food_mark;Game->food = stuff;display_mark(stuff); }void display_snake(struct game*Game, Snake *snake) {Snake_Body_Node *head = snake->head;Stuff *stuff;while (head->next_node != head){stuff = &Game->map[head->pos_y][head->pos_x];stuff->mark = snake_mark;display_mark(stuff);}stuff = &Game->map[head->pos_y][head->pos_x];stuff->mark = snake_mark;display_mark(stuff); }當(dāng)蛇移動(dòng)的時(shí)候,我們?cè)诓僮魃叩逆湵頃r(shí)并沒(méi)有改變?nèi)康墓?jié)點(diǎn),同時(shí)我們?cè)陲@示蛇的時(shí)候,也沒(méi)有必要更新所有蛇身的顯示,我們只需要更新頭尾的顯示即可
void snake_move(struct game*Game, Snake* snake, Direction dir) {Stuff *stuff;int pos_x = snake->head->pos_x;int pos_y = snake->head->pos_y;pos_x = dir == left ? pos_x - 1 : dir == right ? pos_x + 1 : pos_x;pos_y = dir == up ? pos_y - 1 : dir == down ? pos_y + 1 : pos_y;switch (Game->map[pos_y][pos_x].mark){case ground_mark:stuff = &Game->map[pos_y][pos_x];stuff->mark = snake_mark;display_mark(stuff);stuff = &Game->map[snake->head->previous_node->pos_y][snake->head->previous_node->pos_x];stuff->mark = ground_mark;display_mark(stuff);move(snake, dir, pos_x, pos_y);break;case food_mark:stuff = &Game->map[pos_y][pos_x];stuff->mark = snake_mark;display_mark(stuff);eat(snake, dir, pos_x, pos_y);grow_food(Game);Game->score++;case snake_mark:exit(1);break;case wall_mark:exit(1);break;default:break;} }最初效果如下:■■■■表示蛇,@表示食物
7. 游戲控制
關(guān)于操作的定義,我們已經(jīng)在上文中說(shuō)明了,但是在具體控制中,還有部分細(xì)節(jié)問(wèn)題要處理
總的游戲循環(huán)如下
void start_game() {struct game *Game = (struct game*)malloc(sizeof(struct game));Snake *snake = new_born_snake(5, 5);Game->score = 0;Game->state = gaming;init_map(Game);display_map(Game);display_snake(Game, snake);grow_food(Game);int input = no_option;int last_input = no_option;while (Game->state == gaming){if (_kbhit()){input = _getch();FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));}else input = no_option;switch (input){case move_up:case move_right:case move_down:case move_left:judge_move_input(Game, snake, &input, &last_input);break;case esc:Game->state = back_to_menu;break;case no_option:default:snake_move(Game, snake, snake->head->dir);break;}}free(Game); }8.游戲菜單實(shí)現(xiàn)
下一篇鏈接
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的再来一次的C语言贪吃蛇小游戏(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 再来一次的C语言贪吃蛇小游戏(一)
- 下一篇: 再来一次的C语言贪吃蛇小游戏(三)