當前位置:編程學習大全網 - 編程語言 - 怎麽用C語言寫下雪的動畫效果

怎麽用C語言寫下雪的動畫效果

#include?<stdio.h>

#include?<stdlib.h>

#include?<string.h>

#include?<time.h>

/*

*?清除屏幕的shell?命令/控制臺命令,還有壹些依賴平臺的實現

*?如果定義了?__GNUC__?就假定是?使用gcc?編譯器,為Linux平臺

*否則?認為是?Window?平臺

*/

#if?defined(__GNUC__)

//下面是依賴?Linux?實現

#include?<unistd.h>

#define?sleep_ms(m)?\

usleep(m?*?1000)

//向上移動光標函數?Linux

static?void?__curup(int?height)

{

int?i?=?-1;

while?(++i<height)

printf("\033[1A");?//先回到上壹行?

}

#else?

//?創建等待函數?1s?60?幀?相當於?16.7ms?=>?1幀,?我們取16ms

//?咱麽的這屏幕?推薦?1s?25幀吧?40ms

//?這裏創建等待函數?以毫秒為單位?,?需要依賴操作系統實現

#include?<Windows.h>

#define?sleep_ms(m)?\

Sleep(m)

//向上移動光標

static?void?__curup(int?height)

{

COORD?cr?=?{0,0};

//?GetStdHandle(STD_OUTPUT_HANDLE)?獲取屏幕對象,?設置光標

SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),?cr);

}

#endif?/*__GNUC__?跨平臺的代碼都很醜陋?*/

//?定義初始屏幕的寬高像素宏

#define?_INT_WIDTH(100)

#define?_INT_HEIGHT(50)

//?屏幕刷新幀的速率

#define?_INT_FRATE(40)

//?雪花飄落的速率,相對於?屏幕刷新幀?的倍數

#define?_INT_VSNOW(10)

/*

*?錯誤處理宏,msg必須是""括起來的字符串常量

*?__FILE__:?文件全路徑

*?__func__:?函數名

*?__LINE__:?行數行

*?__VA_ARGS__:?可變參數宏,

*?##表示直接連接,?例如?a##b?<=>?ab

*/

#define?cerr(msg,...)?\

