2017-09-08 20 views
0

ゲームループに適用された補間について読んで、それを自分で実装しようとしました。それは私が期待したものとほぼ同じように見えますが、オブジェクトが動きを終えると、奇妙なステップバックが起こります。私は、この問題がすべてによって引き起こされる可能性があるため、完全なソースをここに貼り付けることにしました。補間を伴うゲームループ - 奇妙なステップバック

#include <SFML/Graphics.hpp> 
#include <chrono> 

sf::RenderWindow window(sf::VideoMode(800, 600), "Interpolation"); 
sf::Event event; 
int fps = 10; // set to 10 for testing purpose 
std::chrono::nanoseconds timePerFrame = std::chrono::seconds(1); 
std::chrono::nanoseconds accumulator; 
std::chrono::steady_clock::time_point start; 
sf::RectangleShape shape1(sf::Vector2f(50, 50)); 
sf::RectangleShape shape2(sf::Vector2f(50, 50)); 
sf::Vector2f movement(0, 0); 
sf::Vector2f position1(375, 100); 
sf::Vector2f position2(375, 275); 

void initialization(); 
void processInput(); 
void update(); 
void interpolate(); 
void render(); 

int main() 
{ 
    initialization(); 
    while(window.isOpen()) 
    { 
     start = std::chrono::steady_clock::now(); 
     processInput(); 
     while(accumulator >= timePerFrame) 
     { 
      update(); 
      accumulator -= timePerFrame; 
     } 
     interpolate(); 
     render(); 
     accumulator += std::chrono::steady_clock::now() - start; 
    } 
    return 0; 
} 

void initialization() 
{ 
    timePerFrame /= fps; 
    shape1.setPosition(position1); 
    shape2.setPosition(position2); 
} 

void processInput() 
{ 
    while(window.pollEvent(event)) 
    { 
     if(event.type == sf::Event::Closed) window.close(); 
    } 
} 

void update() 
{ 
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) movement = sf::Vector2f(-300, 0); 
    else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) movement = sf::Vector2f(300, 0); 
    else movement = sf::Vector2f(0, 0); 
    position1.x += movement.x/fps; 
    position2.x += movement.x/fps; 
    shape1.setPosition(position1); 
    shape2.setPosition(position2); 
} 

void interpolate() 
{ 
    double interpolationFactor = (double) accumulator.count()/timePerFrame.count(); 
    shape2.setPosition(position2.x + (movement.x/fps * interpolationFactor), position2.y); 
} 

void render() 
{ 
    window.clear(sf::Color::Black); 
    window.draw(shape1); 
    window.draw(shape2); 
    window.display(); 
} 

この種の問題が発生する原因はわかりません。私はあなたの助けを楽しみにしています。

+0

この一連の記事を読んでいますか?https://gafferongames.com/post/fix_your_timestep/ –

+0

はい、何度も繰り返していますが、多分誤解されていました。 –

答えて

0

interpolate機能は、時間間隔のいくつかの部分を複数回カウントすることができます。

は、すべてのtimePerFrameのティックだけをリセットするので、高速ループレートでは、より小さい間隔を複数回追加できます。メインループが0.01秒で実行される場合、最初の呼び出しであるinterpolateは補間係数で0.01を使用します。次回は、0.02を使用します(合計0.03)。これは、updateが0.1秒(タイムステップ)を使用して位置を更新するのに十分な時間が蓄積されるまで続きます。それ以上の時間にinterpolateが追加されたため、オブジェクトは元に戻ります。

interpolateは、現在のステップの時間に加算するだけで、完全に累積された時間では追加しないでください。 (また、ループごとに開始時刻を取得するためにnowを呼び出すのではなく、終了時刻に使用された前回のループのnow値を次のループの開始時刻として使用する必要があります。 1つのループの終わりと次のループの終わり)

+0

クイック返信ありがとう。あなたの答えから私はいくつかのことを理解しています。私は、メインループの終わりにタイムポイントを含む新しい変数を追加することをお勧めします。しかし、私はあなたが「現在のステップで追加する」という意味を知らない。下のリンクには、私の考え方が何であるかを説明する画像があります。私は補間された位置が次のフレームの間に設定されているものより大きくないことを意味します。 http://i.imgur.com/jGa2Hyw.png –

+0

@NaulPewman 'interpolate'関数は、現在のステップの時間間隔(' accumulator'に追加する量)だけを追加する必要があります。言い換えれば、 'interpolate'の最後の呼び出しまでの時間をすでに考慮しているので、それはそれ以来経過した時間を考慮する必要があります。 – 1201ProgramAlarm

+0

いくつかのコードを投稿して、どのように動作させるべきですか?それを想像するのが良いでしょう。 –