雪花啤酒psnow(编程代码:用C语言来实现下雪效果,这个冬天,雪花很美)

编程代码:用C言语来完成下雪后果,这个冬天,雪花很美

弁言

1.本文主要围绕 怎样 在 控制台上 下起 一场 仅有本人能望见的雪

2.是个浅易跨平台的,主要是C言语

3.动画 接纳 1s 40帧, 雪花具有 x轴速率和y轴速率

4.比力简便,可以给学生作为C言语结课作业吧.



要文

1.1 先简便处理跨平台

  本文写作动机,照旧感激一下大学的发蒙教师,让我晓得了有条路叫做步骤员,可以作为事情活着下去.那就上代码了.

起首代码定位 是 面向 简便跨平台,最少让 gcc 和 vs 可以跑起来.

但是跨平台都是嚼頭, 说白了就是一些昏暗的宏. 真渴望一切体系合二为一,接纳一致的标准api 计划,但这是不成能的,就相当于很早之前的电视制式一样.

那么我们先看 围绕跨平台的宏


#include #include #include #include /** 时间 : 2015年12月26日11:43:22

* 形貌 : 应该算过节吧,今天,写了个雪花殊效 代码,

* *//** 扫除屏幕的shell 下令/控制台下令,另有一些依托平台的完成

* 假如界说了 __GNUC__ 就假定是 使用gcc 编译器,为Linux平台

* 不然 以为是 Window 平台*/#ifdefined(__GNUC__)//底下是依托 Linux 完成#include #definesleep_ms(m) \ usleep(m *1000)//向上挪动光标函数 Linuxstaticvoid__curup(int height)

