创意控制台:下雨动画特效(ASCII 雨滴下落)

在编程的世界里,控制台不仅仅是输出文本信息的工具,通过巧妙的代码设计,我们还能在其中创造出充满趣味的动态画面。本文将带领大家使用 C 语言打造一个创意控制台下雨动画特效,利用 ASCII 字符模拟雨滴下落的过程,为单调的控制台增添一份灵动与趣味。

一、实现思路

实现控制台下雨动画特效,主要围绕以下几个核心步骤展开:

  1. 定义雨滴状态:使用结构体来存储每一滴雨滴的位置、下落速度等信息,方便后续对雨滴进行管理和更新。
  2. 初始化雨滴:在程序开始时,随机生成一定数量的雨滴,并为它们设置初始位置和下落速度。
  3. 绘制雨滴:根据雨滴的当前状态,在控制台相应位置输出表示雨滴的 ASCII 字符,呈现雨滴下落的视觉效果。
  4. 更新雨滴状态:不断改变雨滴的位置,模拟下落过程。当雨滴到达控制台底部时,重新设置其位置,实现循环下落的效果。
  5. 控制动画节奏:通过设置合适的时间间隔,控制雨滴下落的速度和动画的流畅度,让下雨效果更加逼真。

二、代码实现详解

1. 引入头文件

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>  // 用于Windows系统控制台操作
  • stdio.h:提供标准输入输出函数,如printf用于在控制台输出雨滴。
  • stdlib.h:包含内存分配、随机数生成等函数,用于初始化雨滴状态和动态内存管理。
  • time.h:用于获取系统时间,作为随机数种子,使每次运行程序时雨滴的初始状态不同。
  • windows.h:在 Windows 系统下,用于控制台相关操作,如设置光标位置、清屏等。若在 Linux 或 macOS 系统,需使用其他函数实现类似功能,后续会进行说明。

2. 定义雨滴结构体

#define WIDTH 80  // 控制台宽度
#define HEIGHT 25 // 控制台高度
#define NUM_RAIN 100 // 雨滴数量typedef struct {int x;  // 雨滴x坐标int y;  // 雨滴y坐标int speed; // 雨滴下落速度
} Raindrop;
  • 定义了WIDTHHEIGHT常量,分别表示控制台的宽度和高度,方便控制雨滴的显示范围。
  • NUM_RAIN常量指定了雨滴的总数。
  • Raindrop结构体用于存储每一滴雨滴的信息,包括在控制台中的x坐标、y坐标以及下落速度。

3. 初始化雨滴函数

