欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言FlappyBird飛揚(yáng)的小鳥實(shí)現(xiàn)開發(fā)流程

 更新時間:2022年11月07日 09:35:11   作者:莫淺子  
因?yàn)樵诩艺撕枚嗵欤S手玩了下自己以前做的一些小游戲,說真的,有幾個游戲做的是真的劣質(zhì),譬如 flappybird 真的讓我難以忍受,于是重做了一波分享給大家

前言

《flappy bird》是一款由來自越南的獨(dú)立游戲開發(fā)者Dong Nguyen所開發(fā)的作品,游戲于2013年5月24日上線,并在2014年2月突然暴紅。2014年2月,《Flappy Bird》被開發(fā)者本人從蘋果及谷歌應(yīng)用商店撤下。2014年8月份正式回歸APP Store,正式加入Flappy迷們期待已久的多人對戰(zhàn)模式。游戲中玩家必須控制一只小鳥,跨越由各種不同長度水管所組成的障礙。

通過游戲開發(fā)可以做到

1)在游戲窗口中顯示從右向左運(yùn)動的障礙物,顯示三根柱子墻;

2)用戶使用空格鍵控制小鳥向上移動,以不碰到障礙物為準(zhǔn),即需要從柱子墻的縫隙中穿行,確保隨機(jī)產(chǎn)生的障礙物之間的縫隙大小可以足夠小鳥通過;

3)在沒有用戶按鍵操作情況下,小鳥受重力影響會自行下落;

4)進(jìn)行小鳥與障礙物的碰撞檢測,如果沒有碰到,則給游戲者加 1 分。

5)如果小鳥碰到障礙物或者超出游戲畫面的上下邊界,則游戲結(jié)束。

?

使用空格鍵控制小鳥向上移動,在沒有用戶按鍵操作情況下,小鳥受重力影響會自行下落。如果小鳥碰到障礙物或者超出游戲畫面的上下邊界,則游戲結(jié)束。

打印上下邊界

Linux 環(huán)境下光標(biāo)定位

學(xué)會在 Linux 環(huán)境中光標(biāo)定位,在屏幕上在不同的位置,打印出不同的內(nèi)容。

光標(biāo)報告的格式是: 0x1B [行坐標(biāo);列坐標(biāo)]。

//x 為行坐標(biāo) ,y 為列坐標(biāo)

printf ( "%c[%d;%df" ,0x1B,y,x);

Windows 環(huán)境下光標(biāo)定位

Windows 環(huán)境中,光標(biāo)定位的方法有所不同,引入 windows.h 頭文件,以下所使用的到的結(jié)構(gòu)體或者函數(shù)均在存在于該頭文件。

首先需要使用到 windows.h 中的 COORD 結(jié)構(gòu)體,其定義為,

typedef struct _COORD {

SHORT X; // horizontal coordinate

SHORT Y; // vertical coordinate

} COORD;

再通過 GetStdHandle() 獲得標(biāo)準(zhǔn)輸出設(shè)備句柄 HANDLE;

HANDLE hp = GetStdHandle(STD_OUTPUT_HANDLE);

最后通過 SetConsoleCursorPosition() 設(shè)置控制臺光標(biāo)位置。

//變量 pos 為 COORD 結(jié)構(gòu)體對象

SetConsoleCursorPosition(hp, pos);

現(xiàn)在,我們可以在不同環(huán)境中,在不同位置進(jìn)行打印輸出。

代碼

#include <stdio.h>
#define BOOTEM 26 //下邊界的高度
#define DISTANCE 10 //兩個墻體之間的距離
#define WIDTH 5 //墻體寬度
#define BLANK 10 //上下墻體之間的距離
/**********Begin**********/
//光標(biāo)定位
void gotoxy(int x, int y){
 
     printf("%c[%d;%df", 0x1B, y, x);
}
//函數(shù)功能:顯示上下邊界和分?jǐn)?shù)
void begin(){
    system("clear");
    //打印上邊界
    gotoxy(0, 0);
    printf("\n==========================\n");
    //打印下邊界
    gotoxy(0, BOOTEM);
    printf("\n==========================");
}
/**********End**********/
int main()
{
	begin();
	return 0;
}

打印小鳥

代碼

#include "./head.h"
typedef struct COORD {
short X; // horizontal coordinate
short Y; // vertical coordinate
} COORD;
typedef struct bird
{
    COORD pos;
    int score;
} BIRD;
//函數(shù)功能:顯示小鳥
void prtBird(BIRD *bird){
    /**********Begin**********/
    void prtBird(BIRD *bird)
   {
    gotoxy(bird->pos.X, bird->pos.Y);
    printf("O^^0");
    fflush(stdout);
   }
    /**********End**********/
    //linux環(huán)境printf頻繁偶爾會在緩存中不會立即打印,fflush函數(shù)可以清空緩存并立即打印
    fflush(stdout);
}
int main()
{
	BIRD bird = {{10, 13}, 0};//小鳥的初始位置
	begin();
	prtBird(&bird);
	return 0;
}