fprintf(stderr,?"[%s:%s:%d]"?msg?"\n",__FILE__,__func__,__LINE__,##__VA_ARGS__);

/*

*?屏幕結構體,?具有?寬高

*?frate?:?繪制壹幀的周期,?單位是?毫秒

*?width?:?屏幕的寬,基於窗口的左上角(0,0)

*?height?:?屏幕的高

*?pix:?用壹維模擬二維?主要結構如下

*?0?0?0?1?0?0?1?0?1?0

*?0?1?0?1?0?1?0?1?2?0

*?.?.?.

*?=>?0表示沒像素,?1表示1個像素,2表示2個像素....

*/

struct?screen?{

int?frate;?//?也可以用?unsigned?結構

int?width;

int?height;

char?*pix;

};

/*

*?創建壹個?屏幕結構指針?返回

*

*?int?frate:?繪制壹幀的周期

*?int?width:?屏幕寬度

*?int?height:?屏幕高度

*?return:?指向屏幕結構的指針

*?*/

struct?screen*?screen_create(int?frate,?int?width,?int?height);

/*

*?銷毀壹個?屏幕結構指針,?並為其置空

*?struct?screen**?:?指向?屏幕結構指針的指針,?二級銷毀壹級的

*?*/

void?screen_destory(struct?screen**?pscr);

/**

*?屏幕繪制函數,主要生成壹個雪花效果

*

*?struct?screen*?:?屏幕數據

*?return?:?0表示可以繪制了,1表示圖案不變

*/

int?screen_draw_snow(struct?screen*?scr);

/**

*?屏幕繪制動畫效果,?繪制雪花動畫

*

*?struct?screen*?:?屏幕結構指針

*/

void?screen_flash_snow(struct?screen*?scr);

//?主函數,主業務在此運行

int?main(int?argc,?char?*argv[])

{

struct?screen*?scr?=?NULL;

//創建壹個屏幕對象

scr?=?screen_create(_INT_FRATE,?_INT_WIDTH,?_INT_HEIGHT);

if?(NULL?==?scr)

exit(EXIT_FAILURE);

//繪制雪花動畫

screen_flash_snow(scr);

//銷毀這個屏幕對象

screen_destory(&scr);

return?0;

}

/*

*?創建壹個?屏幕結構指針?返回

*

*?int?frate:?繪制壹幀的周期

*?int?width:?屏幕寬度

*?int?height:?屏幕高度

*?return:?指向屏幕結構的指針

*?*/

struct?screen*

screen_create(int?frate,?int?width,?int?height)

{

struct?screen?*scr?=?NULL;

if?(frate<0?||?width?<=?0?||?height?<=?0)?{

cerr("[WARNING]check?is?frate<0?||?width<=0?||?height<=0?err!");

return?NULL;

}

//後面是?為?scr->pix?分配的內存?width*height

scr?=?malloc(sizeof(struct?screen)?+?sizeof(char)*width*height);

if?(NULL?==?scr)?{

cerr("[FATALG]Out?of?memory!");

return?NULL;

}

scr->frate?=?frate;

scr->width?=?width;

scr->height?=?height;

//減少malloc次數,malloc消耗很大,內存泄露呀,內存碎片呀

scr->pix?=?((char?*)scr)?+?sizeof(struct?screen);

return?scr;

}

/*

*?銷毀壹個?屏幕結構指針,?並為其置空

*?struct?screen**?:?指向?屏幕結構指針的指針,?二級銷毀壹級的

*?*/

void

screen_destory(struct?screen**?pscr)

{

if?(NULL?==?pscr?||?NULL?==?*pscr)

return;

free(*pscr);

//?避免野指針

*pscr?=?NULL;

}

//構建開頭?的雪花,下面宏表示每?_INT_SHEAD?個步長,壹個雪花,需要是2的冪

//static?可以理解為?private,?宏,位操作代碼多了確實難讀

#define?_INT_SHEAD?(1<<2)

static?void?__snow_head(char*?snow,?int?len)

{

int?r?=?0;

//數據需要清空

memset(snow,?0,?len);

for?(;;)?{

//取余壹個技巧?2^3?-?1?=?7?=>?111?,?並就是取余數

int?t?=?rand()?&?(_INT_SHEAD?-?1);

if?(r?+?t?>=?len)

break;

snow[r?+?t]?=?1;

r?+=?_INT_SHEAD;

}

}

#undef?_INT_SHEAD

//通過?上壹個?scr->pix[scr->width*(idx-1)]?=>?scr->pix[scr->width*idx]

//下面的宏?規定?雪花左右搖擺?0?向左壹個像素,?1?表示?不變,?2表示向右壹個像素

#define?_INT_SWING?(3)

static?void?__snow_next(struct?screen*?scr,?int?idx)

{

int?width?=?scr->width;

char*?psnow?=?scr->pix?+?width*(idx?-?1);

char*?snow?=?psnow?+?width;

int?i,?j,?t;?//?i索引,?j保存下壹個瞬間雪花的位置,t?臨時補得,解決雪花重疊問題

//為當前行重置

memset(snow,?0,?width);

//通過上壹次雪花位置?計算下壹次雪花位置

for?(i?=?0;?i<width;?++i)?{

for?(t?=?psnow[i];?t>0;?--t)?{?//?雪花可以重疊

//?rand()%_INT_SWING?-?1?表示?雪花?橫軸的偏移量,相對上壹次位置

j?=?i?+?rand()?%?_INT_SWING?-?1;

j?=?j<0width?-?1?:?j?>=?width0?:?j;?//?j如果越界了,左邊越界讓它到右邊,右邊越界到左邊

++snow[j];

}

}

}

/**

*?屏幕繪制函數,主要生成壹個雪花效果

*

*?struct?screen*?:?屏幕數據

*?return?:?0表示可以繪制了,1表示圖案不變

*/

int

screen_draw_snow(struct?screen*?scr)

{

//?靜態變量,默認初始化為0,每次都***用

static?int?__speed?=?0;

int?idx;

if?(++__speed?!=?_INT_VSNOW)

return?1;

//下面?就是?到了雪花飄落的時刻了?既?__speed?==?_INT_VSNOW

__speed?=?0;

//這裏重新構建雪花界面,先構建頭部,再從尾部開始構建

for?(idx?=?scr->height?-?1;?idx?>?0;?--idx)

__snow_next(scr,?idx);

//構建頭部

__snow_head(scr->pix,?scr->width);

return?0;

}

//buf?保存scr?中pix?數據,構建後為?(width+1)*height,?後面宏是雪花圖案

#define?_CHAR_SNOW?‘*‘

static?void?__flash_snow_buffer(struct?screen*?scr,?char*?buf)

{

int?i,?j,?rt;

int?height?=?scr->height,?width?=?scr->width;

int?frate?=?scr->frate;?//刷新的幀頻率

//每次都等壹下

for?(;;sleep_ms(frate))?{

//開始繪制屏幕

rt?=?screen_draw_snow(scr);

if?(rt)

continue;

for?(i?=?0;i<height;?++i)?{

char*?snow?=?scr->pix?+?i*width;

for?(j?=?0;?j<width;?++j)

buf[rt++]?=?snow[j]_CHAR_SNOW?:?‘?‘;

buf[rt++]?=?‘\n‘;

}

buf[rt?-?1]?=?‘\0‘;

//正式繪制到屏幕上

puts(buf);

//清空老屏幕,屏幕光標回到最上面

__curup(height);

}

}

#undef?_CHAR_SNOW

/**

*?屏幕繪制動畫效果,?繪制雪花動畫

*

*?struct?screen*?:?屏幕結構指針

*/

void

screen_flash_snow(struct?screen*?scr)

{

char*?buf?=?NULL;

//?初始化隨機數種子,改變雪花軌跡

srand((unsigned)time(NULL));

buf?=?malloc(sizeof(char)*(scr->width?+?1)*scr->height);

if?(NULL?==?buf)?{

cerr("[FATAL]Out?of?memory!");

exit(EXIT_FAILURE);

}

__flash_snow_buffer(scr,?buf);

//1.這裏理論上不會執行到這,沒加控制器.?2.對於buf=NULL,這種代碼?可以省掉,看編程習慣

free(buf);

buf?=?NULL;

}

  • 上一篇:數控車削中 公制螺紋 美制螺紋 英制螺紋在圖紙上的表達方式 如何換算 並編程車削
  • 下一篇:51單片機如何模擬旋轉編碼器輸出的相位差90度的方波
  • copyright 2024編程學習大全網