C# 平滑的SDL2精灵运动

C# 平滑的SDL2精灵运动,c#,.net-core,sdl-2,C#,.net Core,Sdl 2,我制作了一个具有视差效果的场景。我无法使精灵沿X轴平滑移动。问题是,无论我使用的是SDL\u RenderCopyF还是SDL\u RenderCopy,当缓慢移动时,精灵都会根据监视器的像素网格绘制,并伴有抖动效应, 当有许多层时,每个人都以不同的速度移动 我的问题是 但是有一个版本的SDL2不支持浮点渲染,作者不得不对其进行修补。从2.0.10.0版开始,SDL\u RenderCopyF,SDL\u FRect和其他功能已添加到SDL中,使用这些功能可以实现亚像素移动精灵,但我无法让它们在

我制作了一个具有视差效果的场景。我无法使精灵沿X轴平滑移动。问题是,无论我使用的是
SDL\u RenderCopyF
还是
SDL\u RenderCopy
,当缓慢移动时,精灵都会根据监视器的像素网格绘制,并伴有抖动效应, 当有许多层时,每个人都以不同的速度移动

我的问题是 但是有一个版本的SDL2不支持浮点渲染,作者不得不对其进行修补。从2.0.10.0版开始,
SDL\u RenderCopyF
SDL\u FRect
和其他功能已添加到SDL中,使用这些功能可以实现亚像素移动精灵,但我无法让它们在我的场景中工作

全高清分辨率有10层。渲染在FullHD窗口中进行

窗口和渲染初始化代码:

void CreateWidnow()
{
    var windowFlags = Settings.Fullscreen ?
        SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN : Settings.Resizeble ? 
        SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE : SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN;
        
    renderWindow = SDL.SDL_CreateWindow(
        Settings.DebugMode ? $"{Settings.Title} [DEBUG]" : Settings.Title, SDL.SDL_WINDOWPOS_CENTERED, 
        SDL.SDL_WINDOWPOS_CENTERED,
        Settings.Resolution.Width,
        Settings.Resolution.Height,              
        windowFlags);
}

void CreateRenderer()
{
    if(Settings.VSinc) {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC |
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }
    else
    {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }   
}
void RenderLoop()
{
    bool cap = Settings.FPS > 0;
    var timer_fps = new Timer();
        
    ulong now_counter = SDL.SDL_GetPerformanceCounter();
    ulong last_counter = 0;
    double deltaTime = 0;
        
    while (renderLoop)
    {
        timer_fps.Start();
            
        last_counter = now_counter;
        now_counter = SDL.SDL_GetPerformanceCounter();
            
        deltaTime = (double)(now_counter - last_counter) / SDL.SDL_GetPerformanceFrequency();
            
        OnPreUpdate(deltaTime);
        OnUpdate(deltaTime);
        SDL.SDL_RenderPresent(renderer);
        OnPostUpdate(deltaTime);
            
        if( ( cap ) && ( timer_fps.GetTicks() < 1000 / Settings.FPS ) )
        {
            SDL.SDL_Delay( ( 1000 / Settings.FPS  ) - timer_fps.GetTicks() );
        }
            
    }
}
public Sprite(string path)
{
    Path = path;
    Transform = new Transform(new Point(0, 0));
    sprite = Image.IMG_LoadTexture(Game.RenderContext, path);
    SDL.SDL_QueryTexture(sprite, out format, out access, out width, out height); // get the width and height of the texture

    draw_rect = new SDL.SDL_FRect();
    draw_rect.w = width;
    draw_rect.h = height;
    scr_rect.x = 0; scr_rect.y = 0; scr_rect.w = width; scr_rect.h = height; 
}

public Transform Transform
{
    get; set;
}

public void Draw()
{
    draw_rect.x = (float)Transform.Position.X;
    draw_rect.y = (float)Transform.Position.Y;
    SDL.SDL_RenderCopyExF(Game.RenderContext, sprite, ref scr_rect, ref draw_rect, Transform.Degrees, IntPtr.Zero, SDL.SDL_RendererFlip.SDL_FLIP_NONE);
}
public void Translate(double x, double y)
{
    position.X += x;
    position.Y += y;
}
void layerDraw(Sprite l1, Sprite l2, double speed)
{
    l1.Transform.Translate(speed, 0);
    l1.Draw();


    l2.Transform.Translate(speed, 0);
    l2.Draw();

    if (l1.Transform.Position.X <= -Settings.Resolution.Width)
        l1.Transform.SetPosition(Settings.Resolution.Width + l2.Transform.Position.X, 0);
    if (l2.Transform.Position.X <= -Settings.Resolution.Width)
        l2.Transform.SetPosition(Settings.Resolution.Width + l1.Transform.Position.X, 0);  
    }
double speed_09 = -2.0, speed_08 = -4.0, speed_07 = -8.0, speed_06 = -16.0;
double speed_05 = -24.0, speed_04 = -32.0, speed_03 = -64.0, speed_02 = -96.0, speed_01 = -128.0;

