两个吃奶一个添下面视频_人妻第一页香蕉网_欧美xxxx少妇_妺妺窝人体色www婷婷

一、項目介紹

這是一個彈幕射擊類小游戲(究極簡化版)。方向鍵控制移動,按住z鍵射擊,按住shift可以緩速移動,擊敗敵人取得勝利。

游戲C語言實現(xiàn)+easyX圖形繪制,視覺交互效果好,趣味性強。

 

編譯環(huán)境:visual c++ 6.0

第三方庫:Easyx2022

 

二、運行截圖

游戲操作提示

游戲界面

彈幕游戲2

游戲勝利


三、源碼解析

我們先思考游戲的流程。

在程序運行的開始,我們自然需要初始化。接著就是游戲的進(jìn)行過程,當(dāng)檢測到勝負(fù)已分時,給出提示,結(jié)束游戲。

 

在游戲過程中,所有的操作都需要得到實時的反饋。只要你輸入操作,游戲數(shù)據(jù)和畫面就會即時做出反應(yīng)。顯然我們需要用循環(huán)的方式,不斷地檢測輸入,處理游戲數(shù)據(jù)以及繪制圖像。

 

循環(huán)的頻率是根據(jù)游戲刷新頻率確定的,每經(jīng)過一小段時間,循環(huán)就會執(zhí)行一次,檢測玩家在這段時間按下了什么按鍵,然后判斷這些按鍵引起了移動方向的改變,還是子彈的發(fā)射,將這些結(jié)果寫入到游戲數(shù)據(jù)當(dāng)中,最后再刷新畫面,計算出下一幀界面應(yīng)該是什么樣子。

 

然后是程序中定義的函數(shù),變量及其功能。

void hp_bar();
void show_player();
void show_enemy();
void move_enemy();               //繪制一系列圖像
void draw_background();
int generate_line();                                // 若返回 -1,表示生成線條失敗
int create_p_b();                                    // 創(chuàng)建自機的子彈
int create_e_b();                                    // 創(chuàng)建敵機的子彈
int destroy_p_b(int index);
int destroy_e_b(int index);                           // 刪除一個子彈
#define FRAMERATE 20                                // 畫面刷新的周期(ms)
#define FIRERATE 350                                   // 射擊間隔時間
#define E_FIRERATE 350                               // 敵人射擊間隔
#define BLEED_TIME 150                             // 受傷閃爍時間
#define BACKGROUND 80                            // 繪制背景線條的周期
#define MAX_LINES 75                                 // 最多同屏背景線條數(shù)目
#define MAX_PLAYER_BULLETS 40              // 最多同屏自機子彈數(shù)目
#define MAX_ENEMY_BULLETS 40              // 最多同屏敵機子彈數(shù)目
 
int player_pos[2] = { 30,30 };                                      // 自機位置xy
int enemy_bullet[MAX_ENEMY_BULLETS][2];                         // 敵人的子彈位置
int player_bullet[MAX_PLAYER_BULLETS][2];                   // 自機的子彈位置
int enemy_pos[2] = { 580,240 };                                        // 敵機位置
bool p_b_slots[MAX_PLAYER_BULLETS] = { false };           // 用于判斷 player_bullet 的某個位置是否可用
bool e_b_slots[MAX_ENEMY_BULLETS] = { false };
int number_p_b = 0, number_e_b = 0;                             // 記錄自機和敵機的子彈數(shù),減少遍歷壓力
int player_health = 100, enemy_health = 100;
bool isBleeding_p = false, isBleeding_e = false;  // 用于實現(xiàn)命中后的閃爍效果
int background_line[MAX_LINES][3];                                // 背景的線條,三個參數(shù)分別是 x、y、長度
bool line_slots[MAX_LINES] = { false };
int number_lines = 0;                                                  // 記錄背景線條數(shù)目
clock_t begin_time = 0;

 

下面是主函數(shù)的源碼。由于相對來說較長,所以其中的一部分我會用文字來描述,具體的內(nèi)容會放在完整源碼當(dāng)中。

 

int main()
{
       initgraph(640, 550, 4);
       srand((unsigned)time(NULL));
       settextcolor(RGB(0, 254, 0));
       settextstyle(30, 0, "微軟雅黑");
       outtextxy(50, 200, "方向鍵移動, Z 攻擊, 左 Shift 切換低速模式");
       bool win = false, dead = false;
       clock_t firerate = clock();                                     // 射擊控制
       clock_t e_firerate = clock();                                 // 控制敵機的射擊
       clock_t runtime = clock();                                    // 用于控制畫面刷新頻率
       clock_t bleed_p = clock(), bleed_e = clock();       // 用于實現(xiàn)受傷閃爍
       clock_t backgroundline_generate = clock();        // 用于生成背景線條
       Sleep(3000);
       BeginBatchDraw();
       bool leftshift = false;
       begin_time = clock();
       return 0;
}