void init_raindrops(Raindrop raindrops[]) {srand(time(NULL));for (int i = 0; i < NUM_RAIN; i++) {raindrops[i].x = rand() % WIDTH;raindrops[i].y = 0;raindrops[i].speed = rand() % 3 + 1;  // 速度范围1 - 3}
}

  • init_raindrops函数接受一个Raindrop类型的数组作为参数。
  • 使用time(NULL)作为随机数种子,确保每次运行程序时雨滴的初始位置和速度都不相同。
  • 通过循环为每一滴雨滴随机生成在控制台宽度范围内的x坐标,初始y坐标设为 0(从控制台顶部开始下落),并随机赋予 1 到 3 之间的速度。

4. 绘制雨滴函数

void draw_raindrops(Raindrop raindrops[]) {COORD pos;  // 用于设置光标位置HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);  // 获取控制台句柄system("cls");  // 清屏for (int i = 0; i < NUM_RAIN; i++) {pos.X = raindrops[i].x;pos.Y = raindrops[i].y;SetConsoleCursorPosition(hConsole, pos);  // 设置光标位置printf("|");  // 输出雨滴}
}

  • draw_raindrops函数用于在控制台绘制雨滴。
  • 通过GetStdHandle(STD_OUTPUT_HANDLE)获取控制台句柄,使用system("cls")清屏,清除上一帧的雨滴。
  • 遍历雨滴数组,利用SetConsoleCursorPosition函数设置光标的位置到每一滴雨滴对应的坐标处,然后输出|字符模拟雨滴。

5. 更新雨滴状态函数

void update_raindrops(Raindrop raindrops[]) {for (int i = 0; i < NUM_RAIN; i++) {raindrops[i].y += raindrops[i].speed;if (raindrops[i].y >= HEIGHT) {raindrops[i].y = 0;raindrops[i].x = rand() % WIDTH;}}
}
  • update_raindrops函数用于更新每一滴雨滴的状态。
  • 通过循环,根据每滴雨滴的速度增加其y坐标,模拟下落过程。
  • 当雨滴的y坐标超出控制台高度时,将其y坐标重新设为 0(回到顶部),并随机生成新的x坐标,实现雨滴循环下落的效果。

6. 主函数

int main() {Raindrop raindrops[NUM_RAIN];init_raindrops(raindrops);while (1) {draw_raindrops(raindrops);update_raindrops(raindrops);Sleep(50);  // 控制动画速度,单位毫秒}return 0;
}
  • main函数中,首先定义了一个Raindrop类型的数组raindrops,用于存储所有雨滴的信息。
  • 调用init_raindrops函数初始化雨滴。
  • 通过一个无限循环,不断调用draw_raindrops函数绘制雨滴,调用update_raindrops函数更新雨滴状态,并使用Sleep(50)函数控制每次循环的时间间隔为 50 毫秒,从而控制动画的速度,使下雨效果更加自然流畅。

7. Linux 或 macOS 系统适配

如果要在 Linux 或 macOS 系统上运行该程序,需要对与 Windows 控制台操作相关的代码进行修改。

  • 清屏操作:将system("cls")替换为system("clear")
  • 设置光标位置:在 Linux 或 macOS 系统中,可以使用 ANSI 转义序列来设置光标位置,定义如下函数:
#include <unistd.h>void set_cursor_position(int x, int y) {printf("\033[%d;%dH", y, x);
}

然后将draw_raindrops函数中设置光标位置的部分修改为:

void draw_raindrops(Raindrop raindrops[]) {system("clear");  // 清屏for (int i = 0; i < NUM_RAIN; i++) {set_cursor_position(raindrops[i].x, raindrops[i].y);printf("|");  // 输出雨滴}
}

同时,由于 Linux 和 macOS 系统中没有Sleep函数,需要使用usleep函数(单位为微秒)来控制动画速度,将Sleep(50)修改为usleep(50000)(50 毫秒 = 50000 微秒)。

三、完整代码

Windows 系统版本

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>#define WIDTH 80
#define HEIGHT 25
#define NUM_RAIN 100typedef struct {int x;int y;int speed;
} Raindrop;void init_raindrops(Raindrop raindrops[]);
void draw_raindrops(Raindrop raindrops[]);
void update_raindrops(Raindrop raindrops[]);void init_raindrops(Raindrop raindrops[]) {srand(time(NULL));for (int i = 0; i < NUM_RAIN; i++) {raindrops[i].x = rand() % WIDTH;raindrops[i].y = 0;raindrops[i].speed = rand() % 3 + 1;}
}void draw_raindrops(Raindrop raindrops[]) {COORD pos;HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);system("cls");for (int i = 0; i < NUM_RAIN; i++) {pos.X = raindrops[i].x;pos.Y = raindrops[i].y;SetConsoleCursorPosition(hConsole, pos);printf("|");}
}void update_raindrops(Raindrop raindrops[]) {for (int i = 0; i < NUM_RAIN; i++) {raindrops[i].y += raindrops[i].speed;if (raindrops[i].y >= HEIGHT) {raindrops[i].y = 0;raindrops[i].x = rand() % WIDTH;}}
}int main() {Raindrop raindrops[NUM_RAIN];init_raindrops(raindrops);while (1) {draw_raindrops(raindrops);update_raindrops(raindrops);Sleep(50);}return 0;
}

Linux 或 macOS 系统版本

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>#define WIDTH 80
#define HEIGHT 25
#define NUM_RAIN 100typedef struct {int x;int y;int speed;
} Raindrop;void init_raindrops(Raindrop raindrops[]);
void draw_raindrops(Raindrop raindrops[]);
void update_raindrops(Raindrop raindrops[]);
void set_cursor_position(int x, int y);void init_raindrops(Raindrop raindrops[]) {srand(time(NULL));for (int i = 0; i < NUM_RAIN; i++) {raindrops[i].x = rand() % WIDTH;raindrops[i].y = 0;raindrops[i].speed = rand() % 3 + 1;}
}void set_cursor_position(int x, int y) {printf("\033[%d;%dH", y, x);
}void draw_raindrops(Raindrop raindrops[]) {system("clear");for (int i = 0; i < NUM_RAIN; i++) {set_cursor_position(raindrops[i].x, raindrops[i].y);printf("|");}
}void update_raindrops(Raindrop raindrops[]) {for (int i = 0; i < NUM_RAIN; i++) {raindrops[i].y += raindrops[i].speed;if (raindrops[i].y >= HEIGHT) {raindrops[i].y = 0;raindrops[i].x = rand() % WIDTH;}}
}int main() {Raindrop raindrops[NUM_RAIN];init_raindrops(raindrops);while (1) {draw_raindrops(raindrops);update_raindrops(raindrops);usleep(50000);}return 0;
}