protected override void Update(double deltaTime)
{
    background.Draw();
    layerDraw(forest_091, forest_092, speed_09 * deltaTime);
    layerDraw(forest_081, forest_082, speed_08 * deltaTime);
    layerDraw(forest_071, forest_072, speed_07 * deltaTime);
    layerDraw(forest_061, forest_062, speed_06 * deltaTime);
    layerDraw(particles051, particles052, speed_05 * deltaTime);
    layerDraw(forest_041, forest_042, speed_04 * deltaTime);
    layerDraw(particles_031, particles_032, speed_03 * deltaTime);
    layerDraw(bushes_021, bushes_022, speed_02 * deltaTime);
    layerDraw(mist_011, mist_012, speed_01 * deltaTime);
}
[11:31:07:32] (x,y): = (1902,7461329999965:0), deltaTime = 0,001391, speed = -0,002782
[11:31:07:32] (x:y): = (1902,7430913999965:0), deltaTime = 0,0015208, speed = -0,0030416
[11:31:07:32] (x:y): = (1902,7400399999965:0), deltaTime = 0,0015257, speed = -0,0030514
[11:31:07:32] (x:y): = (1902,7370409999965:0), deltaTime = 0,0014995, speed = -0,002999
[11:31:07:32] (x:y): = (1902,7339605999964:0), deltaTime = 0,0015402, speed = -0,0030804
[11:31:07:33] (x:y): = (1902,7300727999964:0), deltaTime = 0,0019439, speed = -0,0038878
[11:31:07:33] (x:y): = (1902,7271281999963:0), deltaTime = 0,0014723, speed = -0,0029446
[11:31:07:33] (x:y): = (1902,7241953999962:0), deltaTime = 0,0014664, speed = -0,0029328
[11:31:07:33] (x:y): = (1902,7212207999962:0), deltaTime = 0,0014873, speed = -0,0029746
[11:31:07:33] (x:y): = (1902,7181395999962:0), deltaTime = 0,0015406, speed = -0,0030812
[11:31:07:33] (x:y): = (1902,715346599996:0), deltaTime = 0,0013965, speed = -0,002793
[11:31:07:33] (x:y): = (1902,712221399996:0), deltaTime = 0,0015626, speed = -0,0031252
[11:31:07:34] (x:y): = (1902,709382799996:0), deltaTime = 0,0014193, speed = -0,0028386
[08:48:34:25] now_counter = 1097310517365, last_counter = 1097310516099, now_counter-last_counter = 1266
[08:48:34:25] now_counter = 1097310519141, last_counter = 1097310517365, now_counter-last_counter = 1776
[08:48:34:25] now_counter = 1097310521406, last_counter = 1097310519141, now_counter-last_counter = 2265
[08:48:34:25] now_counter = 1097310532746, last_counter = 1097310521406, now_counter-last_counter = 11340
[08:48:34:25] now_counter = 1097310534069, last_counter = 1097310532746, now_counter-last_counter = 1323
[08:48:34:25] now_counter = 1097310535356, last_counter = 1097310534069, now_counter-last_counter = 1287
[08:48:34:25] now_counter = 1097310536628, last_counter = 1097310535356, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310537897, last_counter = 1097310536628, now_counter-last_counter = 1269
[08:48:34:25] now_counter = 1097310539169, last_counter = 1097310537897, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310540441, last_counter = 1097310539169, now_counter-last_counter = 1272`
主循环,计算
deltaTime

void CreateWidnow()
{
    var windowFlags = Settings.Fullscreen ?
        SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN : Settings.Resizeble ? 
        SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE : SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN;
        
    renderWindow = SDL.SDL_CreateWindow(
        Settings.DebugMode ? $"{Settings.Title} [DEBUG]" : Settings.Title, SDL.SDL_WINDOWPOS_CENTERED, 
        SDL.SDL_WINDOWPOS_CENTERED,
        Settings.Resolution.Width,
        Settings.Resolution.Height,              
        windowFlags);
}

void CreateRenderer()
{
    if(Settings.VSinc) {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC |
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }
    else
    {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }   
}
void RenderLoop()
{
    bool cap = Settings.FPS > 0;
    var timer_fps = new Timer();
        
    ulong now_counter = SDL.SDL_GetPerformanceCounter();
    ulong last_counter = 0;
    double deltaTime = 0;
        
    while (renderLoop)
    {
        timer_fps.Start();
            
        last_counter = now_counter;
        now_counter = SDL.SDL_GetPerformanceCounter();
            
        deltaTime = (double)(now_counter - last_counter) / SDL.SDL_GetPerformanceFrequency();
            
        OnPreUpdate(deltaTime);
        OnUpdate(deltaTime);
        SDL.SDL_RenderPresent(renderer);
        OnPostUpdate(deltaTime);
            
        if( ( cap ) && ( timer_fps.GetTicks() < 1000 / Settings.FPS ) )
        {
            SDL.SDL_Delay( ( 1000 / Settings.FPS  ) - timer_fps.GetTicks() );
        }
            
    }
}
public Sprite(string path)
{
    Path = path;
    Transform = new Transform(new Point(0, 0));
    sprite = Image.IMG_LoadTexture(Game.RenderContext, path);
    SDL.SDL_QueryTexture(sprite, out format, out access, out width, out height); // get the width and height of the texture

    draw_rect = new SDL.SDL_FRect();
    draw_rect.w = width;
    draw_rect.h = height;
    scr_rect.x = 0; scr_rect.y = 0; scr_rect.w = width; scr_rect.h = height; 
}

public Transform Transform
{
    get; set;
}

public void Draw()
{
    draw_rect.x = (float)Transform.Position.X;
    draw_rect.y = (float)Transform.Position.Y;
    SDL.SDL_RenderCopyExF(Game.RenderContext, sprite, ref scr_rect, ref draw_rect, Transform.Degrees, IntPtr.Zero, SDL.SDL_RendererFlip.SDL_FLIP_NONE);
}
public void Translate(double x, double y)
{
    position.X += x;
    position.Y += y;
}
void layerDraw(Sprite l1, Sprite l2, double speed)
{
    l1.Transform.Translate(speed, 0);
    l1.Draw();


    l2.Transform.Translate(speed, 0);
    l2.Draw();

    if (l1.Transform.Position.X <= -Settings.Resolution.Width)
        l1.Transform.SetPosition(Settings.Resolution.Width + l2.Transform.Position.X, 0);
    if (l2.Transform.Position.X <= -Settings.Resolution.Width)
        l2.Transform.SetPosition(Settings.Resolution.Width + l1.Transform.Position.X, 0);  
    }
double speed_09 = -2.0, speed_08 = -4.0, speed_07 = -8.0, speed_06 = -16.0;
double speed_05 = -24.0, speed_04 = -32.0, speed_03 = -64.0, speed_02 = -96.0, speed_01 = -128.0;

protected override void Update(double deltaTime)
{
    background.Draw();
    layerDraw(forest_091, forest_092, speed_09 * deltaTime);
    layerDraw(forest_081, forest_082, speed_08 * deltaTime);
    layerDraw(forest_071, forest_072, speed_07 * deltaTime);
    layerDraw(forest_061, forest_062, speed_06 * deltaTime);
    layerDraw(particles051, particles052, speed_05 * deltaTime);
    layerDraw(forest_041, forest_042, speed_04 * deltaTime);
    layerDraw(particles_031, particles_032, speed_03 * deltaTime);
    layerDraw(bushes_021, bushes_022, speed_02 * deltaTime);
    layerDraw(mist_011, mist_012, speed_01 * deltaTime);
}
[11:31:07:32] (x,y): = (1902,7461329999965:0), deltaTime = 0,001391, speed = -0,002782
[11:31:07:32] (x:y): = (1902,7430913999965:0), deltaTime = 0,0015208, speed = -0,0030416
[11:31:07:32] (x:y): = (1902,7400399999965:0), deltaTime = 0,0015257, speed = -0,0030514
[11:31:07:32] (x:y): = (1902,7370409999965:0), deltaTime = 0,0014995, speed = -0,002999
[11:31:07:32] (x:y): = (1902,7339605999964:0), deltaTime = 0,0015402, speed = -0,0030804
[11:31:07:33] (x:y): = (1902,7300727999964:0), deltaTime = 0,0019439, speed = -0,0038878
[11:31:07:33] (x:y): = (1902,7271281999963:0), deltaTime = 0,0014723, speed = -0,0029446
[11:31:07:33] (x:y): = (1902,7241953999962:0), deltaTime = 0,0014664, speed = -0,0029328
[11:31:07:33] (x:y): = (1902,7212207999962:0), deltaTime = 0,0014873, speed = -0,0029746
[11:31:07:33] (x:y): = (1902,7181395999962:0), deltaTime = 0,0015406, speed = -0,0030812
[11:31:07:33] (x:y): = (1902,715346599996:0), deltaTime = 0,0013965, speed = -0,002793
[11:31:07:33] (x:y): = (1902,712221399996:0), deltaTime = 0,0015626, speed = -0,0031252
[11:31:07:34] (x:y): = (1902,709382799996:0), deltaTime = 0,0014193, speed = -0,0028386
[08:48:34:25] now_counter = 1097310517365, last_counter = 1097310516099, now_counter-last_counter = 1266
[08:48:34:25] now_counter = 1097310519141, last_counter = 1097310517365, now_counter-last_counter = 1776
[08:48:34:25] now_counter = 1097310521406, last_counter = 1097310519141, now_counter-last_counter = 2265
[08:48:34:25] now_counter = 1097310532746, last_counter = 1097310521406, now_counter-last_counter = 11340
[08:48:34:25] now_counter = 1097310534069, last_counter = 1097310532746, now_counter-last_counter = 1323
[08:48:34:25] now_counter = 1097310535356, last_counter = 1097310534069, now_counter-last_counter = 1287
[08:48:34:25] now_counter = 1097310536628, last_counter = 1097310535356, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310537897, last_counter = 1097310536628, now_counter-last_counter = 1269
[08:48:34:25] now_counter = 1097310539169, last_counter = 1097310537897, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310540441, last_counter = 1097310539169, now_counter-last_counter = 1272`
移动函数(Transform.Translate):

