如何用C语言画出69岁的老同志?年轻人不讲武德!

在这里插入图片描述
在这里插入图片描述

马大师效果预览

马老师经典名言:年轻人不讲武德,我劝你耗子尾汁!

这是一个非常有意思的水博客,年轻人不讲武德。先看看效果:
在这里插入图片描述

进入正题(详细步骤)

思路分析

视频

众所周知,视频都是由一帧一帧的图片构成的,在播放的时候,每一帧图片的快速切换就形成了我们看到的动画。这是我提取的图片帧:
在这里插入图片描述

字符

所以,我们C语言输出的马老师也是一样的道理,只不过快速切换的不是图片帧,而是由字符构成的字符帧:
在这里插入图片描述

具体实现

那我们从视频得图片帧,最后得到字符帧呢?
两个软件:PremiereAscgen2

第一步:Premiere

Premiere是一个强大的剪辑软件,这里我们是用来提取视频中的图片帧:
先将视频导入Pr里面,然后选中视频按Ctrl+M,导出格式选择PNG,勾选导出为序列:
在这里插入图片描述
然后我们就得到图片帧了。

第二步:Ascgen2,得到字符视频

然后我们打开Ascgen2,按Ctrl+B,打开批量转换:
在这里插入图片描述
将图片帧的目录加入进来,然后自己设置一下转换后字符矩阵的大小,字符帧就完成了:
在这里插入图片描述

代码实现

资源准备好了,开始动手写代码。
字符帧最后是用的字符数组存的,这样编译后就形成了一个exe整体,不需要再读取外部数据了,所以我把字符帧放进了一个 rescore.h 头文件里。
不过我们现在得到了字符文本,它们是很多个文件,我们怎么把它合并成一个头文件?手动复制?累死!
首先我们在字符文本目录下新建一个 cmd.dat 文件,内容如下:
在这里插入图片描述
在这里插入图片描述
然后我们双击cmd.dat,随后我们就得到了一个 path.txt文件,这个文件存储了当前文件夹下,所有文件的名字 ,也就是 所有字符帧文件的名字
在这里插入图片描述
代码目录结构:
在这里插入图片描述
其中 rescore.h 头文件是creatRescore.cpp生成出来的。
字符帧 和 path.txt文件都在 ==RESCORE \ TXT == 目录下。
main.exe是我们最后生成的效果。

creatRescore.cpp代码:

#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <string.h>
#pragma comment(lib, "winmm.lib")
#define FPS 10.92
#define TXT_PATH "RESCORE\\TXT\\"
#define FILE_NAME "path.txt"
#define COUNT (1818) //一共有多少帧
#define SIZE 115584  //一帧的大小(B)
void gotoxy(short i, short j)
{
    COORD position = {j, i};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), position);
    CONSOLE_CURSOR_INFO cursor_info = {1, 0};
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
bool isError(FILE *fptr)
{
    if (fptr == NULL)
        return true;
    return false;
}
void fun()
{
    char path[200] = TXT_PATH;
    FILE *fptr, *pptr, *rescore;
    rescore = fopen("rescore.h", "wb+"); //生成我们的资源头文件
    int cell, i;
    pptr = fopen(TXT_PATH FILE_NAME, "r"); //打开我们存储字符图片名的文件
    if (isError(pptr))
    {
        puts("path not found.");
        puts(TXT_PATH FILE_NAME);
        puts("Error");
        getchar();
        return;
    }
    //写入头文件的预处理部分
    fprintf(rescore, "#define SIZE (%d)\n", SIZE);
    fprintf(rescore, "#define COUNT (%d)\n", COUNT);
    fprintf(rescore, "#define FPS %lf\n", FPS);
    fputs("char rescore[COUNT][SIZE+1]{\n", rescore);

    //读取字符帧
    for (i = 0; i < COUNT; i++)
    {
        gotoxy(0,0);
        printf("%d\n",i);
        fgets(path + strlen(TXT_PATH), 200, pptr); //每次循环读取一张字符帧的名字
        path[strlen(path) - 1] = '\0';
        fptr = fopen(path, "r"); //打开字符帧文件
        if (isError(fptr))
        {
            puts(path);
            puts("Error");
            getchar();
            return;
        }
        //将字符帧写入头文件
        fputs("{\n\"", rescore);
        int c=0;
        while ((cell = fgetc(fptr)) != EOF)
        {
            if (cell == '\n')
                fputs("\\n\"\n\"", rescore);
            else
                fputc(cell, rescore);
            c++;
        }
        printf("一帧的大小:%d\n",c);
        fseek(rescore, -1, SEEK_CUR);
        fputs("},\n", rescore);
        fclose(fptr);
    }
    fseek(rescore, -1, SEEK_END), fputs("};", rescore);
    fclose(rescore);//关闭头文件
    fclose(pptr);//关闭路径文件
    getchar();
}
int main(void)
{
    fun();
}

main.cpp代码:

