Cómo escribir el efecto de animación de la nieve en lenguaje C
#include?
#include?
#include?
#include?
/*
*? Comando de Shell/comando de consola para borrar la pantalla y algunas implementaciones dependientes de la plataforma
* Si se define __GNUC__, se supone que el compilador gcc se utiliza para la plataforma Linux
* En caso contrario, se supone que es la plataforma Windows
*/
#if?definido(__GNUC__)
//Lo siguiente depende de la implementación de Linux
#include?
# define?sleep_ms(m)?\
usleep(m?*?1000)
//Mover función del cursor hacia arriba?Linux
static?void ?__curup (int?altura)
{
int?i?=?-1;
mientras?(++i printf("\033[1A");?//¿Volver primero a la línea anterior? } #else? // ?Crear una función de espera? 1s? 60? cuadros? //?¿Crear una función de espera aquí en milisegundos?,?Necesita confiar en la implementación del sistema operativo #include? #define?sleep_ms(m)?\ Sleep(m) //Mover el cursor hacia arriba static?void?__curup(int?height) { COORD?cr?=?{0,0}; //?GetStdHandle(STD_OUTPUT_HANDLE)?Obtener el objeto de pantalla,?Establecer el cursor SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),?cr); } #endif?/*__GNUC__?¿El código multiplataforma es feo?*/ //?Define las macros de píxeles de ancho y alto de la pantalla inicial #define?_INT_WIDTH(100) #define?_INT_HEIGHT(50) //?La tasa de fotogramas de actualización de la pantalla #define?_INT_FRATE(40) //?La tasa de caída de los copos de nieve, en relación con el múltiplo de "marcos de actualización de pantalla" p> #define?_INT_VSNOW(10) /* *? Error al manejar la macro, el mensaje debe ser una constante de cadena encerrada entre " " *?__FILE__:?Ruta completa del archivo *?__func__:?Nombre de la función *?__LINE__:?Número de líneas *?__VA_ARGS__: ?Macro de parámetro variable, *?## indica conexión directa,?Por ejemplo?a##b?<=>?ab */ # define?cerr(msg,...)?\ fprintf(stderr,?"[%s:%s:%d]"?msg?"\n" ,__ARCHIVO__,__func__,__L INE__,##__VA_ARGS__); /* *?Estructura de pantalla,?Tiene?ancho y alto *?frate?:?Dibujar un marco El período, la unidad es milisegundos *?width?:?El ancho de la pantalla, basado en la esquina superior izquierda de la ventana (0,0) *?height ?:?El ancho de la pantalla Alto *?pix:? ¿Utiliza una dimensión para simular dos dimensiones? La estructura principal es la siguiente *?0?0?0? 1?0?0?1?0?1? 0 *?0?1?0?1?0?1?0?1?2?0 *? .?.?. *?=>?0 significa que no hay píxeles, ?1 significa 1 píxel, 2 significa 2 píxeles.... */ struct?screen?{ int?frate;?//?También puedes usar la estructura ?unsigned? int?width; int ?height; char? *pix; }; /* *?Crear un?puntero de estructura de pantalla?return * *?int?frate:?El período de dibujo de un fotograma *?int?width:?Ancho de pantalla *?int?height:?Alto de la pantalla *?return:?Puntero a la estructura de la pantalla *?*/ struct?screen*?screen_create (int?frate,?int?width,?int ?height); /* * Destruye un puntero de estructura de pantalla y déjalo en blanco * ?struct?screen**?:?Puntero a?puntero de estructura de pantalla,?destrucción nivel-nivel *?*/ void?screen_destory(struct?screen**?pscr ); *?*/ void?screen_destory(struct?screen**?pscr); /** *?Función de dibujo de pantalla, genera principalmente un efecto de copo de nieve * *?struct?screen*?:? Datos de pantalla *?return? :?0 significa que se puede dibujar, 1 significa que el patrón permanece sin cambios */ int?screen_draw_snow(struct?screen* ?scr); /** *?Efecto de animación de dibujo de pantalla,? Animación de dibujo de copo de nieve * *?struct ?screen*?:?Puntero de estructura de pantalla p> */ void?screen_flash_snow(struct?screen*?scr); //?Función principal, el negocio principal se ejecuta aquí int?main(int?argc,?char?*argv[]) { struct?screen*?scr? =?NULL; //Crear un objeto de pantalla scr?=?screen_create(_INT_FRATE,?_INT_WIDTH,?_INT_HEIGHT); if?(NULL ?==?scr) exit(EXIT_FAILURE); //Dibujar animación de copo de nieve screen_flash_snow(scr); / /Destruir este objeto de pantalla screen_destory(&scr); return?0; } /* *?¿Crear un?Puntero de estructura de pantalla? Retorno * *?int?frate:?El período de dibujo de un cuadro *? int?width:?Ancho de pantalla *?int?height:?Alto de pantalla *?return:?Puntero a la estructura de la pantalla *?* / struct?screen* screen_create(int?frate,?int?width,?int?height) { estructura ?screen?*scr?=?NULL; if?(frate<0?||?width?<=?0?||?height?<=?0)?{ cerr("[ADVERTENCIA]check?is?frate<0?||?width<=0?||?height<=0?err!"); return?NULL } //A continuación se muestra la memoria asignada para scr->pix?width*height scr?=?malloc(sizeof(struct ?screen)? +?sizeof(char)*width*height); if?(NULL?==?scr)?{ cerr("[FATALG]¡Sin? memoria! "); return?NULL; } scr->frate?=?frate; scr ->ancho? =?width; scr->height?=?height; //Reducir el número de mallocs, el consumo de malloc es muy grande, pérdidas de memoria, fragmentación de la memoria scr->pix?=?((char?*)scr)?+?sizeof(struct?screen); return?scr; } /* * Destruye un puntero de estructura de pantalla y déjalo en blanco *?struct?screen**:?points to? El puntero del puntero de estructura de pantalla, ?Destrucción nivel-nivel *?*/ void screen_destory(struct?screen**?pscr) { si?(NULL?==?pscr?||?NULL?==?*pscr) return; gratis(*pscr); //?Evita los punteros salvajes *pscr?=?NULL; } / /Construye el copo de nieve al principio. La siguiente macro significa que cada tamaño de paso _INT_SHEAD, un copo de nieve, debe ser una potencia de 2 // ¿estático puede entenderse como código de operación de bits?macro privado. Es realmente difícil de leer. #define?_INT_SHEAD?(1<<2) static?void?__snow_head(char*?snow,?int?len) { int?r?=?0; //Los datos deben borrarse memset(snow,?0,?len); for?(;;)?{ //¿Un truco para tomar el resto?2^3?-?1?=?7?=>?111?,?The union tomará el resto int?t?=?rand()?&?(_INT_SHEAD?-?1); if?(r?+?t?> =?len) p> romper; nieve[r?+?t]?=?1; r?+=?_INT_SHEAD ; } } #undef?_INT_SHEAD //Pass?Previous?scr->pix[scr-> ancho *(idx-1)]?=>?scr->pix[scr->width*idx] //¿La siguiente macro estipula que los copos de nieve se mueven hacia la izquierda y hacia la derecha un píxel? a la izquierda, ?1? significa sin cambios, ?2 significa un píxel a la derecha #define?_INT_SWING?(3) static?void?__snow_next(struct?screen*? scr, ?int?idx) { int?width?=?scr->ancho; char*?psnow?=?scr-> pix? +?width*(idx?-?1); char*?snow?=?psnow?+?width; int?i,?j,?t ;? ///?i índice,?j guarda la posición del siguiente copo de nieve instantáneo, t? se compensa temporalmente para resolver el problema de superposición del copo de nieve //Restablecer para la fila actual memset(snow,?0 ,?width) ; //¿Calcular la siguiente posición del copo de nieve hasta la última posición del copo de nieve? for?(i?=?0;?i for?(t?=?psnow[i];?t>0;?--t)?{?//?Los copos de nieve pueden superponerse // ?rand() %_INT_SWING?-?1? representa el desplazamiento del eje horizontal del copo de nieve, con respecto a la posición anterior j?=?i?+?rand()?%?_INT_SWING? -?1; j?=?j<0width?-?1?:?j?>=?width0?:?j;?//?jSi cruza el límite, el lado izquierdo cruza el límite y va hacia la derecha, y el lado derecho cruza el límite hacia la Izquierda ++snow[j]; } } p> } /** *?Función de dibujo de pantalla, genera principalmente un efecto de copo de nieve * * ?struct?screen*?:?Datos de pantalla *?return?:?0 significa que se puede dibujar, 1 significa que el patrón permanece sin cambios */ int screen_draw_snow(struct?screen*?scr) { //?Variable estática, inicializada a 0 de forma predeterminada, utilizada siempre estática?int?__velocidad?=?0; int?idx; if?(++__velocidad?!=?_INT_VSNOW) return?1; // ¿Siguiente? ¿Es hora de que caigan los copos de nieve? __speed?==?_INT_VSNOW __speed?=?0; //Reconstruya la interfaz del copo de nieve aquí, primero construya el encabezado y construya desde la cola for?(idx?=?scr->height?-?1;?idx?>?0;? --idx) __snow_next (scr,?idx); //Construir la cabeza __snow_head(scr->pix,?scr->width ); return?0 ; } //buf?Guarda los datos de pix en scr?, después de la construcción es?(ancho+1 )*height,?La siguiente macro es un patrón de copo de nieve #define?_CHAR_SNOW?'*' static?void?__fla sh_snow_buffer(struct?screen*?scr,?char*?buf) { int?i,?j,?rt; int?height ?=?scr->height,?width?=?scr->width; int?frate?=?scr->frate;?//Actualizar frecuencia de fotogramas / /Esperar cada vez para?(;;sleep_ms(frate))?{ //Empezar a dibujar la pantalla rt?=?screen_draw_snow (scr ); si?(rt) continuar; para?(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'; //Dibujado formalmente en la pantalla puts(buf); //Borrar la pantalla anterior y devolver el cursor de la pantalla a la parte superior __curup(height); } } #undef?_CHAR_SNOW /** *? ¿Efecto de animación de dibujo de pantalla,? * *?struct?screen*?:?Puntero de estructura de pantalla */ void screen_flash_snow(struct?screen* ?scr ) { char*?buf?=?NULL; //?Inicializa la semilla de números aleatorios y cambia la trayectoria del copo de nieve srand((unsigned)time(NULL)); buf?=?malloc(sizeof(char)*(scr->width?+?1)*scr->height); if?(NULL?==?buf)?{ cerr("[FATAL]¿Sin?memoria!"); exit( EXIT_FAILURE); } __flash_snow_buffer(scr,?buf); ///1. .?2. Para buf=NULL, este tipo de código se puede omitir, dependiendo de los hábitos de programación free(buf); buf?=?NULL; }