void CreateWidnow()
{
    var windowFlags = Settings.Fullscreen ?
        SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN : Settings.Resizeble ? 
        SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE : SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN;
        
    renderWindow = SDL.SDL_CreateWindow(
        Settings.DebugMode ? $"{Settings.Title} [DEBUG]" : Settings.Title, SDL.SDL_WINDOWPOS_CENTERED, 
        SDL.SDL_WINDOWPOS_CENTERED,
        Settings.Resolution.Width,
        Settings.Resolution.Height,              
        windowFlags);
}

void CreateRenderer()
{
    if(Settings.VSinc) {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC |
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }
    else
    {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }   
}
void RenderLoop()
{
    bool cap = Settings.FPS > 0;
    var timer_fps = new Timer();
        
    ulong now_counter = SDL.SDL_GetPerformanceCounter();
    ulong last_counter = 0;
    double deltaTime = 0;
        
    while (renderLoop)
    {
        timer_fps.Start();
            
        last_counter = now_counter;
        now_counter = SDL.SDL_GetPerformanceCounter();
            
        deltaTime = (double)(now_counter - last_counter) / SDL.SDL_GetPerformanceFrequency();
            
        OnPreUpdate(deltaTime);
        OnUpdate(deltaTime);
        SDL.SDL_RenderPresent(renderer);
        OnPostUpdate(deltaTime);
            
        if( ( cap ) && ( timer_fps.GetTicks() < 1000 / Settings.FPS ) )
        {
            SDL.SDL_Delay( ( 1000 / Settings.FPS  ) - timer_fps.GetTicks() );
        }
            
    }
}
public Sprite(string path)
{
    Path = path;
    Transform = new Transform(new Point(0, 0));
    sprite = Image.IMG_LoadTexture(Game.RenderContext, path);
    SDL.SDL_QueryTexture(sprite, out format, out access, out width, out height); // get the width and height of the texture

    draw_rect = new SDL.SDL_FRect();
    draw_rect.w = width;
    draw_rect.h = height;
    scr_rect.x = 0; scr_rect.y = 0; scr_rect.w = width; scr_rect.h = height; 
}

