(译)SDL编程入门(14)动画精灵和VSync
动画精灵和VSync
动画简而言之就是展示一个又一个的图像来制造运动的假象。在这里我们将展示不同的精灵来制作一个简笔画的动画。
假设我们有以下动画帧(这清楚地表明我不是动画师):
而且每隔十分之一秒就显示一个,我们会得到这个动画:
由于SDL 2中的图像是典型的SDL_Textures,所以在SDL中的动画是一个接一个地显示纹理的不同部分(或不同的整体纹理)。
//走路动画
const int WALKING_ANIMATION_FRAMES = 4;
SDL_Rect gSpriteClips[ WALKING_ANIMATION_FRAMES ];
LTexture gSpriteSheetTexture;
所以,这里我们有带有精灵的精灵表,我们要用它来制作动画。
//为窗口创建垂直同步渲染器
gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
if( gRenderer == NULL )
{
printf( "Renderer could not be created! SDL Error: %sn", SDL_GetError() );
success = false;
}
对于本篇(以及未来的教程),我们要使用垂直同步。VSync允许渲染在垂直刷新期间与你的显示器更新时同步更新。对于本教程,它将确保动画不会运行得太快。大多数显示器以每秒60帧左右的速度运行,这是我们在这里做的假设。如果你有一个不同的显示器刷新率,这将解释为什么动画运行太快或太慢。
bool loadMedia(){
//Loading success flag
bool success = true;
//Load sprite sheet texture
if( !gSpriteSheetTexture.loadFromFile( "14_animated_sprites_and_vsync/foo.png" ) )
{
printf( "Failed to load walking animation texture!n" );
success = false;
}
else
{
//Set sprite clips
gSpriteClips[ 0 ].x = 0;
gSpriteClips[ 0 ].y = 0;
gSpriteClips[ 0 ].w = 64;
gSpriteClips[ 0 ].h = 205;
gSpriteClips[ 1 ].x = 64;
gSpriteClips[ 1 ].y = 0;
gSpriteClips[ 1 ].w = 64;
gSpriteClips[ 1 ].h = 205;
gSpriteClips[ 2 ].x = 128;
gSpriteClips[ 2 ].y = 0;
gSpriteClips[ 2 ].w = 64;
gSpriteClips[ 2 ].h = 205;
gSpriteClips[ 3 ].x = 196;
gSpriteClips[ 3 ].y = 0;
gSpriteClips[ 3 ].w = 64;
gSpriteClips[ 3 ].h = 205;
}
return success;
}
在加载完精灵表后,我们要定义各个动画帧的精灵。
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//Current animation frame
int frame = 0;
在主循环之前,我们必须声明一个变量来跟踪当前的动画帧。
//渲染当前帧
SDL_Rect* currentClip = &gSpriteClips[ frame / 4 ];
gSpriteSheetTexture.render( ( SCREEN_WIDTH - currentClip->w ) / 2, ( SCREEN_HEIGHT - currentClip->h ) / 2, currentClip );
//Update screen
SDL_RenderPresent( gRenderer );
在主循环中清空屏幕后,我们要渲染当前帧的动画。
动画从第0帧到第3帧,由于动画只有4帧,所以我们要把动画的速度放慢一点。这就是为什么当我们得到当前裁剪精灵时,我们要将帧除以4。这样实际的动画帧只每4帧更新一次,因为用int数据类型0/4=0,1/4=0,2/4=0,3/4=0,4/4=1,5/4=1,等等。
当我们得到当前的精灵后,我们要把它渲染到屏幕上,并更新屏幕。
//转到下一帧
++frame;
//循环动画
if( frame / 4 >= WALKING_ANIMATION_FRAMES )
{
frame = 0;
}
}
现在为了让帧更新,我们需要每一帧递增帧值。如果我们不这样做,那么动画将停留在第一帧。
我们还想让动画循环,所以当帧达到最终值(16 / 4 = 4)时,我们将帧重置为0,这样动画就会重新开始。
在我们通过递增或循环更新帧到0之后,我们就到达了主循环的终点。这个主循环将不断地显示一帧并更新动画值,使精灵产生动画。
参考资料
[1]
这里: http://www.lazyfoo.net/tutorials/SDL/14_animated_sprites_and_vsync/14_animated_sprites_and_vsync.zip
[2]
原文链接: http://www.lazyfoo.net/tutorials/SDL/14_animated_sprites_and_vsync/index.php
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python接口测试环境搭建过程详解
- 使用已经得到的keras模型识别自己手写的数字方式
- 解决keras使用cov1D函数的输入问题
- PHP PDOStatement::getColumnMeta讲解
- PHP PDOStatement::nextRowset讲解
- PHP _construct()函数讲解
- PHP PDOStatement::rowCount讲解
- Python 如何对文件目录操作
- Python字符串split及rsplit方法原理详解
- Laravel框架文件上传功能实现方法示例
- python中如何写类
- 什么是PHP7中的孤儿进程与僵尸进程
- Python爬虫小例子——爬取51job发布的工作职位
- 详解PHP素材图片上传、下载功能
- Python enumerate() 函数如何实现索引功能