SDL_Texture移动动画

时间:2014-07-17 02:05:35

标签: c++ sdl sdl-2

我想为我的迷你游戏进行插值。有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;
    } 
}

1 个答案:

答案 0 :(得分:3)

这是一个最小(但完全有效)的例子:

#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;
}

为简单起见,它绘制矩形而不是纹理,但这很容易改变。

正如你所看到的,在那个例子中,只要动画不完整就保持旧坐标,并且只有当它完全消失时才能固定它。这很容易让它重新回放,并且没有精确度方面的问题;但是 - 如果您在动画播放时尝试按空格键,它将重新启动。

另一种方法是更新每个动画步骤的坐标(可能有不同的更新频率,然后重绘);在这种情况下,您需要保留当前坐标,目标坐标(动画完成后您将达到的坐标),并且可能还有起始坐标(以消除精度问题)。

相关问题