public Transform Transform
{
    get; set;
}

public void Draw()
{
    draw_rect.x = (float)Transform.Position.X;
    draw_rect.y = (float)Transform.Position.Y;
    SDL.SDL_RenderCopyExF(Game.RenderContext, sprite, ref scr_rect, ref draw_rect, Transform.Degrees, IntPtr.Zero, SDL.SDL_RendererFlip.SDL_FLIP_NONE);
}
public void Translate(double x, double y)
{
    position.X += x;
    position.Y += y;
}
void layerDraw(Sprite l1, Sprite l2, double speed)
{
    l1.Transform.Translate(speed, 0);
    l1.Draw();


    l2.Transform.Translate(speed, 0);
    l2.Draw();

    if (l1.Transform.Position.X <= -Settings.Resolution.Width)
        l1.Transform.SetPosition(Settings.Resolution.Width + l2.Transform.Position.X, 0);
    if (l2.Transform.Position.X <= -Settings.Resolution.Width)
        l2.Transform.SetPosition(Settings.Resolution.Width + l1.Transform.Position.X, 0);  
    }
double speed_09 = -2.0, speed_08 = -4.0, speed_07 = -8.0, speed_06 = -16.0;
double speed_05 = -24.0, speed_04 = -32.0, speed_03 = -64.0, speed_02 = -96.0, speed_01 = -128.0;