小鳥移動

代碼

#include "./head.h"
//EVALUATING 宏定義  1 為 評測模式  0 為命令行模式
#define EVALUATING 1
//函數(shù)功能:檢測鍵盤輸入
//有輸入值時,該函數(shù)返回 1 ,沒有輸入時,該函數(shù)返回 0
int kbhit()
{
	struct termios oldt, newt; 
	int ch; 
	int oldf; 
	tcgetattr(STDIN_FILENO, &oldt); 
	newt = oldt; 
	newt.c_lflag &= ~(ICANON | ECHO); 
	tcsetattr(STDIN_FILENO, TCSANOW, &newt); 
	oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 
	fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 
	ch = getchar(); 
	tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 
	fcntl(STDIN_FILENO, F_SETFL, oldf); 
	if(ch != EOF) { 
    	ungetc(ch, stdin); 
    	return 1; 
	} 
	return 0; 
}
//函數(shù)功能:移動小鳥
void moveBird(BIRD *bird){
	/**********Begin**********/
     /**********Begin**********/
      char ch;  
    //下面兩行代碼  作用是覆蓋上次打印出來的小鳥位置,如果不加的話 會顯示殘影  
    gotoxy(bird->pos.X, bird->pos.Y);  
    printf("     ");
    if (kbhit()) {  
        ch = getchar();  
        if (ch == ' ') {  
            bird->pos.Y--;//向上移動  
        }  
    }  
    else {  
        bird->pos.Y++;//向下移動  
    }
	/**********End**********/
}
int main()
{
	begin();
	BIRD bird = {{10, 13}, 0};//小鳥的初始位置
	//EVALUATING 宏定義 1 為評測模式  0 為命令行模式
 	if(EVALUATING){
		int cnt=3;// 請忽略 輔助評測 無實(shí)際意義 
    	while(cnt--){
			prtBird(&bird);
			usleep(400000);
			moveBird(&bird);
   		}
	}else{
		while(1){
		prtBird(&bird);
		usleep(400000);
		moveBird(&bird);
    	}
	}
	return 0;
}

打印墻體

我們使用鏈表來存放墻體,鏈表是一種常用的數(shù)據(jù)結(jié)構(gòu),由若干個結(jié)點(diǎn)組成,每個結(jié)點(diǎn)包括兩個部分:一個是存儲數(shù)據(jù)元素的數(shù)據(jù)域,另一個是存儲下一個結(jié)點(diǎn)地址的指針域。

typedef struct wall{

COORD pos;

struct wall *next;//指向下一鏈表

}WALL;

在這里我們要注意變量的生存周期,如果函數(shù)將變量內(nèi)存地址存放在棧區(qū)的時候,當(dāng)創(chuàng)建該變量的函數(shù)結(jié)束時,其內(nèi)部創(chuàng)建在棧區(qū)的地址將被釋放。

因此我們需要將結(jié)點(diǎn)申請?jiān)诙褏^(qū),在 C 語言中,我們可以通過 malloc() 函數(shù)申請堆區(qū),例如。

WALL *wall = (WALL *)malloc(sizeof(WALL)); 

當(dāng)該變量不需要使用的時候,使用 free() 函數(shù)將其地址空間釋放。

free(wall);

第 1 行和第 BOOTEM 行是上下邊界,從第 2 行開始打印墻體,其中上下墻體間隔 BLANK 行。DISTANCE 為相鄰兩個墻體的間距,WIDTH 為墻體的寬度。

#define BOOTEM 26 //下邊界的高度
#define DISTANCE 10 //兩個墻體之間的距離
#define WIDTH 5 //墻體寬度
#define BLANK 10 //上下墻體之間的距離

墻體樣式為,

prtNode(p, "*"); 

代碼

#include "./head.h"
//EVALUATING 宏定義  1 為 評測模式  0 為命令行模式
#define EVALUATING 1
typedef struct wall{
	COORD pos;
	struct wall *next;
}WALL;
/**********Begin**********/
 //創(chuàng)建節(jié)點(diǎn)
