1. 程式人生 > 程式設計 >C語言實現打飛機小遊戲

C語言實現打飛機小遊戲

本文例項為大家分享了C語言實現打飛機小遊戲的具體程式碼,供大家參考,具體內容如下

編譯環境:vs2019

需求:

在同一個平面內,控制大炮發射的三個方向,空格發射炮彈,敵軍和友軍飛機會一直隨機在天上飛過,擊中天上飛行的敵軍飛機加一分,擊中友軍飛機減一分

思路:

先初始化程式,再畫出說明和地圖,接著進入無限迴圈,迴圈中分別實現飛機不停地在天上飛、通過awd空格鍵控制遊戲內容、符合遊戲條件時加分三個主要步驟。

做法:

首先要實現飛機的動畫效果,本質是要在控制檯上輸出三條x軸上輸出一個字串,並要讓這三個字串看起來在同時移動。這裡我藉助了寫賭馬大賽的經驗:在第一次無限迴圈內分別迴圈輸出第1、2、3條的字串表示走出第一步,然後再自增三個字串x軸座標數值,第二次無限迴圈清除上一次字串移動痕跡,並再分別輸出三條字串,表示走出第二步。由於內層for迴圈沒有休眠函式,這樣看起來就是三個字元串同時移動的效果。這樣就可以通過無限迴圈表示三架飛機不停地移動了。

接下來是通過getch函式改變大炮炮口指向方向(一個字元),在炮口指向切換的同時,炮彈初始化的位置也同樣會改變,當按下空格時,炮彈(一個字元)會從他的初始化位置沿設定好的路線不停移動,當橫縱軸座標與飛機座標相匹配時判斷是否為敵軍飛機|—0>,是則得分加一,否則得分減一。
此外程式裡還有很多細節,這裡不一一贅述。

難點:

看起來讓三個字元串同時移動。這是一種演算法,學會了就應該應該像記住基礎知識一樣牢牢記住他。明白了原理之後,比較容易掌握。

說明:

這是一個簡單的小程式,實現該程式中相同的效果有著很多種方法,而我則大量地使用了陣列來存放、統計和使用各種不同的資料,其實類似效果還可以通過單鏈表來實現。在我目前的認知中使用陣列和直接輸出字串的寫法有著簡潔明瞭的優點。但同時也導致出一個顯示效果上比較致命的缺陷。

注意:

由於編譯器原因程式中_kbhit()和_getch()函式可能在其他編譯器上編譯會出現錯誤,解決辦法是去掉函式前面的 “_”。

執行效果:

C語言實現打飛機小遊戲

程式碼實現:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
#include <string.h>


void HideCursor();  //隱藏游標
void gotoxy(int x,int y); //游標定位

#define R 26  //飛機每次隨機尾x座標最大值
#define N 20  //通關分數

int ax[3] = { 0 };  //三個飛機尾座標,全域性
int y[3] = { 3,7,11 }; //三個y軸,全域性,查表法確定飛機的y軸位置 
    //因為炮彈的飛行距離是一次加兩個格子,為了奇偶對應這裡的y軸必須都是偶數
int i;   //迴圈用變數
int fd[3];   //控制飛機種類

void cshcxhs()    //初始化函式
{
 system("title 打飛機小遊戲");  //標題
 system("mode con cols=100 lines=30"); //寬100,高30
 HideCursor();    //游標隱藏

 gotoxy(46,12);    //介紹遊戲規則
 printf("遊戲規則:");
 gotoxy(36,14);
 printf("w a d鍵控制方向,空格鍵發射炮彈");
 gotoxy(26,16);
 printf("擊中敵軍飛機 |---0> 加一分,擊中友軍飛機 >>>>>> 減一分");
 gotoxy(40,18);
 printf("累計得分 %d 結束遊戲",N);
 Sleep(2800);

 system("cls");
 
 int k;     //迴圈用變數
 gotoxy(40,R);    //初始化炮臺
 for (k = 0; k < 17; k++)
 printf("_");

 gotoxy(46,R);
 printf("[_O_]");
 gotoxy(48,25);    //中間x:48
 printf("|");

 int j;
 srand((unsigned)time(NULL));  //初始化隨機種子
 for (j = 0; j < 3; j++)   //初始化飛機的初始x座標,寫在迴圈之外
 {
 ax[j] = rand() % R;
 fd[j] = rand() % 2;
 }

 gotoxy(0,R);
 printf(" 得分:");   //分數x座標9
}

void hcfjhs()   //畫出飛機函式
{
 gotoxy(ax[i],y[i]);  //首先在飛機尾處輸出整架飛機

 if (fd[i] == 1)  
 printf("|---0>"); 
 else    
 printf(">>>>>>"); 

 gotoxy(ax[i] - 1,y[i]); //清除飛機尾部留下的痕跡
 printf(" ");

 ax[i]++;   //然後飛機尾座標自增,下次自飛機尾輸出整架飛機
}

void dhpdxshs()   //畫出飛機,並讓飛機在飛過x94的時候消失
{
 for (i = 0; i < 3; i++)  //每架飛機都走一步
 {
 hcfjhs();

 if (ax[i] + 6 >= 94) //判斷每架飛機頭有沒有超過94
 {
  gotoxy(94,y[i]); //滿足條件在每架飛機的94處輸出空格
  printf(" ");
  if (ax[i]+6 > 100) //每架飛機的飛機頭超過100,則重置一個隨機數
  {
  ax[i] = rand() % R; //修改為小於R的隨機數
  fd[i] = rand() % 2;
  }
 }
 }
}