protected override void Update(double deltaTime)
{
    background.Draw();
    layerDraw(forest_091, forest_092, speed_09 * deltaTime);
    layerDraw(forest_081, forest_082, speed_08 * deltaTime);
    layerDraw(forest_071, forest_072, speed_07 * deltaTime);
    layerDraw(forest_061, forest_062, speed_06 * deltaTime);
    layerDraw(particles051, particles052, speed_05 * deltaTime);
    layerDraw(forest_041, forest_042, speed_04 * deltaTime);
    layerDraw(particles_031, particles_032, speed_03 * deltaTime);
    layerDraw(bushes_021, bushes_022, speed_02 * deltaTime);
    layerDraw(mist_011, mist_012, speed_01 * deltaTime);
}
[11:31:07:32] (x,y): = (1902,7461329999965:0), deltaTime = 0,001391, speed = -0,002782
[11:31:07:32] (x:y): = (1902,7430913999965:0), deltaTime = 0,0015208, speed = -0,0030416
[11:31:07:32] (x:y): = (1902,7400399999965:0), deltaTime = 0,0015257, speed = -0,0030514
[11:31:07:32] (x:y): = (1902,7370409999965:0), deltaTime = 0,0014995, speed = -0,002999
[11:31:07:32] (x:y): = (1902,7339605999964:0), deltaTime = 0,0015402, speed = -0,0030804
[11:31:07:33] (x:y): = (1902,7300727999964:0), deltaTime = 0,0019439, speed = -0,0038878
[11:31:07:33] (x:y): = (1902,7271281999963:0), deltaTime = 0,0014723, speed = -0,0029446
[11:31:07:33] (x:y): = (1902,7241953999962:0), deltaTime = 0,0014664, speed = -0,0029328
[11:31:07:33] (x:y): = (1902,7212207999962:0), deltaTime = 0,0014873, speed = -0,0029746
[11:31:07:33] (x:y): = (1902,7181395999962:0), deltaTime = 0,0015406, speed = -0,0030812
[11:31:07:33] (x:y): = (1902,715346599996:0), deltaTime = 0,0013965, speed = -0,002793
[11:31:07:33] (x:y): = (1902,712221399996:0), deltaTime = 0,0015626, speed = -0,0031252
[11:31:07:34] (x:y): = (1902,709382799996:0), deltaTime = 0,0014193, speed = -0,0028386
[08:48:34:25] now_counter = 1097310517365, last_counter = 1097310516099, now_counter-last_counter = 1266
[08:48:34:25] now_counter = 1097310519141, last_counter = 1097310517365, now_counter-last_counter = 1776
[08:48:34:25] now_counter = 1097310521406, last_counter = 1097310519141, now_counter-last_counter = 2265
[08:48:34:25] now_counter = 1097310532746, last_counter = 1097310521406, now_counter-last_counter = 11340
[08:48:34:25] now_counter = 1097310534069, last_counter = 1097310532746, now_counter-last_counter = 1323
[08:48:34:25] now_counter = 1097310535356, last_counter = 1097310534069, now_counter-last_counter = 1287
[08:48:34:25] now_counter = 1097310536628, last_counter = 1097310535356, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310537897, last_counter = 1097310536628, now_counter-last_counter = 1269
[08:48:34:25] now_counter = 1097310539169, last_counter = 1097310537897, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310540441, last_counter = 1097310539169, now_counter-last_counter = 1272`
视差实现功能(离开屏幕时将精灵移回右侧):

void CreateWidnow()
{
    var windowFlags = Settings.Fullscreen ?
        SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN : Settings.Resizeble ? 
        SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE : SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN;
        
    renderWindow = SDL.SDL_CreateWindow(
        Settings.DebugMode ? $"{Settings.Title} [DEBUG]" : Settings.Title, SDL.SDL_WINDOWPOS_CENTERED, 
        SDL.SDL_WINDOWPOS_CENTERED,
        Settings.Resolution.Width,
        Settings.Resolution.Height,              
        windowFlags);
}

void CreateRenderer()
{
    if(Settings.VSinc) {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC |
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }
    else
    {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }   
}
void RenderLoop()
{
    bool cap = Settings.FPS > 0;
    var timer_fps = new Timer();
        
    ulong now_counter = SDL.SDL_GetPerformanceCounter();
    ulong last_counter = 0;
    double deltaTime = 0;
        
    while (renderLoop)
    {
        timer_fps.Start();
            
        last_counter = now_counter;
        now_counter = SDL.SDL_GetPerformanceCounter();
            
        deltaTime = (double)(now_counter - last_counter) / SDL.SDL_GetPerformanceFrequency();
            
        OnPreUpdate(deltaTime);
        OnUpdate(deltaTime);
        SDL.SDL_RenderPresent(renderer);
        OnPostUpdate(deltaTime);
            
        if( ( cap ) && ( timer_fps.GetTicks() < 1000 / Settings.FPS ) )
        {
            SDL.SDL_Delay( ( 1000 / Settings.FPS  ) - timer_fps.GetTicks() );
        }
            
    }
}
public Sprite(string path)
{
    Path = path;
    Transform = new Transform(new Point(0, 0));
    sprite = Image.IMG_LoadTexture(Game.RenderContext, path);
    SDL.SDL_QueryTexture(sprite, out format, out access, out width, out height); // get the width and height of the texture

    draw_rect = new SDL.SDL_FRect();
    draw_rect.w = width;
    draw_rect.h = height;
    scr_rect.x = 0; scr_rect.y = 0; scr_rect.w = width; scr_rect.h = height; 
}

public Transform Transform
{
    get; set;
}

public void Draw()
{
    draw_rect.x = (float)Transform.Position.X;
    draw_rect.y = (float)Transform.Position.Y;
    SDL.SDL_RenderCopyExF(Game.RenderContext, sprite, ref scr_rect, ref draw_rect, Transform.Degrees, IntPtr.Zero, SDL.SDL_RendererFlip.SDL_FLIP_NONE);
}
public void Translate(double x, double y)
{
    position.X += x;
    position.Y += y;
}
void layerDraw(Sprite l1, Sprite l2, double speed)
{
    l1.Transform.Translate(speed, 0);
    l1.Draw();


    l2.Transform.Translate(speed, 0);
    l2.Draw();

    if (l1.Transform.Position.X <= -Settings.Resolution.Width)
        l1.Transform.SetPosition(Settings.Resolution.Width + l2.Transform.Position.X, 0);
    if (l2.Transform.Position.X <= -Settings.Resolution.Width)
        l2.Transform.SetPosition(Settings.Resolution.Width + l1.Transform.Position.X, 0);  
    }
double speed_09 = -2.0, speed_08 = -4.0, speed_07 = -8.0, speed_06 = -16.0;
double speed_05 = -24.0, speed_04 = -32.0, speed_03 = -64.0, speed_02 = -96.0, speed_01 = -128.0;

protected override void Update(double deltaTime)
{
    background.Draw();
    layerDraw(forest_091, forest_092, speed_09 * deltaTime);
    layerDraw(forest_081, forest_082, speed_08 * deltaTime);
    layerDraw(forest_071, forest_072, speed_07 * deltaTime);
    layerDraw(forest_061, forest_062, speed_06 * deltaTime);
    layerDraw(particles051, particles052, speed_05 * deltaTime);
    layerDraw(forest_041, forest_042, speed_04 * deltaTime);
    layerDraw(particles_031, particles_032, speed_03 * deltaTime);
    layerDraw(bushes_021, bushes_022, speed_02 * deltaTime);
    layerDraw(mist_011, mist_012, speed_01 * deltaTime);
}
[11:31:07:32] (x,y): = (1902,7461329999965:0), deltaTime = 0,001391, speed = -0,002782
[11:31:07:32] (x:y): = (1902,7430913999965:0), deltaTime = 0,0015208, speed = -0,0030416
[11:31:07:32] (x:y): = (1902,7400399999965:0), deltaTime = 0,0015257, speed = -0,0030514
[11:31:07:32] (x:y): = (1902,7370409999965:0), deltaTime = 0,0014995, speed = -0,002999
[11:31:07:32] (x:y): = (1902,7339605999964:0), deltaTime = 0,0015402, speed = -0,0030804
[11:31:07:33] (x:y): = (1902,7300727999964:0), deltaTime = 0,0019439, speed = -0,0038878
[11:31:07:33] (x:y): = (1902,7271281999963:0), deltaTime = 0,0014723, speed = -0,0029446
[11:31:07:33] (x:y): = (1902,7241953999962:0), deltaTime = 0,0014664, speed = -0,0029328
[11:31:07:33] (x:y): = (1902,7212207999962:0), deltaTime = 0,0014873, speed = -0,0029746
[11:31:07:33] (x:y): = (1902,7181395999962:0), deltaTime = 0,0015406, speed = -0,0030812
[11:31:07:33] (x:y): = (1902,715346599996:0), deltaTime = 0,0013965, speed = -0,002793
[11:31:07:33] (x:y): = (1902,712221399996:0), deltaTime = 0,0015626, speed = -0,0031252
[11:31:07:34] (x:y): = (1902,709382799996:0), deltaTime = 0,0014193, speed = -0,0028386
[08:48:34:25] now_counter = 1097310517365, last_counter = 1097310516099, now_counter-last_counter = 1266
[08:48:34:25] now_counter = 1097310519141, last_counter = 1097310517365, now_counter-last_counter = 1776
[08:48:34:25] now_counter = 1097310521406, last_counter = 1097310519141, now_counter-last_counter = 2265
[08:48:34:25] now_counter = 1097310532746, last_counter = 1097310521406, now_counter-last_counter = 11340
[08:48:34:25] now_counter = 1097310534069, last_counter = 1097310532746, now_counter-last_counter = 1323
[08:48:34:25] now_counter = 1097310535356, last_counter = 1097310534069, now_counter-last_counter = 1287
[08:48:34:25] now_counter = 1097310536628, last_counter = 1097310535356, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310537897, last_counter = 1097310536628, now_counter-last_counter = 1269
[08:48:34:25] now_counter = 1097310539169, last_counter = 1097310537897, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310540441, last_counter = 1097310539169, now_counter-last_counter = 1272`
forest_091
坐标输出到控制台:

void CreateWidnow()
{
    var windowFlags = Settings.Fullscreen ?
        SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN : Settings.Resizeble ? 
        SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE : SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN;
        
    renderWindow = SDL.SDL_CreateWindow(
        Settings.DebugMode ? $"{Settings.Title} [DEBUG]" : Settings.Title, SDL.SDL_WINDOWPOS_CENTERED, 
        SDL.SDL_WINDOWPOS_CENTERED,
        Settings.Resolution.Width,
        Settings.Resolution.Height,              
        windowFlags);
}

void CreateRenderer()
{
    if(Settings.VSinc) {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC |
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }
    else
    {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }   
}
void RenderLoop()
{
    bool cap = Settings.FPS > 0;
    var timer_fps = new Timer();
        
    ulong now_counter = SDL.SDL_GetPerformanceCounter();
    ulong last_counter = 0;
    double deltaTime = 0;
        
    while (renderLoop)
    {
        timer_fps.Start();
            
        last_counter = now_counter;
        now_counter = SDL.SDL_GetPerformanceCounter();
            
        deltaTime = (double)(now_counter - last_counter) / SDL.SDL_GetPerformanceFrequency();
            
        OnPreUpdate(deltaTime);
        OnUpdate(deltaTime);
        SDL.SDL_RenderPresent(renderer);
        OnPostUpdate(deltaTime);
            
        if( ( cap ) && ( timer_fps.GetTicks() < 1000 / Settings.FPS ) )
        {
            SDL.SDL_Delay( ( 1000 / Settings.FPS  ) - timer_fps.GetTicks() );
        }
            
    }
}
public Sprite(string path)
{
    Path = path;
    Transform = new Transform(new Point(0, 0));
    sprite = Image.IMG_LoadTexture(Game.RenderContext, path);
    SDL.SDL_QueryTexture(sprite, out format, out access, out width, out height); // get the width and height of the texture

    draw_rect = new SDL.SDL_FRect();
    draw_rect.w = width;
    draw_rect.h = height;
    scr_rect.x = 0; scr_rect.y = 0; scr_rect.w = width; scr_rect.h = height; 
}

public Transform Transform
{
    get; set;
}

public void Draw()
{
    draw_rect.x = (float)Transform.Position.X;
    draw_rect.y = (float)Transform.Position.Y;
    SDL.SDL_RenderCopyExF(Game.RenderContext, sprite, ref scr_rect, ref draw_rect, Transform.Degrees, IntPtr.Zero, SDL.SDL_RendererFlip.SDL_FLIP_NONE);
}
public void Translate(double x, double y)
{
    position.X += x;
    position.Y += y;
}
void layerDraw(Sprite l1, Sprite l2, double speed)
{
    l1.Transform.Translate(speed, 0);
    l1.Draw();


    l2.Transform.Translate(speed, 0);
    l2.Draw();

    if (l1.Transform.Position.X <= -Settings.Resolution.Width)
        l1.Transform.SetPosition(Settings.Resolution.Width + l2.Transform.Position.X, 0);
    if (l2.Transform.Position.X <= -Settings.Resolution.Width)
        l2.Transform.SetPosition(Settings.Resolution.Width + l1.Transform.Position.X, 0);  
    }
double speed_09 = -2.0, speed_08 = -4.0, speed_07 = -8.0, speed_06 = -16.0;
double speed_05 = -24.0, speed_04 = -32.0, speed_03 = -64.0, speed_02 = -96.0, speed_01 = -128.0;