将上述对应系统的代码保存为.c文件(如rain_animation.c),使用gcc编译器进行编译。例如在命令行中输入gcc rain_animation.c -o rain_animation,生成可执行文件后运行,就能在控制台欣赏到精彩的下雨动画特效了。通过这个项目,我们不仅掌握了 C 语言在控制台动画方面的应用,还了解了不同操作系统下控制台操作的差异,为今后更多创意编程项目打下坚实基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/78266.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL--索引入门

MySQL官方对索引的定义为&#xff1a;索引&#xff08;Index&#xff09;是帮助MySQL高效获取数据的数据结构。 Mysql在存储数据之外&#xff0c;数据库系统各种还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种引用&#xff08;指向&#xff09;表中的数据…

MIT XV6 - 1.2 Lab: Xv6 and Unix utilities - pingpong

接上文 MIT XV6 - 1.1 Lab: Xv6 and Unix utilities - user/_sleep 是什么&#xff1f;做什么&#xff1f; pingpong 不务正业了那么久(然而并没有&#xff0c;虽然还在探索sleep&#xff0c;但是教材我已经看完了前三章了)&#xff0c;让我们赶紧继续下去 在进行本实验之前请务…

前端面经-VUE3篇(二)--vue3组件知识(一)组件注册、props 与 emits、透传、插槽(Slot)

组件允许我们将 UI 划分为独立的、可重用的部分&#xff0c;并且可以对每个部分进行单独的思考。在实际应用中&#xff0c;组件常常被组织成一个层层嵌套的树状结构&#xff1a; 一、注册 Vue 组件本质上是一个可以复用的 自定义 HTML 元素&#xff0c;为了在其他组件中使用一…

LeetCode —— 102. 二叉树的层序遍历

&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️…

Linux第20节 --- inode和文件系统

一、没有被打开的文件 如果一个文件没有被打开&#xff0c;那么该文件存储在哪里&#xff1f; 该文件是存储在磁盘当中的&#xff01; 文件 文件内容 文件属性&#xff01; 文件的内容是按照数据块存储的&#xff1b;文件的属性其实就是inode&#xff08;是一个128字节的…

1.PowerBi保姆级安装教程

1.进入power bi网站 PowerBi下载链接 2.下载power bi软件 3.双击安装 4.下一步 5.下一步 6.下一步 7.下一步 8.安装 9.双击桌面图标

Android Studio中OpenCV应用详解:图像处理、颜色对比与OCR识别

文章目录 一、OpenCV在Android中的集成与配置1.1 OpenCV简介1.2 在Android Studio中集成OpenCV1.2.1 通过Gradle依赖集成1.2.2 通过模块方式集成1.2.3 初始化OpenCV 1.3 OpenCV基础类介绍 二、指定区域图像抓取与对比2.1 图像抓取基础2.2 指定区域图像抓取实现2.2.1 从Bitmap中…

前端面试每日三题 - Day 22

今天我们将深入探讨 JavaScript 中的 Set 和 Map 数据结构&#xff0c;了解它们的特性及应用场景。接下来&#xff0c;我们会分析 React 的 Suspense 和 Concurrent Mode 的工作原理&#xff0c;探索它们如何提升应用的性能和用户体验。最后&#xff0c;我们将学习如何设计一个…

[Vue]编程式导航

在 Vue 中&#xff0c;编程式导航是通过 JavaScript 代码&#xff08;而非 <router-link> 标签&#xff09;动态控制路由跳转的核心方式。这个方法依赖于 Vue Router 提供的 API&#xff0c;能更灵活地处理复杂场景&#xff08;如异步操作、条件跳转等&#xff09;。 一、…

邹晓辉教授十余年前关于围棋程序与融智学的思考,体现了对复杂系统本质的深刻洞察,其观点在人工智能发展历程中具有前瞻性意义。我们可以从以下三个维度进行深入解析:

