Try   HackMD

程式設計III 小恐龍專題

原本程式碼:

#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;
}

修改後的程式碼:

#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;
}

修改+增加的部分

天空
for (int i = 0; i < ROAD_LENGTH; i++) {
    printf("_");
}
  • 利用了路的原理製造了一個天空。
障礙物
struct barrier {
    int position;
    struct barrier* next;
};
typedef struct barrier Barrier;

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;
// 移動路面和放置障礙物
        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';
        }
Barrier* temp_barrier = MyDino->barriers;
    while (temp_barrier != NULL)
    {
        Barrier* current_barrier = temp_barrier;
        temp_barrier = temp_barrier->next;
        free(current_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;
void display(Dino* MyDino, Bullet* bullets)
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]);
            }
        }
    }
// 玩家射擊子彈
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;
}
// 檢查子彈是否擊中障礙物
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;
    }
}
// 釋放動態分配的記憶體
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。謝謝你們!