以上是初始化內(nèi)容。Initgraph()用來初始化繪圖區(qū)域,settextcolor用來改變字體顏色,outtextxy用于在指定位置輸出文字。BeginBatchDraw這個函數(shù)用于開始批量繪圖。執(zhí)行后,任何繪圖操作都將暫時不輸出到繪圖窗口上,直到執(zhí)行 FlushBatchDraw 或 EndBatchDraw 才將之前的繪圖輸出,這樣可以防止畫面不同步輸出。這幾個函數(shù)都來自easyx頭文件。

初始化中還用clock()函數(shù)進(jìn)行計時。Clock()返回值為clock_t類型,獲取進(jìn)程使用的cpu時間單元總數(shù)。等到某個時間點再次調(diào)用該函數(shù),就能得出從現(xiàn)在到那時,究竟過了多長時間。

   while (true)
       {
 
              if (clock() - runtime >= FRAMERATE)//只有當(dāng)距離處理上一幀過去了一定時間,才會開始下一次處理。
              {
                     runtime = clock();
                     cleardevice();//使用當(dāng)前背景色清空繪圖設(shè)備。
                     draw_background();//在本文件中定義,繪制背景
                     hp_bar();// 畫血條
                     show_player();;//在本文件中定義,繪制玩家
                     show_enemy();;//在本文件中定義,繪制敵人
 
                     int n_p_b = 1, n_e_b = 1;                              // 計數(shù),遍歷子彈,刷新位置
                     int p_b_toprocess = number_p_b, e_b_toprocess = number_e_b;       // 需要處理的子彈數(shù)
這里number_p_b和number_e_b分別是自機和敵機的子彈數(shù)目。為了保證游戲運行正常,可以給雙方的同屏彈幕數(shù)各設(shè)定一個上限,如果當(dāng)前的子彈超過了上限,則后續(xù)的子彈不生成。這一步的意思是讓這兩個變量繼承上一幀的子彈數(shù)目。
                     for (int i = 0; i < MAX_PLAYER_BULLETS && (n_p_b <= p_b_toprocess || n_e_b <= e_b_toprocess); ++i)//對每個子彈進(jìn)行處理,超出限制不處理
                     {
                            if (n_p_b <= p_b_toprocess)                         // 如果子彈已經(jīng)處理完就不處理了
                            {
                                   if (p_b_slots[i] == true)
                                   {
                                          ++n_p_b;
                                          player_bullet[i][0] += 3;//自機的子彈橫向移動三個單位長度
                                          setfillcolor(RGB(150, 180, 210));
                                          if (player_bullet[i][0] >= 635)
                                          {
                                                 destroy_p_b(i);    // 到達(dá)了屏幕最右端,銷毀子彈
                                          }
 
                                          // 碰撞檢測,兩個矩形
                                          if ((player_bullet[i][0] + 5 >= enemy_pos[0] - 20 && player_bullet[i][0] - 5 <= enemy_pos[0] + 20) && (player_bullet[i][1] - 5 < enemy_pos[1] + 40 && player_bullet[i][1] + 5 > enemy_pos[1] - 40))
                                                 // 擊中敵人
                                          {
                                                 destroy_p_b(i);
                                                 enemy_health -= 8;
                                                 isBleeding_e = true;//被命中后會閃爍
                                                 bleed_e = clock();
                                          }
 
                                          fillrectangle(player_bullet[i][0] - 5, player_bullet[i][1] - 5, player_bullet[i][0] + 5, player_bullet[i][1] + 5);            // 畫子彈
                                   }
 
                            }
 
                            if (n_e_b <= e_b_toprocess)...// 敵人的子彈,處理方式和自機類似。
                           
 
                     if (win || dead)
                            break;
                     FlushBatchDraw();
                     move_enemy();
                     if (player_health <= 0)
                            dead = true;
                     if (enemy_health <= 0)
                     {
                            win = true;
                     }
//檢驗勝利或失敗
                     if (GetAsyncKeyState(VK_LSHIFT) & 0x8000)      // 按住 Shift 減速
                     {
                            leftshift = true;
                     }
                     else
                     {
                            leftshift = false;
                     }
 
                     if (GetAsyncKeyState(VK_UP) & 0x8000)
                            // 玩家移動
                     {
                            if (player_pos[1] >= 28)
                                   if (leftshift)
                                          player_pos[1] -= 2;                          // y 的正方向是向下的
                                   else
                                          player_pos[1] -= 5;
                     }
//其它三個方向的移動同理
                     if (clock() - firerate >= FIRERATE && GetAsyncKeyState('Z') & 0x8000)
                            // 玩家開火
                     {
                            firerate = clock();
                            create_p_b();
                     }
 
                     if (clock() - e_firerate >= E_FIRERATE)//敵人間隔固定時間開火
                     {
                            e_firerate = clock();
                            create_e_b();
                     }
 
 
                     if (clock() - bleed_p >= BLEED_TIME)           // 受傷時間結(jié)束后關(guān)閉受傷閃爍效果
                     {
                            isBleeding_p = false;
                     }
 
                     if (clock() - bleed_e >= BLEED_TIME)           // 受傷時間結(jié)束后關(guān)閉受傷閃爍效果
                     {
                            isBleeding_e = false;
                     }
 
                     if (clock() - backgroundline_generate >= BACKGROUND)
                     {
                            backgroundline_generate = clock();
                            generate_line();//間隔一段時間繪制背景線條
                     }
              }
       }
       if (win)
       {
              settextcolor(RGB(0, 254, 0));
              settextstyle(35, 0, "黑體");
              outtextxy(150, 200, "你打敗了boss!你贏了??!");
       }
       else
       {
              settextcolor(RGB(254, 0, 0));
              settextstyle(35, 0, "黑體");
              outtextxy(140, 200, "你被boss打敗了!");
       }//處理勝利或者失敗
       FlushBatchDraw();//這個函數(shù)用于執(zhí)行未完成的繪制任務(wù)。
       Sleep(5000);
       EndBatchDraw();//這個函數(shù)用于結(jié)束批量繪制,并執(zhí)行未完成的繪制任務(wù)。
       return 0;
}

 

