[教程]字符动画制作
2023-02-18 16:42:45 时间
实现效果
https://www.bilibili.com/video/av75231006
bad apple!!
制作步骤
一、用Pr把视频导出为帧图片和mp3
1.打开Pr,按ctrl+i导入需要制成字符动画的原视频
2.按ctrl+m导出为jpg图片,记得存进一个文件夹里,因为会导出大量图片,例如一个三分多钟六十帧的badApple就有一万三千多帧。
3.按ctrl+m导出为mp3,后期程序播放音频会用到 等待导出完成。
二、用ascgen2把帧图制成字符文本
1.选择帧图所在文件夹,导入所有图片(安装包在最下面有)
2.修改字符文本的一些属性,或者默认也可
3.修改分辨率和导出路径,点击导出
等待导出完成
三、编写程序,读取并打印文本
代码部分其实很简单,逻辑上只要做读取文件,播放音乐,并每间隔1/60秒打印输出一帧的字符即可,而在开始播放前,需要做一些初始化处理,如隐藏光标,调整控制台大小等:
void init(){
//隐藏光标
CONSOLE_CURSOR_INFO cursor_info = {1, 0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
SetConsoleTitle("字符badApple"); //控制台标题
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SMALL_RECT rc = {0,0, MAXCOL, MAXROW}; // 重置窗口位置和大小
SetConsoleWindowInfo(hOut,true ,&rc);
}
完整代码
#include<iostream>
#include<windows.h>
#include<ctime>
#include<string>
#include<cstdio>
#include<mmsystem.h>
#pragma comment(lib, "Winmm.lib")
#define MAXCOL 150
#define MAXROW 66
#define ZERO SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),{0,0})
// 150: 150x66
//100: 100x44
using namespace std;
char map[200][200];
void init(){
//隐藏光标
CONSOLE_CURSOR_INFO cursor_info = {1, 0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
SetConsoleTitle("字符badApple"); //控制台标题
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SMALL_RECT rc = {0,0, MAXCOL, MAXROW}; // 重置窗口位置和大小
SetConsoleWindowInfo(hOut,true ,&rc);
}
string getName(int num){
string fileSrcName = "badAppleTxt_150_60fps/ASCII-badApple60fps00000.txt";
int tmp = num;
int idx = fileSrcName.find('.')-1;
while(num!=0){
fileSrcName[idx--] = num%10+'0';
num/=10;
}
return fileSrcName;
}
int main(){
FILE *fp;
char chs[200];
int beginIdx = 4000;
string fileName;
int sum,x,y;
cout << "请输入任意键开始" << endl;
getchar();
init();system("mode con cols=150 lines=68");
//PlaySound("badApple.wav",NULL,SND_ASYNC);
mciSendString("play badApple.mp3", NULL, 0, NULL);
system("cls");
float cd = 1000/60.0f; //每秒60帧
clock_t beginClock = clock();
float totalCd = 0.0f;
for(int idx = 0;idx < 14000;idx+=1){
while(1){
if(clock()>=beginClock+(int)totalCd){
totalCd+=cd;
//读取
fileName.clear();
fileName = getName(idx);
if ((fp = fopen(fileName.c_str(), "r")) != NULL) { //打开一帧
x = 0;
while (!feof(fp)) { //只要该帧画面没读取完,就继续循环
fgets(chs, MAXCOL + 10, fp);
chs[MAXCOL] = '\0';
puts(chs);
//strcpy(map[x], chs);
x++;
}
fclose(fp);
}
else {
goto End;
};
break;
}
}
ZERO;
}
End:
return 0;
}
但这种直接读一帧输出一帧的方式会受cpu性能影响,可能出现音画不同步的情况,所以还有另一种输出方案,就是先把所有帧全部读取进数组,然后再播放输出:
先缓存再播放版本代码
#include<iostream>
#include<windows.h>
#include<ctime>
#include<string>
#include<cstdio>
#include<mmsystem.h>
#pragma comment(lib, "Winmm.lib")
#define MAXCOL 150
#define MAXROW 66
#define ZERO SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {0,0})
// 150: 150x66
//100: 100x44
using namespace std;
char map[14000][200][200];
void init(){
//隐藏光标
CONSOLE_CURSOR_INFO cursor_info = {1, 0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
SetConsoleTitle("字符badApple"); //控制台标题
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SMALL_RECT rc = {0,0, MAXCOL, MAXROW}; // 重置窗口位置和大小
SetConsoleWindowInfo(hOut,true ,&rc);
}
string getName(int num){
string fileSrcName = "badAppleTxt_150_60fps/ASCII-badApple60fps00000.txt";
int tmp = num;
int idx = fileSrcName.find('.')-1;
while(num!=0){
fileSrcName[idx--] = num%10+'0';
num/=10;
}
return fileSrcName;
}
int main(){
FILE *fp;
char chs[200];
int beginIdx = 4000;
string fileName;
int sum,x,y;
for(sum = 0;sum < 14000;sum++){
fileName.clear();
fileName = getName(sum);
if((fp = fopen(fileName.c_str(),"r"))!=NULL){ //打开一帧
x = 0;y = 0;
while(!feof(fp)){ //只要该帧画面没输出完,就继续循环
fgets(chs,MAXCOL+10,fp);
chs[MAXCOL] = '\0';
strcpy(map[sum][x],chs);
x++;
}
fclose(fp);
}
else {
break;
};
}
//输出
cout << "请输入任意键开始" << endl;
getchar();
init();system("mode con cols=150 lines=67");
//PlaySound("badApple.wav",NULL,SND_ASYNC);
mciSendString("play badApple.mp3", NULL, 0, NULL);
system("cls");
double cd = 1000/60.0; //每秒60帧
clock_t beginClock = clock();
double totalCd = 0.0;
for(int tmp = 0;tmp < sum;tmp++){
while(1){
if(clock()>=beginClock+(int)totalCd){
totalCd+=cd;
for( x = 0;x < MAXROW;x++){
puts(map[tmp][x]);
}
break;
}
}
ZERO;
}
return 0;
}
注意需要使用c++11标准,且要引入多媒体函数库 -lwinmm。 这里我使用的是devc,引入如图
下载链接
相关文章
- Java核心知识体系3:异常机制详解
- Java核心知识体系2:注解机制详解
- Java核心知识1:泛型机制详解
- Java:导出Excel大批量数据的优化过程
- Springboot返回数据null转空字符串
- java记录项目的UV值与PV值
- 小米手机自拍图标-小米Civi 1S体验:这次,男生也能自拍美颜了
- java文件网络路径转MultipartFile
- 百度短信接口以及人脸实名认证接口
- 怎样使用摄像机-索尼高清摄像机使用方法简要介绍【教程】
- 小米手机自拍图标-小米Civi 1S vs 小米9:最强自拍手机的后置镜头咋样?
- spring框架
- hexo博客插入音视频
- java实用小功能案例
- Excel自动化办公
- Open-CV图像处理
- open-CV的初步学习
- 树莓派 usb-使用您的树莓派
- NLP和知识图谱-neo4j安装和使用
- adobe cs6 系列软件通用破解补丁-Adobe CC全系列注册机-Adobe CC通用破解补丁1.1 中文免费版