SDL_Texture 移动动画
Posted
技术标签:
【中文标题】SDL_Texture 移动动画【英文标题】:SDL_Texture move animation 【发布时间】:2014-07-17 02:05:35 【问题描述】:我想为我的迷你游戏制作插值。有 2 个 SDL_Textures,当我先单击然后再单击时,它们的位置会交换,但没有移动动画。 那么如何为 SDL_Textures 制作动画位置交换呢?
void MainLoop()
SDL_Event Event;
float t = 0.0f;
float dt = 0.1f;
float currentTime = 0.0f;
float accumulator = 0.0f;
while (Running)
while(SDL_PollEvent(&Event))
OnEvent(&Event);
const float newTime = SDL_GetTicks();
float frameTime = newTime - currentTime;
const Uint32 maxFrameTime = 1000; // 1 sec per frame is the slowest we allow
if( frameTime > maxFrameTime)
frameTime = maxFrameTime;
currentTime = newTime;
accumulator += frameTime;
while( accumulator >= dt )
this->UpdatePositions(); // simulate a "frame" of logic at a different FPS than we simulate a frame of rendering
accumulator -= dt;
t += dt;
Render();
主要渲染方法:
void Puzzle::Render() const
SDL_RenderClear(renderer);
for (int i = 0; i < blocksNum; ++i)
Rectangle texRect = normalizeTexCoords(blockRect(blocks[i]));
Rectangle scrRectOrigin = blockRect(i);
DrawRect(scrRectOrigin, i, texRect);
SDL_RenderPresent(renderer);
void DrawRect(const Rectangle& screenCoords, int textureId, const Rectangle& textureCoord)
SDL_Texture *texture = blockTexture(blocks[textureId]);
renderTexture(texture, renderer, (int)screenCoords.left, (int)screenCoords.top, (int)blockWidth, (int)blockHeight);
//SDL_DestroyTexture(texture2);
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y, int w, int h)
// Destination rectangle position
SDL_Rect dst;
dst.x = x; dst.y = y; dst.w = w; dst.h = h;
SDL_RenderCopy(ren, tex, NULL, &dst);
在我的 UpdatePosition 方法中,我想让我的 SDL_Textures 移动,但它仍然在没有动画的情况下进行交换。
void Puzzle::UpdatePositions()
if (secondSwappedBlock != -1)
Rectangle firstRect = blockRect(blocks[firstSwappedBlock]);
firstRect.left += speed * deltaTime;
firstRect.right += speed * deltaTime;
SDL_Texture *texture = blockTexture(blocks[firstSwappedBlock]);
renderTexture(texture, renderer, (int)firstRect.left, (int)firstRect.top, (int)blockWidth, (int)blockHeight);
void Puzzle::SwapBlocks(const int first, const int second) const
if (first != second)
const int t = blocks[first];
blocks[first] = blocks[second];
blocks[second] = t;
【问题讨论】:
代码中的注释表明 update 和 render 是完全分离的东西(应该如此),但您的 update 函数调用renderTexture
而不是更新 blockRect
s。这是为什么? speed
是什么? deltaTime
是什么?你如何触发交换?为什么你的更新只重绘第一个块而不是第二个块,甚至没有计算它应该动画的方向(硬编码为“向右移动”,甚至没有指定多长时间)?
我正在尝试向某个方向移动图像,但它没有移动。我正在尝试更新 blockRect、speed 和 deltaTime,它是常量。添加交换块
你在没有任何动画的情况下改变了 SwapBlocks 中的坐标。当然,它会立即交换。动画开始应该只是提高一些标志并保存块的原始位置;然后,在每一帧上,计算新的位置,直到动画没有完全播放。然后放下动画标志并固定最终位置。
我想,在 SwapBlock 中我会立即更改坐标,在更新循环中我会精确地进行插值。而且以这种方式,我不明白为什么我需要“更新”方法,如果我都可以在 render 中做的话。你能用伪代码写 unswer 我会投票吗
【参考方案1】:
这是一个最小(但完全有效)的示例:
#include "SDL.h"
#include <assert.h>
/* linear interpolation between start.x; start.y and end.x; end.y */
static void rect_lerp(SDL_Rect *out, const SDL_Rect *start, const SDL_Rect *end, float f)
float t = 1.0f - f;
out->x = (float)start->x * t + (float)end->x * f;
out->y = (float)start->y * t + (float)end->y * f;
int main(int argc, char **argv)
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
SDL_Window *window = SDL_CreateWindow("example",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN);
assert(window);
SDL_Renderer *renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED);
assert(renderer);
int quit = 0;
int animate = 0;
Uint32 animation_start_time;
/* whole animation will play in e.g. one seconds */
const Uint32 animation_time_total = 1000;
SDL_Rect rect0 =
.x = 0, .y = 0, .w = 128, .h = 128
;
SDL_Rect rect1 =
.x = 256, .y = 256, .w = 128, .h = 128
;
while(!quit)
/* time of current frame */
Uint32 tcurrent = SDL_GetTicks();
SDL_Event event;
while(SDL_PollEvent(&event))
if(event.type == SDL_KEYUP)
if(event.key.keysym.sym == SDLK_ESCAPE)
quit = 1;
break;
else if(event.key.keysym.sym == SDLK_SPACE)
animate = 1;
animation_start_time = tcurrent;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_Rect r0 = rect0, r1 = rect1;
/* if not within animation - leave coordinates as they are */
if(animate)
if(tcurrent > animation_start_time + animation_time_total)
/* animation ends by now */
/* swap rect0 and rect1 and stop animation */
SDL_Rect t = rect0;
rect0 = rect1;
rect1 = t;
animate = 0;
/* need to update r0 and r1 too */
r0 = rect0;
r1 = rect1;
else
/* animation is incomplete - interpolate coordinates */
/* calculate current animation percentage - in range [0; 1] */
float factor = ((float)(tcurrent - animation_start_time)) / animation_time_total;
rect_lerp(&r0, &rect0, &rect1, factor);
rect_lerp(&r1, &rect1, &rect0, factor);
/* r0 and r1 now have correct coordinates, draw */
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(renderer, &r0);
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
SDL_RenderDrawRect(renderer, &r1);
SDL_RenderPresent(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
为简单起见,它绘制矩形而不是纹理,但这很容易改变。
如您所见,在该示例中,只要动画不完整,我就会保留旧坐标,并且仅在它完全消失时才对其进行修复。这很容易允许重放它并且没有精度问题;但是 - 如果您在动画已经播放时尝试按空格键,它将重新启动。
另一种方法是更新每个动画步骤的坐标(可能有不同的更新频率然后重绘);在这种情况下,您需要保留当前坐标、目标坐标(动画完成后您将到达的坐标)以及可能的起始坐标(以消除精度问题)。
【讨论】:
谢谢,太好了,我正在寻找精确的例子!以上是关于SDL_Texture 移动动画的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio 2017 C2027 使用未定义类型“SDL_Texture”