之后是各個函數(shù)的實現(xiàn)原理。

void hp_bar();
void show_player();
void show_enemy();
void move_enemy();              
void draw_background();

首先是五個繪制圖像的函數(shù)。它們的邏輯結(jié)構(gòu)都是線性的,只需要依次調(diào)用函數(shù)即可。

用到的函數(shù)有:

setlinecolor用于設(shè)置當(dāng)前設(shè)備畫線顏色。

line用于畫直線。

setfillcolor用于設(shè)置當(dāng)前設(shè)備填充顏色。

rectangle用于畫無填充的矩形。

fillrectangle用于畫有邊框的填充矩形。

以及之前提到的繪制文字的函數(shù)等。

 

敵機的移動:

void move_enemy()
{
       static bool angle_v;           // 控制敵機的豎直移動方向,true 為向上,到邊緣就換向
       static bool angle_h;          // 控制敵機的水平移動方向,true 為向左,到邊緣就換向
       static clock_t interval;       // 定時隨機換向
 
       if (clock() - interval >= 2000)
       {
              interval = clock();
              if (rand() % 2)                    // 一半的概率換向
                     angle_v = !angle_v;
              if (rand() % 2)
                     angle_h = !angle_h;
       }
       if (angle_v == true)                  //敵機移動
enemy_pos[1] -= 3;
       else
              enemy_pos[1] += 3;
       if (angle_h == true)
              enemy_pos[0] -= 3;
       else
              enemy_pos[0] += 3;
 
       if (enemy_pos[1] >= 440)  // 到了地圖邊緣就調(diào)頭
              angle_v = true;
       else if (enemy_pos[1] <= 40)
              angle_v = false;
       if (enemy_pos[0] >= 580)
              angle_h = true;
       else if (enemy_pos[0] <= 380)
              angle_h = false;
 
}

 

創(chuàng)建玩家子彈(敵人同理)

int create_p_b()
{
       if (number_p_b > MAX_PLAYER_BULLETS)                // 空間不夠
              return -1;
       for (int i = 0; i < MAX_PLAYER_BULLETS; ++i)      // 搜索 slots,尋找空位
       {
              if (p_b_slots[i] == false)
              {
                     p_b_slots[i] = true;
                     player_bullet[i][0] = player_pos[0] + 45;
                     player_bullet[i][1] = player_pos[1];       // 創(chuàng)建子彈
                     ++number_p_b;
                     break;
              }
       }
       return 0;
}

 

銷毀玩家子彈(敵人同理)

int destroy_p_b(int index)
{
       if (index > MAX_PLAYER_BULLETS - 1)//如果子彈數(shù)目溢出
              return -2;
       if (p_b_slots[index] == false)//如果子彈已經(jīng)被銷毀
              return -1;
       p_b_slots[index] = false;
       --number_p_b;
       return 0;
}


四、完整源碼


C語言彈幕射擊游戲完整源碼

點贊(0)

C語言網(wǎng)提供由在職研發(fā)工程師或ACM藍(lán)橋杯競賽優(yōu)秀選手錄制的視頻教程,并配有習(xí)題和答疑,點擊了解:

一點編程也不會寫的:零基礎(chǔ)C語言學(xué)練課程

解決困擾你多年的C語言疑難雜癥特性的C語言進(jìn)階課程

從零到寫出一個爬蟲的Python編程課程

只會語法寫不出代碼?手把手帶你寫100個編程真題的編程百練課程

信息學(xué)奧賽或C++選手的 必學(xué)C++課程

藍(lán)橋杯ACM、信息學(xué)奧賽的必學(xué)課程:算法競賽課入門課程

手把手講解近五年真題的藍(lán)橋杯輔導(dǎo)課程

Dotcpp在線編譯      (登錄可減少運行等待時間)