#include <stdio.h>
#include <windows.h>
#include "rescore.h"
void gotoxy(short i, short j)
{
    COORD position = {j, i};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), position);
    CONSOLE_CURSOR_INFO cursor_info = {1, 0};
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
void init(int width, int height)
{

    //----------------------设置控制台字体大小---------------------------------
    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获取控制台输出句柄
    CONSOLE_FONT_INFOEX cfi;
    cfi.cbSize = sizeof cfi;
    cfi.nFont = 0;
    cfi.dwFontSize.X = 2; //字宽
    cfi.dwFontSize.Y = 2; //字高
    cfi.FontFamily = FF_DONTCARE;
    cfi.FontWeight = FW_NORMAL;        //粗细
    wcscpy_s(cfi.FaceName, L"Raster"); //设置字体,此处设为点阵字体
    SetCurrentConsoleFontEx(handle_out, FALSE, &cfi);

    //----------------------设置控制台窗口大小--------------------------------------
    char str[20];
    sprintf(str, "mode %d,%d", width, height);
    system(str);

    //----------------------设置控制台缓冲区大小------------------------------------
    CONSOLE_SCREEN_BUFFER_INFO scbi;               //定义一个窗口缓冲区信息结构体
    COORD size = {(short)width, (short)height};                  //定义一个坐标结构体
    GetConsoleScreenBufferInfo(handle_out, &scbi); //获得窗口缓冲区信息
    SetConsoleScreenBufferSize(handle_out, size);  // 重新设置缓冲区大小
}
int main(void)
{
    MessageBox(NULL,"年轻人不讲武德","马保国",0);
    int h, w;
    //scanf("%d%d",&h,&w);
    printf("输入窗口大小:");
    int x,y;
    scanf("%d%d",&x,&y);
    init(x, y);
    int i;
    // mciSendString(TEXT("play " WMA_PATH WMA_NAME), NULL, 0, NULL);
    for (i = 0; i < COUNT; i++) //输出字符帧
    {
        gotoxy(0, 0);
        puts((const char *)rescore[i]);
        Sleep(1000 / FPS);
    }
    getchar();
}

我们先编译运行 creatRecsore.cpp ,得到 rescore.h 头文件。
然后编译运行 main.cpp ,就得到了我们 最终的程序main.exe

最终效果:

在这里插入图片描述

最后因为字符比较多,编译出来的exe有200多兆。。。
我这里一帧是由 115584个ascll码 组成,一共1818帧,算一下那就是:

115584B * 1818 = 210131712B = 205206.75KB = 200.4MB.

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用windows api 做的贪吃蛇 #include #include"resource.h" #include"Node.h" #include #include TCHAR szAppname[] = TEXT("Snack_eat"); #define SIDE (x_Client/80) #define x_Client 800 #define y_Client 800 #define X_MAX 800-20-SIDE //点x的范围 #define Y_MAX 800-60-SIDE //点y的范围 #define TIME_ID 1 #define SECOND 100 #define NUM_POINT 10 //点的总个数 #define ADD_SCORE 10 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; //窗口句柄 MSG msg; //消息 WNDCLASS wndclass; //窗口类 HACCEL hAccel;//加速键句柄 wndclass.style = CS_HREDRAW | CS_VREDRAW; //窗口的水平和垂直尺寸被改变时,窗口被重绘 wndclass.lpfnWndProc = WndProc; //窗口过程为WndProc函数 wndclass.cbClsExtra = 0; //预留额外空间 wndclass.cbWndExtra = 0; //预留额外空间 wndclass.hInstance = hInstance; //应用程序的实例句柄,WinMain的第一个参数 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //设置图标 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //载入预定义的鼠标指针 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //设置画刷 wndclass.lpszMenuName = szAppname; //设置菜单 wndclass.lpszClassName = szAppname; //设置窗口类的名字 if (!RegisterClass(&wndclass))//注册窗口类 { MessageBox(NULL, TEXT("这个程序需要windows NT!"), szAppname, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppname, TEXT("Snack_eat"),//CreateWindow函数调用时,WndProc将受到WM_CREATE WS_OVERLAPPEDWINDOW&~WS_THICKFRAME& ~WS_MAXIMIZEBOX,//普通的层叠窗口&禁止改变大小&禁止最大化 CW_USEDEFAULT, //初始x坐标(默认) CW_USEDEFAULT, //初始y坐标 x_Client, //初始x方向尺寸 770 y_Client, //初始y方向尺寸 750 NULL, //父窗口句柄 NULL, //窗口菜单句柄 hInstance, //程序实例句柄 WinMain函数中第二个参数 NULL); //创建参数 ShowWindow(hwnd, iCmdShow);//显示窗口,iCmdShow是WinMain的第四个参数,决定窗口在屏幕中的初始化显示形式,例:SW_SHOWNORMAL表示正常显示 UpdateWindow(hwnd);//使窗口客户区重绘,通过向WndProc发送一条WM_PAINT消息而完成的 hAccel = LoadAccelerators(hInstance, szAppname);//加载加速键 while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }/* while (GetMessage(&msg, NULL, 0, 0))//GetMessage函数从消息队列中得到消息,填充msg。如果msg.message等于WM_QUIT,返回0,否则返回非0 { TranslateMessage(&msg);//将msg返回给windows已进行某些键盘消息的转换 DispatchMessage(&msg);//将msg再次返回给windows }*/ return msg.wParam;//msg.wParam是PostQuitMessage函数的参数值,通常是0 } ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值