{

inti = -1;

while(++i

printf("\033[1A");//先回到上一行 }#else// 创建等候函数 1s 60 帧 相当于 16.7ms => 1帧, 我们取16ms// 咱么的这屏幕 保举 1s 25帧吧 40ms// 这里创建等候函数 以毫秒为单位 , 必要依托利用体系完成#include #definesleep_ms(m) \ Sleep(m)//向上挪动光标staticvoid__curup(int height)

{

COORD cr = {0,0};

// GetStdHandle(STD_OUTPUT_HANDLE) 获取屏幕目标, 设置光标 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cr);

}#endif/*__GNUC__ 跨平台的代码都很昏暗 */

起首是 sleep_ms 这个宏, 传入一个毫秒数,让利用体系等候.

关于__curup 完成的不佳. 功效是 让 控制台如今光标挪动到 外表的 height 地点,关于 window直接挪动到第一行(0,0)地点.

外表一共用了 5个头文件 照旧容易的代码. string.h 主要用的是 memset 函数, 让一段内存初始化,用0添补.

关于time.h 主要是为了 初始化时间种子,便利每次运转都不一样.

// 初始化随机数种子,改动雪花轨迹srand((unsigned)time(NULL));


1.2 再说主业务代码

这里步骤员运转的主业务,先说一说这里用的数据布局 如下

// 界说初始屏幕的宽高像素宏#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*/#definecerr(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 {

intfrate;// 也可以用 unsigned 布局int width;

int height;

char*pix;

};

创建了一个画图目标 struct screen 这里 构建这个布局体的时分用了底下一个本事

//后方是 为 scr->pix 分派的内存 width*heightscr =malloc(sizeof(structscreen) +sizeof(char)*width*height);

一次分派两个内存空间.底下是主要完成的api 目标

/** 创建一个 屏幕布局指针 前往

*

* int frate : 绘制一帧的周期

* int width : 屏幕宽度

* int height : 屏幕高度

* return : 指向屏幕布局的指针

* */structscreen* screen_create(intfrate,intwidth,int height);/** 烧毁一个 屏幕布局指针, 并为其置空

* struct screen** : 指向 屏幕布局指针的指针, 二级烧毁一级的

* */voidscreen_destory(structscreen** pscr);/**

* 屏幕绘制函数,主要天生一个雪花后果

*

* struct screen* : 屏幕数据

* return : 0表现可以绘制了,1表现图案安定*/intscreen_draw_snow(structscreen* scr);/**

* 屏幕绘制动画后果, 绘制雪花动画

*

* struct screen* : 屏幕布局指针*/voidscreen_flash_snow(structscreen* scr);

创建烧毁, 绘制一个雪花界面, 绘制雪花动画后果的api. 但是都很相似,用opengl 库, 主要让我们省略了必要单独和利用体系体现层打交道事情.

这里先容一下,一局部 一个 简便制止 野指针的 的办法, 具体看底下完成

/** 烧毁一个 屏幕布局指针, 并为其置空

* struct screen** : 指向 屏幕布局指针的指针, 二级烧毁一级的

* */voidscreen_destory(structscreen** pscr)

{

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

return;

free(*pscr);

// 制止野指针*pscr = NULL;

}

在实行之后置空,由于C步骤员对NULL一定要敏感,构成条件反射. 和各位开个打趣 ,


叨教 :

C 言语中, NULL , 0,'\0',"0",false有什么异同 ?


接待偕行,在招聘的时分问问,应聘低级开发事情者. 为什么C必要扣的那么细. 由于别的言语.你不明白是什么,

你可以用的很好. 但是C你写的代码,假如不晓得会有怎样的后果,那么 线上就一大片办事器直接崩掉.并且还很难找出

成绩地点. 由于C很简便,越简便就是越繁复.就越必要专业的维护职员.招致它成了'玩具'.

最初看一下 主业务


// 主函数,主业务在此运转intmain(intargc,char*argv[])

{

structscreen* scr = NULL;

//创建一个屏幕目标scr = screen_create(_INT_FRATE, _INT_WIDTH, _INT_HEIGHT);

if(NULL == scr)

exit(EXIT_FAILURE);

//绘制雪花动画 screen_flash_snow(scr);

//烧毁这个屏幕目标screen_destory(&scr);

return0;

}

还好坏常容易看懂的, 创建一个屏幕目标,绘制雪花后果.烧毁屏幕目标.


1.3 说一写 接口的完成细节

先看几个简便的api 完成,创建和销魂代码如下,很直白.

/** 创建一个 屏幕布局指针 前往

*

* int frate : 绘制一帧的周期

* int width : 屏幕宽度

* int height : 屏幕高度

* return : 指向屏幕布局的指针

* */structscreen* screen_create(intfrate,intwidth,int height)

{

structscreen *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*heightscr =malloc(sizeof(structscreen) +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** : 指向 屏幕布局指针的指针, 二级烧毁一级的

* */voidscreen_destory(structscreen** pscr)

{

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

return;

free(*pscr);

// 制止野指针*pscr = NULL;

}

后方说一下 怎样 绘制 屏幕中雪花

主要算法 是

a.有个屏幕 w x h

b.屏幕从外表第一行 出雪花 , 出雪花 地点是随机的[0,w], 但是有个距离,这个距离内仅有一个雪花

c.下一行 雪花 依托上一行雪花的天生, 每个雪花在可以飘动的时分, 只能 在[-1,1] 范围内

d.完成动画 后果 就是 每画一帧就等候 一段时间


底下看具体一点的 a

//创建一个屏幕目标scr = screen_create(_INT_FRATE, _INT_WIDTH, _INT_HEIGHT);

scr目标就是我们的创建屏幕. _INT_WIDTH 和 _INT_HEIGHT 就是屏幕轻重. 关于_INT_FRATE 表现绘制一帧时间.


b完成 代码如下:

//构建开头 的雪花,底下宏表现每 _INT_SHEAD 个步长,一个雪花,必要是2的幂//static 可以了解为 private, 宏,位利用代码多了的确难读#define_INT_SHEAD (1<<2)staticvoid__snow_head(char* snow,int len)

{

intr =0;

//数据必要清空memset(snow,0, len);

for (;;) {

//取余一个本事 2^3 - 1 = 7 => 111 , 并就是取余数intt = rand() & (_INT_SHEAD -1);

if(r + t >= len)

break;

snow[r + t] =1;

r += _INT_SHEAD;

}

}#undef_INT_SHEAD

本事如上,可以看分析. 这里 科普一下, 关于 for(;;) {} 和 while(true) {} 异同.

for(;;) {} 和 while(true) {} 这两段代码转成汇编是一样的, 不一样 的是 强加的志愿. 第一个 渴望 跳过 检测步调 速率更快一点.

再扩展一点.

//另一种 循环语句, goto 照旧 很强壮实用的__for_loop:

if(false)

goto __for_break;

goto __for_loop;

__for_break:

可以再扩展深一点, 另有一种 api 比 这个goto 还NB. 天然会分享. 特别强壮, 是特别处理步骤实质.


关于c.

//经过 上一个 scr->pix[scr->width*(idx-1)] => scr->pix[scr->width*idx]//底下的宏 划定 雪花支配摇摆 0 向左一个像素, 1 表现 安定, 2表现向右一个像素#define_INT_SWING (3)staticvoid__snow_next(structscreen* scr,int idx)

{

intwidth = scr->width;

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

char* snow = psnow + width;

inti, j, t;// i索引, j保存下一个刹时雪花的地点,t 暂且补得,处理雪花堆叠成绩

//为如今行重置memset(snow,0, width);

//经过上一次雪花地点 盘算下一次雪花地点for(i =0; i

for(t = psnow[i]; t>0; --t) {// 雪花可以堆叠

// rand()%_INT_SWING - 1 表现 雪花 横轴的偏移量,相对上一次地点j = i + rand() % _INT_SWING -1;

j = j<0? width -1: j >= width ?0: j;// j假如越界了,右方越界让它到右方,右方越界到右方++snow[j];

}

}

}

下一行雪花 依托 上一行雪花, 这里 有点像插进排序.

全体的绘制代码 如下

/**

* 屏幕绘制函数,主要天生一个雪花后果

*

* struct screen* : 屏幕数据

* return : 0表现可以绘制了,1表现图案安定*/intscreen_draw_snow(structscreen* scr)

{

// 静态变量,默许初始化为0,每次都共用staticint__speed =0;

int idx;

if(++__speed != _INT_VSNOW)

return1;

//底下 就是 到了雪花飘落的时候了 既 __speed == _INT_VSNOW__speed =0;

//这里重新构建雪花界面,先构建头部,再从尾部开头构建for(idx = scr->height -1; idx >0; --idx)

__snow_next(scr, idx);

//构建头部__snow_head(scr->pix, scr->width);

return0;

}

绘制了一个屏幕目标的雪花. __speed 纪录 绘制次数, _INT_VSNOW 控制绘制速率


d 的完成代码 如下

起首完成一个 烧毁屏幕代码和 绘制代码


//buf 保存scr 中pix 数据,构建后为 (width+1)*height, 后方宏是雪花图案#define_CHAR_SNOW '*'
staticvoid__flash_snow_buffer(structscreen* scr,char* buf)

{

int i, j, rt;

intheight = scr->height, width = scr->width;

intfrate = scr->frate;//改造的帧频率

//每次都等一下for (;;sleep_ms(frate)) {

//开头绘制屏幕rt = screen_draw_snow(scr);

if (rt)

continue;

for(i =0;i

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

for(j =0; j

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

buf[rt++] ='\n';

}

buf[rt -1] ='\0';

//正式绘制到屏幕上 puts(buf);

//清空老屏幕,屏幕光标回到最外表 __curup(height);

}

}#undef_CHAR_SNOW

这里 sleep_ms(frate); 是等候时间,不然太快, 人眼看不见.

绘制原理是 让屏幕转成控制台可以熟悉的字符. 塞入到buf 中.

__curup(height); 让绘制光标回到开头.

后方另有一段 代码完成

/**

* 屏幕绘制动画后果, 绘制雪花动画

*

* struct screen* : 屏幕布局指针*/voidscreen_flash_snow(structscreen* 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;

}

这种双函数完成一个功效本事用的也很多. 比如写快速排序代码, 就是如此.

到这里 我们 计划和完成都完成了.


2.代码后果展现

2.1 window 上展现

使用VS新建一个控制台项目,F5就可以了后果如下


是动态的.


2.2 关于Linux

直接使用

gcc -g -Wall snow.c -o snow.out./snow.out

运转后果如下



到这里, C言语完成雪花后果就如上了.


2.3 完备的代码展现. 感激 有你,一块偕行.

#include #include #include #include /** 时间 : 2015年12月26日11:43:22

* 形貌 : 应该算过节吧,今天,写了个雪花殊效 代码,

* 送给 大学发蒙 芦教师

* 学生王志 祝愿上

* *//** 扫除屏幕的shell 下令/控制台下令,另有一些依托平台的完成

* 假如界说了 __GNUC__ 就假定是 使用gcc 编译器,为Linux平台

* 不然 以为是 Window 平台*/#ifdefined(__GNUC__)//底下是依托 Linux 完成#include #definesleep_ms(m) \ usleep(m *1000)//向上挪动光标函数 Linuxstaticvoid__curup(int height)

{

inti = -1;

while(++i

printf("\033[1A");//先回到上一行 }#else// 创建等候函数 1s 60 帧 相当于 16.7ms => 1帧, 我们取16ms// 咱么的这屏幕 保举 1s 25帧吧 40ms// 这里创建等候函数 以毫秒为单位 , 必要依托利用体系完成#include #definesleep_ms(m) \ Sleep(m)//向上挪动光标staticvoid__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*/#definecerr(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 {

intfrate;// 也可以用 unsigned 布局int width;

int height;

char*pix;

};/** 创建一个 屏幕布局指针 前往

*

* int frate : 绘制一帧的周期

* int width : 屏幕宽度

* int height : 屏幕高度

* return : 指向屏幕布局的指针

* */structscreen* screen_create(intfrate,intwidth,int height);/** 烧毁一个 屏幕布局指针, 并为其置空

* struct screen** : 指向 屏幕布局指针的指针, 二级烧毁一级的

* */voidscreen_destory(structscreen** pscr);/**

* 屏幕绘制函数,主要天生一个雪花后果

*

* struct screen* : 屏幕数据

* return : 0表现可以绘制了,1表现图案安定*/intscreen_draw_snow(structscreen* scr);/**

* 屏幕绘制动画后果, 绘制雪花动画

*

* struct screen* : 屏幕布局指针*/voidscreen_flash_snow(structscreen* scr);// 主函数,主业务在此运转intmain(intargc,char*argv[])

{

structscreen* scr = NULL;

//创建一个屏幕目标scr = screen_create(_INT_FRATE, _INT_WIDTH, _INT_HEIGHT);

if(NULL == scr)

exit(EXIT_FAILURE);

//绘制雪花动画 screen_flash_snow(scr);

//烧毁这个屏幕目标screen_destory(&scr);

return0;

}/** 创建一个 屏幕布局指针 前往

*

* int frate : 绘制一帧的周期

* int width : 屏幕宽度

* int height : 屏幕高度

* return : 指向屏幕布局的指针

* */structscreen* screen_create(intfrate,intwidth,int height)

{

structscreen *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*heightscr =malloc(sizeof(structscreen) +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** : 指向 屏幕布局指针的指针, 二级烧毁一级的

* */voidscreen_destory(structscreen** pscr)

{

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

return;

free(*pscr);

// 制止野指针*pscr = NULL;

}//构建开头 的雪花,底下宏表现每 _INT_SHEAD 个步长,一个雪花,必要是2的幂//static 可以了解为 private, 宏,位利用代码多了的确难读#define_INT_SHEAD (1<<2)staticvoid__snow_head(char* snow,int len)

{

intr =0;

//数据必要清空memset(snow,0, len);

for (;;) {

//取余一个本事 2^3 - 1 = 7 => 111 , 并就是取余数intt = 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)staticvoid__snow_next(structscreen* scr,int idx)

{

intwidth = scr->width;

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

char* snow = psnow + width;

inti, j, t;// i索引, j保存下一个刹时雪花的地点,t 暂且补得,处理雪花堆叠成绩

//为如今行重置memset(snow,0, width);

//经过上一次雪花地点 盘算下一次雪花地点for(i =0; i

for(t = psnow[i]; t>0; --t) {// 雪花可以堆叠

// rand()%_INT_SWING - 1 表现 雪花 横轴的偏移量,相对上一次地点j = i + rand() % _INT_SWING -1;

j = j<0? width -1: j >= width ?0: j;// j假如越界了,右方越界让它到右方,右方越界到右方++snow[j];

}

}

}/**

* 屏幕绘制函数,主要天生一个雪花后果

*

* struct screen* : 屏幕数据

* return : 0表现可以绘制了,1表现图案安定*/intscreen_draw_snow(structscreen* scr)

{

// 静态变量,默许初始化为0,每次都共用staticint__speed =0;

int idx;

if(++__speed != _INT_VSNOW)

return1;

//底下 就是 到了雪花飘落的时候了 既 __speed == _INT_VSNOW__speed =0;

//这里重新构建雪花界面,先构建头部,再从尾部开头构建for(idx = scr->height -1; idx >0; --idx)

__snow_next(scr, idx);

//构建头部__snow_head(scr->pix, scr->width);

return0;

}//buf 保存scr 中pix 数据,构建后为 (width+1)*height, 后方宏是雪花图案#define_CHAR_SNOW '*'
staticvoid__flash_snow_buffer(structscreen* scr,char* buf)

{

int i, j, rt;

intheight = scr->height, width = scr->width;

intfrate = scr->frate;//改造的帧频率

//每次都等一下for (;;sleep_ms(frate)) {

//开头绘制屏幕rt = screen_draw_snow(scr);

if (rt)

continue;

for(i =0;i

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

for(j =0; j

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

buf[rt++] ='\n';

}

buf[rt -1] ='\0';

//正式绘制到屏幕上 puts(buf);

//清空老屏幕,屏幕光标回到最外表 __curup(height);

}

}#undef_CHAR_SNOW/**

* 屏幕绘制动画后果, 绘制雪花动画

*

* struct screen* : 屏幕布局指针*/voidscreen_flash_snow(structscreen* 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;

}


跋文

到这里就完毕了,这次分享的比力简便,有兴致的同砚可以 看看, 保举写一遍. 代码看不懂的时分,多写写,看得懂的时分,多写写,

就有套路了. 接待吐槽. 错误是在所不免的.

这个冬天,雪花很美,(。⌒?⌒)

内容底部广告位(手机)
标签:

管理员
酒百科管理员

专业提供酒知识、酒文化的知识分享,做高价值酒的百科网站!

上一篇:雀巢和百威(《财富》世界500强公布:食饮行业雀巢排第一 华润、中粮、新希望上榜)
下一篇:返回列表