protected override void Update(double deltaTime)
{
    background.Draw();
    layerDraw(forest_091, forest_092, speed_09 * deltaTime);
    layerDraw(forest_081, forest_082, speed_08 * deltaTime);
    layerDraw(forest_071, forest_072, speed_07 * deltaTime);
    layerDraw(forest_061, forest_062, speed_06 * deltaTime);
    layerDraw(particles051, particles052, speed_05 * deltaTime);
    layerDraw(forest_041, forest_042, speed_04 * deltaTime);
    layerDraw(particles_031, particles_032, speed_03 * deltaTime);
    layerDraw(bushes_021, bushes_022, speed_02 * deltaTime);
    layerDraw(mist_011, mist_012, speed_01 * deltaTime);
}
[11:31:07:32] (x,y): = (1902,7461329999965:0), deltaTime = 0,001391, speed = -0,002782
[11:31:07:32] (x:y): = (1902,7430913999965:0), deltaTime = 0,0015208, speed = -0,0030416
[11:31:07:32] (x:y): = (1902,7400399999965:0), deltaTime = 0,0015257, speed = -0,0030514
[11:31:07:32] (x:y): = (1902,7370409999965:0), deltaTime = 0,0014995, speed = -0,002999
[11:31:07:32] (x:y): = (1902,7339605999964:0), deltaTime = 0,0015402, speed = -0,0030804
[11:31:07:33] (x:y): = (1902,7300727999964:0), deltaTime = 0,0019439, speed = -0,0038878
[11:31:07:33] (x:y): = (1902,7271281999963:0), deltaTime = 0,0014723, speed = -0,0029446
[11:31:07:33] (x:y): = (1902,7241953999962:0), deltaTime = 0,0014664, speed = -0,0029328
[11:31:07:33] (x:y): = (1902,7212207999962:0), deltaTime = 0,0014873, speed = -0,0029746
[11:31:07:33] (x:y): = (1902,7181395999962:0), deltaTime = 0,0015406, speed = -0,0030812
[11:31:07:33] (x:y): = (1902,715346599996:0), deltaTime = 0,0013965, speed = -0,002793
[11:31:07:33] (x:y): = (1902,712221399996:0), deltaTime = 0,0015626, speed = -0,0031252
[11:31:07:34] (x:y): = (1902,709382799996:0), deltaTime = 0,0014193, speed = -0,0028386
[08:48:34:25] now_counter = 1097310517365, last_counter = 1097310516099, now_counter-last_counter = 1266
[08:48:34:25] now_counter = 1097310519141, last_counter = 1097310517365, now_counter-last_counter = 1776
[08:48:34:25] now_counter = 1097310521406, last_counter = 1097310519141, now_counter-last_counter = 2265
[08:48:34:25] now_counter = 1097310532746, last_counter = 1097310521406, now_counter-last_counter = 11340
[08:48:34:25] now_counter = 1097310534069, last_counter = 1097310532746, now_counter-last_counter = 1323
[08:48:34:25] now_counter = 1097310535356, last_counter = 1097310534069, now_counter-last_counter = 1287
[08:48:34:25] now_counter = 1097310536628, last_counter = 1097310535356, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310537897, last_counter = 1097310536628, now_counter-last_counter = 1269
[08:48:34:25] now_counter = 1097310539169, last_counter = 1097310537897, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310540441, last_counter = 1097310539169, now_counter-last_counter = 1272`

我使用nectcore3.1,цSDL2 v2.0.10.0

UPD:日志延迟计算:

void CreateWidnow()
{
    var windowFlags = Settings.Fullscreen ?
        SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN : Settings.Resizeble ? 
        SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE : SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN;
        
    renderWindow = SDL.SDL_CreateWindow(
        Settings.DebugMode ? $"{Settings.Title} [DEBUG]" : Settings.Title, SDL.SDL_WINDOWPOS_CENTERED, 
        SDL.SDL_WINDOWPOS_CENTERED,
        Settings.Resolution.Width,
        Settings.Resolution.Height,              
        windowFlags);
}

void CreateRenderer()
{
    if(Settings.VSinc) {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC |
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }
    else
    {
        renderer = SDL.SDL_CreateRenderer(
            renderWindow, -1, 
            SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
            SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
        );
    }   
}
void RenderLoop()
{
    bool cap = Settings.FPS > 0;
    var timer_fps = new Timer();
        
    ulong now_counter = SDL.SDL_GetPerformanceCounter();
    ulong last_counter = 0;
    double deltaTime = 0;
        
    while (renderLoop)
    {
        timer_fps.Start();
            
        last_counter = now_counter;
        now_counter = SDL.SDL_GetPerformanceCounter();
            
        deltaTime = (double)(now_counter - last_counter) / SDL.SDL_GetPerformanceFrequency();
            
        OnPreUpdate(deltaTime);
        OnUpdate(deltaTime);
        SDL.SDL_RenderPresent(renderer);
        OnPostUpdate(deltaTime);
            
        if( ( cap ) && ( timer_fps.GetTicks() < 1000 / Settings.FPS ) )
        {
            SDL.SDL_Delay( ( 1000 / Settings.FPS  ) - timer_fps.GetTicks() );
        }
            
    }
}
public Sprite(string path)
{
    Path = path;
    Transform = new Transform(new Point(0, 0));
    sprite = Image.IMG_LoadTexture(Game.RenderContext, path);
    SDL.SDL_QueryTexture(sprite, out format, out access, out width, out height); // get the width and height of the texture

    draw_rect = new SDL.SDL_FRect();
    draw_rect.w = width;
    draw_rect.h = height;
    scr_rect.x = 0; scr_rect.y = 0; scr_rect.w = width; scr_rect.h = height; 
}

public Transform Transform
{
    get; set;
}

public void Draw()
{
    draw_rect.x = (float)Transform.Position.X;
    draw_rect.y = (float)Transform.Position.Y;
    SDL.SDL_RenderCopyExF(Game.RenderContext, sprite, ref scr_rect, ref draw_rect, Transform.Degrees, IntPtr.Zero, SDL.SDL_RendererFlip.SDL_FLIP_NONE);
}
public void Translate(double x, double y)
{
    position.X += x;
    position.Y += y;
}
void layerDraw(Sprite l1, Sprite l2, double speed)
{
    l1.Transform.Translate(speed, 0);
    l1.Draw();


    l2.Transform.Translate(speed, 0);
    l2.Draw();

    if (l1.Transform.Position.X <= -Settings.Resolution.Width)
        l1.Transform.SetPosition(Settings.Resolution.Width + l2.Transform.Position.X, 0);
    if (l2.Transform.Position.X <= -Settings.Resolution.Width)
        l2.Transform.SetPosition(Settings.Resolution.Width + l1.Transform.Position.X, 0);  
    }
double speed_09 = -2.0, speed_08 = -4.0, speed_07 = -8.0, speed_06 = -16.0;
double speed_05 = -24.0, speed_04 = -32.0, speed_03 = -64.0, speed_02 = -96.0, speed_01 = -128.0;

protected override void Update(double deltaTime)
{
    background.Draw();
    layerDraw(forest_091, forest_092, speed_09 * deltaTime);
    layerDraw(forest_081, forest_082, speed_08 * deltaTime);
    layerDraw(forest_071, forest_072, speed_07 * deltaTime);
    layerDraw(forest_061, forest_062, speed_06 * deltaTime);
    layerDraw(particles051, particles052, speed_05 * deltaTime);
    layerDraw(forest_041, forest_042, speed_04 * deltaTime);
    layerDraw(particles_031, particles_032, speed_03 * deltaTime);
    layerDraw(bushes_021, bushes_022, speed_02 * deltaTime);
    layerDraw(mist_011, mist_012, speed_01 * deltaTime);
}
[11:31:07:32] (x,y): = (1902,7461329999965:0), deltaTime = 0,001391, speed = -0,002782
[11:31:07:32] (x:y): = (1902,7430913999965:0), deltaTime = 0,0015208, speed = -0,0030416
[11:31:07:32] (x:y): = (1902,7400399999965:0), deltaTime = 0,0015257, speed = -0,0030514
[11:31:07:32] (x:y): = (1902,7370409999965:0), deltaTime = 0,0014995, speed = -0,002999
[11:31:07:32] (x:y): = (1902,7339605999964:0), deltaTime = 0,0015402, speed = -0,0030804
[11:31:07:33] (x:y): = (1902,7300727999964:0), deltaTime = 0,0019439, speed = -0,0038878
[11:31:07:33] (x:y): = (1902,7271281999963:0), deltaTime = 0,0014723, speed = -0,0029446
[11:31:07:33] (x:y): = (1902,7241953999962:0), deltaTime = 0,0014664, speed = -0,0029328
[11:31:07:33] (x:y): = (1902,7212207999962:0), deltaTime = 0,0014873, speed = -0,0029746
[11:31:07:33] (x:y): = (1902,7181395999962:0), deltaTime = 0,0015406, speed = -0,0030812
[11:31:07:33] (x:y): = (1902,715346599996:0), deltaTime = 0,0013965, speed = -0,002793
[11:31:07:33] (x:y): = (1902,712221399996:0), deltaTime = 0,0015626, speed = -0,0031252
[11:31:07:34] (x:y): = (1902,709382799996:0), deltaTime = 0,0014193, speed = -0,0028386
[08:48:34:25] now_counter = 1097310517365, last_counter = 1097310516099, now_counter-last_counter = 1266
[08:48:34:25] now_counter = 1097310519141, last_counter = 1097310517365, now_counter-last_counter = 1776
[08:48:34:25] now_counter = 1097310521406, last_counter = 1097310519141, now_counter-last_counter = 2265
[08:48:34:25] now_counter = 1097310532746, last_counter = 1097310521406, now_counter-last_counter = 11340
[08:48:34:25] now_counter = 1097310534069, last_counter = 1097310532746, now_counter-last_counter = 1323
[08:48:34:25] now_counter = 1097310535356, last_counter = 1097310534069, now_counter-last_counter = 1287
[08:48:34:25] now_counter = 1097310536628, last_counter = 1097310535356, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310537897, last_counter = 1097310536628, now_counter-last_counter = 1269
[08:48:34:25] now_counter = 1097310539169, last_counter = 1097310537897, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310540441, last_counter = 1097310539169, now_counter-last_counter = 1272`
感谢您的回答和花费的时间。事实上,我花了很长时间才解决这个问题,我真的不明白为什么即使在SDL2中添加了绘制浮点精灵的功能,他们仍然根据显示器的像素网格绘制我

好消息是:deltaTime计算正确, 在将坐标传输到SDL渲染时,使用双圆角也没有问题

坏消息:解决方案太简单,不可能花上几天时间

SDL.SDL_SetHint(SDL.SDL_HINT_RENDER_SCALE_QUALITY,“2”)

这一行告诉SDL2在渲染精灵时使用各向异性过滤。
它使我的动画流畅。

您能将计时器的整数值也添加到日志中吗
now_counter-last_counter
或just
now_counter
@keltar Post updateSorry,但只有当浮点值和整数值都显示在同一个日志中时,它才有意义,因此我将解释为什么我要求它。我的猜测是,你们的加法计算累积了不精确性,所以你们的增量移动的总和与预期结果不同。我总是尽可能地重新进行整数计算;更简单的解决方案可能是使用总通过时间而不是dt(并在2小时左右滚动,以避免精度损失峰值)。