WALL *createWall(int x, int y){
    //首先生成一個節(jié)點(diǎn)
    WALL *wall = (WALL *)malloc(sizeof(WALL));
    if(wall == NULL) return NULL;
    wall->pos.X = x;
    wall->pos.Y = y;
    wall->next = NULL;
    return wall;
}
//遍歷鏈表
WALL *lastNode(WALL *wall){
    WALL *p = wall;
    if(wall == NULL) return NULL;
    while(p->next){
        p = p->next;
    }
    return p;
}
//創(chuàng)建鏈表
WALL *createLink(){
    //生成一個隨機(jī)數(shù),作為上半部分墻體的高度
    srand(0);
    //生成隨機(jī)值,當(dāng)rd等于0或等于1時,給其賦值2
    int rd = rand() % (BOOTEM / 2);
    if(rd == 1||rd==0) rd = 2;
    //初始化一個節(jié)點(diǎn)
    WALL *wall = createWall(20, rd);
    WALL *temp, *p;
    for(int i = 1; i <= 2; i ++){
        //生成隨機(jī)值,當(dāng)rd等于0或等于1時,給其賦值2
        rd = rand() % (BOOTEM / 2);
        if(rd == 1||rd==0) rd = 2;
        p = lastNode(wall);//找到了鏈表的尾節(jié)點(diǎn)
        //創(chuàng)建節(jié)點(diǎn)
        temp = createWall(p->pos.X + DISTANCE + WIDTH * 2, rd);
        p->next = temp;//尾插法
    }
    return wall;
}
//銷毀鏈表
void deleteLink(WALL *wall){
    WALL *p, *q;
    p = q = wall;
    if(wall != NULL){
        while(p->next != NULL){
            q = p->next;
            p->next = q->next;
            free(q);
        }
    }
    free(wall);//free(p);
}
//打印單個墻體
void prtNode(WALL *node, char ch[]){
    if(node == NULL) return ;
    int i, j;
    //上半部分墻體,第一行是上邊界,從第2行開始打印
    for(i = 2; i <= node->pos.Y; i ++){
        gotoxy(node->pos.X, i);
        for(j = 1; j <= WIDTH; j ++){
            printf("%s", ch);
        }
    }
    //下半部分墻體 第BOOTEM行是下邊界,此處 BOOTEM -1 避免墻體覆蓋邊界
    for(i = node->pos.Y + BLANK; i < BOOTEM - 1; i ++){
        gotoxy(node->pos.X, i);
        for(j = 1; j <= WIDTH; j ++){
            printf("%s", ch);
        }
    }
}
//打印整個墻體
void prtWall(WALL *wall){
    if(wall == NULL) return ;
    WALL *p = wall;
    while(p){
        prtNode(p, "*");
        p = p->next;
    }
}
int main()
{
	begin();
	BIRD bird = {{10, 13}, 0};//小鳥的初始位置
	WALL *wall= createLink();//鏈表生成墻體
	prtWall(wall);
	//EVALUATING 宏定義 1 為評測模式  0 為命令行模式
 	if(EVALUATING){
		int cnt=3;// 請忽略 輔助評測 無實(shí)際意義 
    	while(cnt--){
			prtBird(&bird);
			usleep(400000);
			moveBird(&bird);
   		}
	}else{
		while(1){
			prtBird(&bird);
			usleep(400000);
			moveBird(&bird);
    	}
	}
    deleteLink(wall);
	return 0;
}

檢測碰撞

當(dāng) justHead() 函數(shù)沒有檢測到碰撞時,返回 0,當(dāng)檢測到碰撞時,返回 1。

當(dāng)小鳥與上下邊界發(fā)生碰撞時,

//與上下邊界發(fā)生碰撞
if(bird->pos.Y <= 0 || bird->pos.Y >= BOOTEM)

當(dāng)小鳥與墻體發(fā)生碰撞時,

//小鳥與墻體發(fā)生碰撞
bird->pos.X >= wall->pos.X && bird->pos.X <= wall->pos.X+ WIDTH

代碼

#include "./head.h"
//EVALUATING 宏定義  1 為 評測模式  0 為命令行模式
#define EVALUATING 1
//監(jiān)測小鳥碰撞
int justHead(WALL *wall, BIRD *bird){
    if(wall == NULL) return -1;
    //與上下邊界發(fā)生碰撞
    if(bird->pos.Y <= 0 || bird->pos.Y >= BOOTEM) return 1;
    //小鳥與墻體發(fā)生碰撞
    if(bird->pos.X  >= wall->pos.X && bird->pos.X <= wall->pos.X+ WIDTH){
        if(bird->pos.Y <= wall->pos.Y || bird->pos.Y >= wall->pos.Y + BLANK){
            return 1;
        }
    }
    return 0;
} 
int main()
{
	begin();
	BIRD bird = {{10, 13}, 0};//小鳥的初始位置
	WALL *wall= createLink();//鏈表生成墻體
	prtWall(wall);
	//EVALUATING 宏定義 1 為評測模式  0 為命令行模式
 	if(EVALUATING){
		int cnt=3;// 請忽略 輔助評測 無實(shí)際意義 
    	while(cnt--&&justHead(wall,&bird)==0){
			prtBird(&bird);
			usleep(400000);
			moveBird(&bird);
			wall = moveWall(wall,&bird);
   		}
	}else{
		while(justHead(wall,&bird)==0){
 
			prtBird(&bird);
			usleep(400000);
			moveBird(&bird);
            wall = moveWall(wall,&bird);
    	}
	}
    deleteLink(wall);
	return 0;
}

