0

我正在使用 SDL 2.0 和 C++ 制作一个自上而下的等距游戏,但遇到了一个小故障。

当使用该SDL_RenderCopy函数将纹理渲染到屏幕上时,纹理顶部碰到屏幕顶部的那一刻,它会被向下推一个像素,从而导致下图所示的缺少边框:

没有注释的预编辑

使用注释进行后期编辑

以下是我特定于世界本身的渲染函数,因为世界的渲染与游戏中的其他一切都不同,因为我只是复制“源”纹理而不是为游戏中的每个图块加载纹理,这将是荒谬的低效。

//-----------------------------------------------------------------------------
// Rendering

DSDataTypes::Sint32 World::Render()
{
    //TODO: Change from indexing to using an interator (pointer) for efficiency
    for(int index = 0; index < static_cast<int>(mWorldSize.mX * mWorldSize.mY); ++index)
    {
        const int kTileType = static_cast<int>(mpTilesList[index].GetType());

        //Translate the world so that when camera panning occurs the objects in the world will all be in the accurate position

我还按如下方式合并了相机平移(由于我的游戏的面向对象设计,我的相机平移逻辑跨越多个文件,因此包含一些代码片段):

(上面的代码立即在下面继续)

        mpTilesList[index].SetRenderOffset(Window::GetPanOffset());

        //position (dstRect)
        SDL_Rect position;
        position.x = static_cast<int>(mpTilesList[index].GetPositionCurrent().mX + Window::GetPanOffset().mX);
        position.y = static_cast<int>(mpTilesList[index].GetPositionCurrent().mY + Window::GetPanOffset().mY);
        position.w = static_cast<int>(mpTilesList[index].GetSize().mX);
        position.h = static_cast<int>(mpTilesList[index].GetSize().mY);

        //clip (frame)
        SDL_Rect clip;
        clip.x = static_cast<int>(mpSourceList[kTileType].GetFramePos().mX);
        clip.y = static_cast<int>(mpSourceList[kTileType].GetFramePos().mY);
        clip.w = static_cast<int>(mpSourceList[kTileType].GetFrameSize().mX);
        clip.h = static_cast<int>(mpSourceList[kTileType].GetFrameSize().mY);

我对为什么会发生这种情况感到困惑,因为无论我是否包含我的简单剔除算法(如下所示),都会出现相同的结果。

(上面的代码立即在下面继续)

        //Check to ensure tile is being drawn within the screen size. If so, rendercopy it, else simply skip over and do not render it.
        //If the tile's position.x is greather than the left border of the screen
        if(position.x > (-mpSourceList[kTileType].GetRenderSize().mX))
        {
            //If the tile's position.y is greather than the top border of the screen
            if(position.y > (-mpSourceList[kTileType].GetRenderSize().mY))
            {
                //If the tile's position.x is less than the right border of the screen
                if(position.x < Window::msWindowSize.w)
                {
                    //If the tile's position.y is less than the bottom border of the screen
                    if(position.y < Window::msWindowSize.h)
                    {
                        SDL_RenderCopy(Window::mspRenderer.get(), mpSourceList[kTileType].GetTexture(), &clip, &position);
                    }
                }
            }
        }
    }

    return 0;//TODO
}
4

2 回答 2

0

答案的简短版本,在底部重述:

  • 通过修复我的数据类型问题,这使我能够修复我的数学库,这消除了像素部分舍入的问题,因为在渲染时屏幕上没有小于 1 但大于 0 的像素。

长答案:

我认为该问题是由将 2D 网格旋转到对角线等距透视时使用的偏移逻辑的舍入误差引起的,舍入误差仅在处理 -1 和 +1 之间的屏幕坐标时发生。

由于我基于从更改正交网格到 y 轴(行)上的对角网格的转换,这可以解释为什么单个像素偏移仅发生在屏幕的顶部边框而不是底部边框。

尽管每一行都有隐式舍入,但没有任何安全检查,只有从世界坐标到屏幕坐标的转换处理了正数和负数之间的舍入。

这一切背后的原因是因为我的模板化数学库有一个问题,我的很多代码都是基于类型定义的用户类型,例如:

typedef unsigned int Uint32;
typedef signed int Sint32;

所以我只是简单地使用DSMathematics::Vector2<float>而不是正确实现DSMathematics::Vector2<int>.

这是一个问题的原因是因为屏幕上不能有“半个像素”,因此必须使用整数而不是浮点值。

通过修复我的数据类型问题,这使我能够修复我的数学库,这消除了像素部分舍入的问题,因为在渲染时屏幕上没有小于 1 但大于 0 的像素。

于 2014-03-25T10:30:36.770 回答
0

当您将位置转换为整数时,您可能会遇到舍入错误。也许你应该四舍五入到最接近的整数,而不是只占地板(这就是你正在做的事情)。位置 (0.8, 0.8) 的图块将在像素 (0, 0) 处呈现,而它可能应该在位置 (1, 1) 处呈现。

或者您可以确保您的图块的大小始终是整数,那么错误不应该累积。

于 2014-03-04T14:08:52.040 回答