int da = 2;  //da = 1為最左 預設中間 炮臺方向,全域性變數
int yip = 0;  //是否開炮,0不開,1,2,3三個方向
int rtde = 1;  //是否發射完畢,必須等待炮彈發射完成


int shells_x;  //炮彈座標
int shells_y;

void ckkzhs()
{
 char ch;
 ch = _getch();

 if (ch == 'd' || ch == 'D')
 {
 gotoxy(49,25);
 printf("/");  //炮臺右轉
 gotoxy(47,25);
 printf(" ");
 da = 3;   //最右狀態
 }
 if (ch == 'A' || ch == 'a')
 {
 gotoxy(47,25);
 printf("\\");  //轉義轉義字元
 gotoxy(48,25);
 printf(" ");
 da = 1;   //最左狀態
 }
 if (ch == 'W' || ch == 'w')
 {
 gotoxy(48,25);
 printf("|");  
 gotoxy(47,25);
 printf(" ");
 gotoxy(49,25);
 printf(" ");
 da = 2;
 }

 if (ch == ' '&& rtde == 0) //大炮處於發射完畢狀態,且按下空格
 {
 if (da == 2)  //中 炮臺朝向
  yip = 2;
 
 if (da == 1)  //左
 {
  yip = 1;
  shells_x = 45;  //初始化炮彈的座標
 }
 if (da == 3)  //右
 {
  yip = 3;
  shells_x = 51;
 }
 shells_y = 23;  //初始化炮彈的座標
 }
}

void dpfshs()   //向三個不同方向發射炮彈
{
 rtde = 1;   //迴圈,炮彈移動時代表未開炮完畢
 if (yip == 2)
 {
 shells_x = 48;
 gotoxy(shells_x,shells_y-=2);
 printf("o");
 gotoxy(shells_x,shells_y+2);
 printf(" ");
 }
 if (yip == 1)
 {
 gotoxy(shells_x-=2,shells_y-=2);
 printf("o");
 gotoxy(shells_x+2,shells_y+2);
 printf(" ");
 }
 if (yip == 3)
 {
 gotoxy(shells_x+=2,shells_y-=2);
 printf("o");
 gotoxy(shells_x-2,shells_y+2);
 printf(" ");
 }

 if (shells_y <= 1)  //炮彈越界,消除炮彈
 {
 yip = 0;  //炮彈越界,炮彈停下
 gotoxy(48,1);  //並消除
 printf(" ");
 gotoxy(23,1);
 printf(" ");
 gotoxy(73,1);
 printf(" "); 
 rtde = 0;  //炮彈越界,開炮完畢,可進行下一輪開炮
 }
}

int score;   //得分

void pdfsjzhs()  //判斷是否擊中和統計資訊
{
 
 for (i = 0; i < 3; i++)
 {
  if (shells_x >= ax[i] && shells_x <= ax[i] + 6 && shells_y == y[i])//擊中時
  {
  if(fd[i]==1)
   score++;   //擊中一次,得分加一
  else
  {
   score--;
   if (score <= 0)
   score = 0;
  }

  rtde = 0;   //擊中時,開炮完成

  gotoxy(ax[i]-1,y[i]);  //擊中後,在原飛機尾巴處消除飛機
  printf(" ");

  ax[i] = rand() % R;  //修改為小於10的隨機數
  fd[i] = rand() % 2;  //飛機種類發生變化

  gotoxy(shells_x,shells_y); //在擊中飛機的地方輸出空格消除炮彈屍體
  printf(" ");

  shells_x = 0,shells_y = 0; //炮彈擊中飛機,炮彈越界,下一次空格將自動初始化炮彈
  }
 }
 
 gotoxy(9,R);
 printf("%d",score);

 if (score >= N)  //遊戲結束判斷
 {
 system("cls"); //清屏
 gotoxy(39,15); 
 printf("您通關了,最終得分:%d !",N);
 gotoxy(0,29);
 exit(0);
 }

}

void process()  //流程
{
 while (1)
 {
 dhpdxshs();  //飛機動畫函式

 if (_kbhit()) 
 {
  ckkzhs(); //操作函式
 }
 
 dpfshs();  //大炮效果函式
 pdfsjzhs();  //判斷是否擊中和統計資訊

 Sleep(18);
 }
}

int main()
{
 cshcxhs(); //初始化程式

 process(); //流程

 return 0;
}

void HideCursor()
{
 CONSOLE_CURSOR_INFO cursor_info = { 1,0 };
 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}

void gotoxy(int x,int y)
{
 COORD pos = { x,y };
 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}

不足之處:

我在程式中輸出飛機時使用了在飛機尾直接輸出整架飛機,飛機尾x座標自增的寫法,這是一種很笨但又很簡單的做法。這種做法導致飛機在飛過控制檯最大寬度的同時無法逐個消除飛機機身,飛機頭一旦越過控制檯最大寬度就會出現程式輸出錯誤,所以我為了保留“讓飛機逐節身體地飛出邊界”這個讓飛機消失時看起來比較自然的效果,只好用最後飛機所在y軸最後6個x軸格子作為遮擋飛機的板子,以此來實現類似的效果。

由於該程式出了創意之外,全是由本人靠自己寫的,由於我能力有限,在寫這個程式的同時隱約感覺到我的程式存在著大量程式碼複用性、結構嚴謹性、執行效率低下上的問題,同時很多函式和變數識別符號我採用了瞎寫、中文拼音組成的做法。

作為一名c語言新手,我對未知的知識始終抱有學習和謙卑的態度,如有貴人能夠對我的程式提出複用性、嚴謹性、執行效率上的建議,我將不勝感激。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。