邹晓辉教授十余年前关于围棋程序与融智学的思考&#xff0c;体现了对复杂系统本质的深刻洞察&#xff0c;其观点在人工智能发展历程中具有前瞻性意义。我们可以从以下三个维度进行深入解析&#xff1a; 一、围棋程序的二元解构&#xff1a;数据结构与算法的辩证关系 1.1.形式…

The Traitor King (10 player 25 player)

The Traitor King 十字军试炼尾王成就。叛变的国王&#xff1a;在30秒内杀死40只虫群甲虫。考验团队配合的成就。比不朽者&#xff0c;黑曜石31等等强度大&#xff0c;甚至感觉比宝库地风火难。

数据结构一 单链表

1.单链表 1.数据结构简介 程序数据结构算法 数据 数据&#xff08;data&#xff09;是客观事物的一个符号表示 数据元素&#xff08;data element&#xff09;是数据的基本单位&#xff0c;一 个数据元素可以由若干个数据项&#xff08;data item&#xff09;组成。数据项…

GPU集群监控系统开发实录:基于Prometheus+Grafana的算力利用率可视化方案

一、科研场景下的GPU监控痛点 在深度学习模型训练、分子动力学模拟等科研场景中&#xff0c;GPU集群的算力利用率直接影响着科研效率。笔者在参与某高校计算中心的运维工作时&#xff0c;发现以下典型问题&#xff1a; 资源黑洞现象&#xff1a;多课题组共享GPU时出现"抢…

【计算机视觉】三维重建: MVSNet:基于深度学习的多视图立体视觉重建框架

MVSNet&#xff1a;基于深度学习的多视图立体视觉重建框架 技术架构与核心算法1. 算法流程2. 关键创新 环境配置与实战指南硬件要求安装步骤数据准备&#xff08;DTU数据集&#xff09; 实战流程1. 模型训练2. 深度图推断3. 点云生成 常见问题与解决方案1. CUDA内存不足2. 特征…

智能家居的OneNet云平台

一、声明 该项目只需要创建一个产品&#xff0c;然后这个产品里面包含几个设备&#xff0c;而不是直接创建几个产品 注意&#xff1a;传输数据使用到了不同的power&#xff0c;还有一定要手机先联网才能使用云平台 二、OneNet云平台创建 &#xff08;1&#xff09;Temperatur…

aidermacs开源程序使用 Aider 在 Emacs 中进行 AI 配对编程

一、软件介绍 文末提供程序和源码下载 Aidermacs 通过集成 Aider&#xff08;最强大的开源 AI 配对编程工具之一&#xff09;为 Emacs 带来了 AI 驱动的开发。如果您缺少 Cursor&#xff0c;但更喜欢生活在 Emacs 中&#xff0c;Aidermacs 提供了类似的 AI 功能&#xff0c;同…

加密算法(一)-对称加密(DES、AES、3DES、Blowfish、Twofish)一篇了解所有主流对称加密,轻松上手使用。

一、对称加密算法 对称加密算法采用相同的密钥来进行加密和解密操作。其优点是加密和解密速度快&#xff0c;不过密钥的管理和分发存在一定的安全风险。 1.1、DES(已不推荐使用) 这是早期的对称加密算法&#xff0c;密钥长度为 56 位。但由于密钥长度较短&#xff0c;如今已不…

深度优先VS广度优先:算法选择的核心逻辑与实战指南

摘要 深度优先搜索&#xff08;DFS&#xff09;与广度优先搜索&#xff08;BFS&#xff09;是图结构遍历与路径分析的基础算法&#xff0c;也是最常见的搜索框架&#xff0c;在路径规划、社交网络分析、游戏AI等领域均有广泛应用。本文从算法思想、数据结构选择、时空复杂度和…

2025深圳杯、东三省数学建模B题数模AI全网专业性第一

为什么选择使用我的数模AI&#xff1f; 1.轻松辅导学生 2.小白也能翻身碾压大佬 3.突破知识壁垒&#xff0c;缩短与大佬的差距&#xff0c;打破不公平的教学资源&#xff0c;扭转差距 4.辅助商业服务&#xff0c;成本低 5.大模型本身有一定随机性&#xff0c;所以也不用担心…

使用MGeo模型高精度实现文本中地址识别

一、功能与安装 1、模型地址 模型是阿里开发的门址高精度识别模型。 https://modelscope.cn/models/iic/mgeo_geographic_elements_tagging_chinese_base/summary 注意&#xff1a;不能自己安装包&#xff0c;没法解决依赖问题&#xff0c;直接按照官方要求安装下面的包&am…