实现黑客帝国的片头字符雨并控制其停止,显示“The Matrix”
程序员文章站
2024-03-19 16:59:46
...
最近在学图形学,作业涉及到做一个字符雨动画,这不禁让我想到黑客帝国的片头,黑客帝国的特效以及其跨时代意义在今天看来都令人惊叹,可见创作者对未来的洞悉,也能深深感受到计算机图形学的无穷魅力。
因为OpenGL的框架略微繁琐,之前对一些图形学原理知识比如图形生成算法、裁剪算法、曲线生成算法等等,一直用EasyX二维图形库去进行绘制,这里也一样,其实和OpenGL相比不过就是简化了那些配置,变成了2维,反而更便于对一些原理知识的验证、实现。
字符雨的实现的一些细节:(注释中都已给出)
(1)随机生成字符要用随机种子,否则会出现很多重复内容。
(2)明暗度和结束时的过渡效果我们就用RGB的255表示方法从0~255逐渐变亮代替。
(3)还有就是字符的更新,就是简单的后者替换前者并生成最开始新的字符。
效果:
最终:
代码:
#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>
//屏幕的宽高(我屏幕的分辨率是1366*768)
#define Height 768
#define Width 1366
#define fontsize 25//字符大小
int CharNum[Width/fontsize][Height/fontsize];//每个字符的ASCII码
int RowNum[Width/fontsize];//每一列字符的数量
int row_num=Width/fontsize,column_num=Height/fontsize;//全部充满字符时的行数列数
int Green_level[Width/fontsize];//每列字符的颜色明暗
int flag=0;//控制是否播放随机字符
void startup() // 数据初始化
{
//对字符数组进行初始化
srand((unsigned) time(NULL));//设置随机种子
int i,j;
for(i=0;i<row_num;i++){
RowNum[i]=rand()%(column_num*9/10)+column_num/10;//随机产生每一列字符的数量
for(j=0;j<RowNum[i];j++){
CharNum[i][j]=rand()%26+65;//产生A—Z的随机ASCII码
}
}
//开始绘制
initgraph(Width,Height);
BeginBatchDraw();
}
void clean()//清除上一帧
{
clearrectangle(0,0,Width-1,Height-1);
}
void show() // 显示画面
{
int i,j;
if(!flag){
for(i=0;i<row_num;i++){
int x=i*fontsize;//当前字符的x坐标
for(j=0;j<RowNum[i];j++){
int y=j*fontsize;//当前字符的y坐标
//输出字符
setfont(25,10, _T("Courier"));
setcolor(RGB(0,Green_level[i],0));
outtextxy(x,y,CharNum[i][j]);
}
}
}
//控制字符雨何时结束并显示The Matrix
static int time=0;
time++;
if(time>=175){//为了有渐隐的结束效果,设置亮度逐渐降低
for(i=0;i<row_num;i++){
if(Green_level[i]>=10){
Green_level[i]-=10;
}
}
}
if(time==200){
flag=1;
}
if(flag){
setfont(60,20, _T("Courier"));
setcolor(RGB(0,255,0));
outtextxy(Width/2-150,Height/2,_T("The Matrix"));
}
FlushBatchDraw();
Sleep(100);
}
void updateWithoutInput() // 与用户输入无关的更新
{
int i,j;
srand((unsigned) time(NULL));//设置随机种子
//每一帧向下移动,最上面产生新的字符
for(i=0;i<row_num;i++){
if(RowNum[i]<column_num){//对于当前列字符数没填满屏幕的
for(j=RowNum[i]-1;j>0;j--){
CharNum[i][j]=CharNum[i][j-1];//上一个字符代替下一个
}
RowNum[i]++;
CharNum[i][0]=rand()%26+65;//生成最上面的新的字符
}else{//如果已经满了就降低字符亮度
if(Green_level[i]>40){
Green_level[i]-=20;
}else{//降到一定程度后重新生成字符
RowNum[i]=rand()%(column_num/3)+column_num/10;//随机产生当前列列字符的数量
Green_level[i]=rand()%75+180;//随机产生当前列列字符的亮度
for(j=0;j<RowNum[i];j++){
CharNum[i][j]=rand()%26+65;//随机产生当前列列字符ASCII码
}
}
}
}
}
void updateWithInput() // 与用户输入有关的更新
{
//null
}
void gameover()//结束时调用的函数
{
EndBatchDraw();
getch();
closegraph();
}
int main()
{
startup(); // 数据初始化
while (1) // 游戏循环执行
{
clean();//清除上一帧画的
updateWithoutInput(); // 与用户输入无关的更新
updateWithInput(); // 与用户输入有关的更新
show(); // 显示画面
}
gameover();
return 0;
}
上一篇: 2048AI设计与实现
下一篇: linux服务器中svn的安装与配置