# 程式設計III 小恐龍專題 ## 原本程式碼: ```c #include<stdio.h> #include<stdlib.h> #include<stdbool.h> #include<windows.h> #include<time.h> #define ROAD_LENGTH 50 //路面長度 #define DINO_PLACE 6 //小恐龍在路面上的第幾格 struct dino { char road[ROAD_LENGTH + 1];//字串結尾需要'\0' int jump_time_left; //還剩多久掉回地面 int score; //分數 int wait_time; //每次迴圈之間等待的時間 int barrier_chance; //放置障礙物的機率 }; typedef struct dino Dino; bool space_pressed(void) { return _kbhit() != 0 && _getch() == 32; } void move(Dino* MyDino) { for (int i = 0; i < ROAD_LENGTH - 1; i++) { MyDino->road[i] = MyDino->road[i + 1]; } MyDino->road[ROAD_LENGTH - 1] = '_'; } Dino* init(void) { Dino* MyDino = (Dino*)malloc(sizeof(Dino)); if (MyDino != NULL) { MyDino->score = 0; MyDino->jump_time_left = 0; MyDino->wait_time = 150; MyDino->barrier_chance = 10; for (int i = 0; i < ROAD_LENGTH; i++) { MyDino->road[i] = '_'; } MyDino->road[ROAD_LENGTH] = '\0'; } return MyDino; } void display(Dino* MyDino) { system("cls"); printf("\n\n\t"); for (int i = 0; i < ROAD_LENGTH; i++) { if (i == DINO_PLACE && MyDino->jump_time_left > 0) printf("O"); else printf(" "); } printf("\n\t"); for (int i = 0; i < ROAD_LENGTH; i++) { if (i == DINO_PLACE && MyDino->jump_time_left == 0) printf("O"); else printf("%c", MyDino->road[i]); } printf("\n\n\n\t"); printf("\t\tyour score is : %d\n", MyDino->score); return; } bool is_bumped(Dino* MyDino) { return MyDino->jump_time_left == 0 && MyDino->road[DINO_PLACE] == 'X'; } bool spawn_barrier(Dino* MyDino) { int random_number = rand() % 100; if (random_number < MyDino->barrier_chance) return true; return false; } int main() { /* 初始化 */ srand(time(NULL)); Dino* MyDino = init(); display(MyDino); /* 遊戲本體 */ while (true) { /* 邏輯運算 */ if (space_pressed() && MyDino->jump_time_left == 0) { MyDino->jump_time_left = 7; } move(MyDino); if (spawn_barrier(MyDino)) { MyDino->road[ROAD_LENGTH - 1] = 'X'; } if (MyDino->jump_time_left > 0) MyDino->jump_time_left -= 1; if (is_bumped(MyDino)) { display(MyDino); break; } /* 渲染呈現 */ display(MyDino); MyDino->score++; Sleep(MyDino->wait_time); } return 0; } ``` ## 修改後的程式碼: ```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <windows.h> #include <time.h> #define ROAD_LENGTH 50 //路面長度 #define DINO_PLACE 6 //小恐龍在路面上的第幾格 struct barrier { int position; struct barrier* next; }; typedef struct barrier Barrier; struct bullet { int position; struct bullet* next; }; typedef struct bullet Bullet; struct dino { char road[ROAD_LENGTH + 1]; // 字串結尾需要 '\0' int jump_time_left; // 還剩多久掉回地面 int score; // 分數 int wait_time; // 每次迴圈之間等待的時間 int barrier_chance; // 放置障礙物的機率 Bullet* bullets; // 儲存子彈的位置 Barrier* barriers; // 儲存障礙物的位置 }; typedef struct dino Dino; bool space_pressed(void) { return _kbhit() != 0 && _getch() == 32; } void move(Dino* MyDino) { for (int i = 0; i < ROAD_LENGTH - 1; i++) { MyDino->road[i] = MyDino->road[i + 1]; } MyDino->road[ROAD_LENGTH - 1] = '_'; } Dino* init(void) { Dino* MyDino = (Dino*)malloc(sizeof(Dino)); if (MyDino != NULL) { MyDino->score = 0; MyDino->jump_time_left = 0; MyDino->wait_time = 150; MyDino->barrier_chance = 20; for (int i = 0; i < ROAD_LENGTH; i++) { MyDino->road[i] = '_'; } MyDino->road[ROAD_LENGTH] = '\0'; MyDino->barriers = NULL; } return MyDino; } void display(Dino* MyDino, Bullet* bullets) { system("cls"); printf("Invincible Bullet Dinosaur\n"); printf("\n\n\n\t"); // 顯示天空 for (int i = 0; i < ROAD_LENGTH; i++) { printf("_"); } printf("\n\t"); // 顯示恐龍和路面 for (int i = 0; i < ROAD_LENGTH; i++) { if (i == DINO_PLACE && MyDino->jump_time_left > 0) printf("O"); else printf(" "); } printf("\n\t"); for (int i = 0; i < ROAD_LENGTH; i++) { bool has_bullet = false; bool has_barrier = false; if (bullets != NULL) { Bullet* current_bullet = bullets; while (current_bullet != NULL) { if (i == current_bullet->position) { has_bullet = true; // 檢查是否有障礙物 if (MyDino->road[i] == 'X') { Barrier* current_barrier = MyDino->barriers; Barrier* prev_barrier = NULL; // 找到最靠近子彈的障礙物 while (current_barrier != NULL && current_barrier->position < i) { prev_barrier = current_barrier; current_barrier = current_barrier->next; } if (prev_barrier == NULL) { MyDino->barriers = current_barrier->next; free(current_barrier); } else { prev_barrier->next = current_barrier->next; free(current_barrier); } MyDino->score += 10; MyDino->road[i] = '_'; } printf("o"); current_bullet = current_bullet->next; continue; } current_bullet = current_bullet->next; } } if (!has_bullet) { if (MyDino->barriers != NULL) { Barrier* current_barrier = MyDino->barriers; while (current_barrier != NULL) { if (i == current_barrier->position) { has_barrier = true; printf("X"); break; } current_barrier = current_barrier->next; } } if (!has_barrier) { if (i == DINO_PLACE && MyDino->jump_time_left == 0) printf("O"); else printf("%c", MyDino->road[i]); } } } printf("\n\n\n\t"); printf("\t\tYour score is ---->>>> %d\n", MyDino->score); } bool is_bumped(Dino* MyDino) { return MyDino->jump_time_left == 0 && MyDino->road[DINO_PLACE] == 'X'; } bool spawn_barrier(Dino* MyDino) { int random_number = rand() % 100; if (random_number < MyDino->barrier_chance) return true; return false; } int main() { /* 初始化*/ srand(time(NULL)); Dino MyDino = init(); Bullet* bullets = NULL; display(MyDino, bullets); /* 遊戲本體 */ while (true) { /* 邏輯運算 */ // 玩家射擊子彈 if (space_pressed() && MyDino->jump_time_left == 0) { Bullet* new_bullet = (Bullet*)malloc(sizeof(Bullet)); new_bullet->position = DINO_PLACE + 1; new_bullet->next = bullets; bullets = new_bullet; } // 移動子彈 Bullet* current_bullet = bullets; Bullet* prev_bullet = NULL; while (current_bullet != NULL) { current_bullet->position += 2; // 子彈速度為恐龍速度的2倍 if (current_bullet->position >= ROAD_LENGTH) { // 超出螢幕範圍,刪除子彈 if (prev_bullet == NULL) { bullets = current_bullet->next; free(current_bullet); current_bullet = bullets; } else { prev_bullet->next = current_bullet->next; free(current_bullet); current_bullet = prev_bullet->next; } } else { prev_bullet = current_bullet; current_bullet = current_bullet->next; } } // 檢查是否撞到障礙物 if (MyDino->jump_time_left == 0 && MyDino->road[DINO_PLACE] == 'X') { display(MyDino, bullets); break; } // 移動路面和放置障礙物 move(MyDino); if (spawn_barrier(MyDino)) { Barrier* new_barrier = (Barrier*)malloc(sizeof(Barrier)); new_barrier->position = ROAD_LENGTH - 1; new_barrier->next = MyDino->barriers; MyDino->barriers = new_barrier; MyDino->road[ROAD_LENGTH - 1] = 'X'; } // 判斷是否遊戲結束 if (MyDino->jump_time_left > 0) { MyDino->jump_time_left -= 1; } // 檢查子彈是否擊中障礙物 current_bullet = bullets; prev_bullet = NULL; while (current_bullet != NULL) { bool hit_barrier = false; Barrier* current_barrier = MyDino->barriers; Barrier* prev_barrier = NULL; while (current_barrier != NULL) { if (current_bullet->position == current_barrier->position) { hit_barrier = true; if (prev_barrier == NULL) { MyDino->barriers = current_barrier->next; free(current_barrier); current_barrier = MyDino->barriers; } else { prev_barrier->next = current_barrier->next; free(current_barrier); current_barrier = prev_barrier->next; } break; } prev_barrier = current_barrier; current_barrier = current_barrier->next; } if (hit_barrier) { // 刪除子彈 if (prev_bullet == NULL) { bullets = current_bullet->next; free(current_bullet); current_bullet = bullets; } else { prev_bullet->next = current_bullet->next; free(current_bullet); current_bullet = prev_bullet->next; } } else { prev_bullet = current_bullet; current_bullet = current_bullet->next; } } // 檢查是否撞到障礙物 if (MyDino->jump_time_left == 0 && MyDino->road[DINO_PLACE] == 'X') { display(MyDino, bullets); break; } // 移動路面和放置障礙物 move(MyDino); if (spawn_barrier(MyDino)) { Barrier* new_barrier = (Barrier*)malloc(sizeof(Barrier)); new_barrier->position = ROAD_LENGTH - 1; new_barrier->next = MyDino->barriers; MyDino->barriers = new_barrier; MyDino->road[ROAD_LENGTH - 1] = 'X'; } // 判斷是否遊戲結束 if (MyDino->jump_time_left > 0) { MyDino->jump_time_left -= 1; } // 檢查子彈是否擊中障礙物 current_bullet = bullets; prev_bullet = NULL; while (current_bullet != NULL) { bool hit_barrier = false; Barrier* current_barrier = MyDino->barriers; Barrier* prev_barrier = NULL; while (current_barrier != NULL) { if (current_bullet->position == current_barrier->position) { hit_barrier = true; if (prev_barrier == NULL) { MyDino->barriers = current_barrier->next; free(current_barrier); current_barrier = MyDino->barriers; } else { prev_barrier->next = current_barrier->next; free(current_barrier); current_barrier = prev_barrier->next; } break; } prev_barrier = current_barrier; current_barrier = current_barrier->next; } if (hit_barrier) { // 刪除子彈s if (prev_bullet == NULL) { bullets = current_bullet->next; free(current_bullet); current_bullet = bullets; } else { prev_bullet->next = current_bullet->next; free(current_bullet); current_bullet = prev_bullet->next; } } else { prev_bullet = current_bullet; current_bullet = current_bullet->next; } } /* 渲染呈現 */ display(MyDino, bullets); MyDino->score++; Sleep(MyDino->wait_time); } // 釋放動態分配的記憶體 Bullet* temp_bullet = bullets; while (temp_bullet != NULL) { Bullet* current_bullet = temp_bullet; temp_bullet = temp_bullet->next; free(current_bullet); } Barrier* temp_barrier = MyDino->barriers; while (temp_barrier != NULL) { Barrier* current_barrier = temp_barrier; temp_barrier = temp_barrier->next; free(current_barrier); } free(MyDino); return 0; } ``` ## 修改+增加的部分 ##### 天空 ```c for (int i = 0; i < ROAD_LENGTH; i++) { printf("_"); } ``` * 利用了路的原理製造了一個天空。 ##### 障礙物 ```c struct barrier { int position; struct barrier* next; }; typedef struct barrier Barrier; ``` ```c struct dino { char road[ROAD_LENGTH + 1]; // 字串結尾需要 '\0' int jump_time_left; // 還剩多久掉回地面 int score; // 分數 int wait_time; // 每次迴圈之間等待的時間 int barrier_chance; // 放置障礙物的機率 Bullet* bullets; // 儲存子彈的位置 Barrier* barriers; // 儲存障礙物的位置 }; typedef struct dino Dino; ``` ```c // 移動路面和放置障礙物 move(MyDino); if (spawn_barrier(MyDino)) { Barrier* new_barrier = (Barrier*)malloc(sizeof(Barrier)); new_barrier->position = ROAD_LENGTH - 1; new_barrier->next = MyDino->barriers; MyDino->barriers = new_barrier; MyDino->road[ROAD_LENGTH - 1] = 'X'; } ``` ```c Barrier* temp_barrier = MyDino->barriers; while (temp_barrier != NULL) { Barrier* current_barrier = temp_barrier; temp_barrier = temp_barrier->next; free(current_barrier); } ``` * 這些都是增加子彈後,障礙物新的設定。 * 有障礙物和子彈重疊的效果、障礙物和小恐龍重疊的效果、障礙物和子彈重疊後會如何等等。 ##### 子彈 ```c struct bullet { int position; struct bullet* next; }; typedef struct bullet Bullet; ``` ```c struct dino { char road[ROAD_LENGTH + 1]; // 字串結尾需要 '\0' int jump_time_left; // 還剩多久掉回地面 int score; // 分數 int wait_time; // 每次迴圈之間等待的時間 int barrier_chance; // 放置障礙物的機率 Bullet* bullets; // 儲存子彈的位置 Barrier* barriers; // 儲存障礙物的位置 }; typedef struct dino Dino; ``` ```c void display(Dino* MyDino, Bullet* bullets) ``` ```c Bullet* current_bullet = bullets; while (current_bullet != NULL) { if (i == current_bullet->position) { has_bullet = true; // 檢查是否有障礙物 if (MyDino->road[i] == 'X') { Barrier* current_barrier = MyDino->barriers; Barrier* prev_barrier = NULL; // 找到最靠近子彈的障礙物 while (current_barrier != NULL && current_barrier->position < i) { prev_barrier = current_barrier; current_barrier = current_barrier->next; } if (prev_barrier == NULL) { MyDino->barriers = current_barrier->next; free(current_barrier); } else { prev_barrier->next = current_barrier->next; free(current_barrier); } MyDino->score += 10; MyDino->road[i] = '_'; } printf("o"); current_bullet = current_bullet->next; continue; } current_bullet = current_bullet->next; } } if (!has_bullet) { if (MyDino->barriers != NULL) { Barrier* current_barrier = MyDino->barriers; while (current_barrier != NULL) { if (i == current_barrier->position) { has_barrier = true; printf("X"); break; } current_barrier = current_barrier->next; } } if (!has_barrier) { if (i == DINO_PLACE && MyDino->jump_time_left == 0) printf("O"); else printf("%c", MyDino->road[i]); } } } ``` ```c // 玩家射擊子彈 if (space_pressed() && MyDino->jump_time_left == 0) { Bullet* new_bullet = (Bullet*)malloc(sizeof(Bullet)); new_bullet->position = DINO_PLACE + 1; new_bullet->next = bullets; bullets = new_bullet; } ``` ```c // 移動子彈 Bullet* current_bullet = bullets; Bullet* prev_bullet = NULL; while (current_bullet != NULL) { current_bullet->position += 2; // 子彈速度為恐龍速度的2倍 if (current_bullet->position >= ROAD_LENGTH) { // 超出螢幕範圍,刪除子彈 if (prev_bullet == NULL) { bullets = current_bullet->next; free(current_bullet); current_bullet = bullets; } else { prev_bullet->next = current_bullet->next; free(current_bullet); current_bullet = prev_bullet->next; } } else { prev_bullet = current_bullet; current_bullet = current_bullet->next; } } ``` ```c // 檢查是否撞到障礙物 if (MyDino->jump_time_left == 0 && MyDino->road[DINO_PLACE] == 'X') { display(MyDino, bullets); break; } ``` ```c // 檢查子彈是否擊中障礙物 current_bullet = bullets; prev_bullet = NULL; while (current_bullet != NULL) { bool hit_barrier = false; Barrier* current_barrier = MyDino->barriers; Barrier* prev_barrier = NULL; while (current_barrier != NULL) { if (current_bullet->position == current_barrier->position) { hit_barrier = true; if (prev_barrier == NULL) { MyDino->barriers = current_barrier->next; free(current_barrier); current_barrier = MyDino->barriers; } else { prev_barrier->next = current_barrier->next; free(current_barrier); current_barrier = prev_barrier->next; } break; } prev_barrier = current_barrier; current_barrier = current_barrier->next; } if (hit_barrier) { // 刪除子彈 if (prev_bullet == NULL) { bullets = current_bullet->next; free(current_bullet); current_bullet = bullets; } else { prev_bullet->next = current_bullet->next; free(current_bullet); current_bullet = prev_bullet->next; } } else { prev_bullet = current_bullet; current_bullet = current_bullet->next; } } ``` ```c // 釋放動態分配的記憶體 Bullet* temp_bullet = bullets; while (temp_bullet != NULL) { Bullet* current_bullet = temp_bullet; temp_bullet = temp_bullet->next; free(current_bullet); } ``` * 子彈的部分是新加的。 * 我把space的功能本來是跳起來,然後被更換去射子彈。 * 我設定了子彈的速度是小恐龍的兩倍。所以會比小恐龍快。 * 當子彈和障礙物重疊時,子彈和障礙物會一起消失。 * 當子彈和障礙物消失時,會加10分。 ## Demo ![](https://i.imgur.com/hImnh1W.png) ## 小錯誤 * 這個程式碼還有一點點bug,我一直不知道在哪裡出錯,有時候子彈會穿過障礙物。 * 有時候也會連續消除兩個障礙物。 * 如果可以,希望劉明機教授或者助教們可以教我找出這個bug。謝謝你們!