# 程式設計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

## 小錯誤
* 這個程式碼還有一點點bug,我一直不知道在哪裡出錯,有時候子彈會穿過障礙物。
* 有時候也會連續消除兩個障礙物。
* 如果可以,希望劉明機教授或者助教們可以教我找出這個bug。謝謝你們!