Flappy bird 實(shí)踐練習(xí)

代碼

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <time.h>
#include <termios.h>
#include <unistd.h> 
#include <fcntl.h>
#include <stdbool.h>
#define DIS 22
#define BLAN 9   //上下兩部分柱子墻之間的縫隙
typedef struct COORD {
short X; // horizontal coordinate
short Y; // vertical coordinate
} COORD;
typedef struct bird
{
    COORD pos;
    int score;
} BIRD;
//bool SetConsoleColor(unsigned int wAttributes); //設(shè)置顏色
void Gotoxy(int x, int y);//定位光標(biāo)
bool SetConsoleColor(int back,int front); //設(shè)置顏色
void CheckWall(COORD wall[]);//顯示柱子墻體
void PrtBird(BIRD *bird);//顯示小鳥
int CheckWin(COORD *wall, BIRD *bird);//檢測小鳥是否碰到墻體或者超出上下邊界
void Begin(BIRD *bird);//顯示上下邊界和分?jǐn)?shù)
int SelectMode();  //選擇模式
int kbhit()
{
    struct termios oldt, newt; 
    int ch; 
    int oldf; 
    tcgetattr(STDIN_FILENO, &oldt); 
    newt = oldt; 
    newt.c_lflag &= ~(ICANON | ECHO); 
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); 
    oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 
    fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 
    ch = getchar(); 
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 
    fcntl(STDIN_FILENO, F_SETFL, oldf); 
    printf("%c\n",ch);
    if(ch != EOF) { 
        ungetc(ch, stdin); 
        return 1; 
    } 
    return 0; 
}
//主函數(shù)
int main(int argc, char* argv[])
{
    BIRD bird = {{20, 13}, 0};//小鳥的初始位置
    COORD wall[3] = {{40, 10},{60, 6},{80, 8}}; //柱子的初始位置和高度
    int i;
    char ch;
    int gameMode = 1;
    gameMode = SelectMode();
    if(gameMode==1) //用于評測
    {
        int count = 0;
        while (count < 60)      //游戲循環(huán)執(zhí)行
        {        
          Begin(&bird); //清屏并顯示上下邊界和分?jǐn)?shù)
          PrtBird(&bird);//顯示小鳥
          CheckWall(wall);//顯示柱子墻
          ch = getchar();//輸入的字符存入ch
          printf("%c",ch);
          if (ch == 'u')//輸入的是u
            {
                bird.pos.Y -= 1; //小鳥向上移動一格
            }
            if (ch == 'd')//輸入的是d
            {
                bird.pos.Y += 1; //小鳥向下移動一格
          }
          for (i=0; i<3; ++i)
          {
            wall[i].X--; //柱子墻向左移動一格
          }
         if(CheckWin(wall, &bird)==0)
            {
                printf("Bird Lose!");
                return 0;
            }
            count++;
        }
        printf("Bird Win!");
        return 0;
    }
    while (CheckWin(wall, &bird))
    {
        Begin(&bird); //清屏并顯示上下邊界和分?jǐn)?shù)
        PrtBird(&bird);//顯示小鳥
        CheckWall(wall);//顯示柱子墻
        usleep(400000);
        if (kbhit()) //檢測到有鍵盤輸入
        {
            ch = getchar();//輸入的字符存入ch
            printf("%c",ch);
            if (ch == ' ')//輸入的是空格
            {
                bird.pos.Y -= 1; //小鳥向上移動一格
            }
        }        
        else //未檢測到鍵盤輸入
        {
            bird.pos.Y += 1;//小鳥向下移動一格
        }
        for (i=0; i<3; ++i)
        {
            wall[i].X--; //柱子墻向做移動一格
        }
    }
    return 0;
}
int SelectMode()
{
    printf(" 請選擇模式:\n 1.評測模式\n 2.自由體驗(yàn)游戲\n");
    int mode;
    while(scanf("%d", &mode))
    {
        if (mode != 1 && mode != 2)
        {
            printf(" 輸入數(shù)據(jù)有誤,請重新輸入!\n\n 請選擇模式:\n 1.評測模式\n 2.自由體驗(yàn)游戲\n");
            continue;
        }
        else return mode;
    }
    return 1;
}
//函數(shù)功能:定位光標(biāo)
void Gotoxy(int x, int y)//void Gotoxy(COORD pos)
{
printf ( "%c[%d;%df" ,0x1B,y,x);
}
//函數(shù)功能:設(shè)置顏色
bool SetConsoleColor(int back,int front)
{
    printf("\033[%dm",(front));
    return TRUE; 
}
//函數(shù)功能:顯示柱子墻體
void CheckWall(COORD wall[])
{
    int i;
    srand(time(0));
    COORD temp = {wall[2].X + DIS, rand() % 13 + 5};//隨機(jī)產(chǎn)生一個新的柱子
    if (wall[0].X < 10)  //超出預(yù)設(shè)的左邊界
    {    //最左側(cè)的柱子墻消失,第二個柱子變成第一個,第三個柱子變成第二個,新產(chǎn)生的柱子變成第三個
        /********** Begin **********/
        wall[0] = wall[1];//最左側(cè)的柱子墻消失,第二個柱子變成第一個
        wall[1] = wall[2];//第三個柱子變成第二個
        wall[2] = temp;   //新產(chǎn)生的柱子變成第三個
        /********** End **********/
    }
    SetConsoleColor(40,31); //設(shè)置黑色背景,亮紅色前景
    for (i=0; i<3; ++i)//每次顯示三個柱子墻
    {
        //顯示上半部分柱子墻
        temp.X = wall[i].X + 1;//向右縮進(jìn)一格顯示圖案
        for (temp.Y=2; temp.Y<wall[i].Y; temp.Y++)//從第2行開始顯示
        {
            Gotoxy(temp.X, temp.Y);
            printf("■■■■■■");
        }
        temp.X--;//向左移動一格顯示圖案
        Gotoxy(temp.X, temp.Y);
        printf("■■■■■■■■");
        //顯示下半部分柱子墻
        temp.Y += BLAN;
        Gotoxy(temp.X, temp.Y);
        printf("■■■■■■■■");
        temp.X++; //向右縮進(jìn)一格顯示圖案
        temp.Y++; //在下一行顯示下面的圖案
        for (; (temp.Y)<26; temp.Y++)//一直顯示到第25行
        {
            Gotoxy(temp.X, temp.Y);
            printf("■■■■■■");
        }
    }
    Gotoxy(0, 26);
    printf("\n");//第1行顯示分?jǐn)?shù)
}
//函數(shù)功能:顯示小鳥
void PrtBird(BIRD *bird)
{
    SetConsoleColor(40,33); //設(shè)置黑色背景,亮黃色前景
    Gotoxy(bird->pos.X, bird->pos.Y);
    printf("o->");
}
//函數(shù)功能:檢測小鳥是否碰到墻體或者超出上下邊界,是則返回0,否則分?jǐn)?shù)加1并返回1
int CheckWin(COORD *wall, BIRD *bird)
{  
    /********** Begin **********/
    if (bird->pos.X >= wall->X) //小鳥的橫坐標(biāo)進(jìn)入柱子坐標(biāo)范圍
    {
        if (bird->pos.Y <= wall->Y || bird->pos.Y >= wall->Y + BLAN) 
        {
            return 0; //小鳥的縱坐標(biāo)碰到上下柱子,則返回0
        }
    }
    if (bird->pos.Y < 1 || bird->pos.Y > 26) 
    {
        return 0; //小鳥的位置超出上下邊界,則返回0
    }
    (bird->score)++; //分?jǐn)?shù)加1
    return 1;
    /********** End **********/
}
//函數(shù)功能:顯示上下邊界和分?jǐn)?shù)
void Begin(BIRD *bird)
{
    system("clear");    
    Gotoxy(0, 26); //第26行顯示下邊界
printf("=========================================================="
"================================Bottom");
Gotoxy(0, 1); //第1行顯示上邊界
printf("=========================================================="
"================================Top");
    SetConsoleColor(40,33);//設(shè)置黑色背景,亮黃色前景
    printf("\n%4d", bird->score);//第1行顯示分?jǐn)?shù)
}

最后在liunx環(huán)境下即可完成游戲

到此這篇關(guān)于C語言FlappyBird飛揚(yáng)的小鳥實(shí)現(xiàn)開發(fā)流程的文章就介紹到這了,更多相關(guān)C語言FlappyBird內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論