6

更新:ここにスタッターを示すビデオをアップロードしました:http://intninety.co.uk/xnastutter.mp4 1920x1080で表示していない場合は、ビデオをよく見る必要があるかもしれませんが、そこに表示されます2秒ごとに移動する場合はかなりはっきりとしたスタッターです。ビデオ自体が途切れないように、Webブラウザーではなく、Windows Media Playerで表示して、実際のスタッターが表示されないようにすることをお勧めします。

少し前に始めたプロジェクトを最近手に入れましたが、それでも問題を解決するのに苦労しています!

現在、画面上に1つのスプライトがあり、方向キーを使用して移動する非常に単純なアプリケーションがあります。問題は約2秒ごとで、ゲームが途切れ、スプライトが後方にジャンプしてから非常に速く前方に戻るように見えます。

スプライト自体は55x33のビットマップであるため、大きなものではなく、使用されているコードは次のとおりです。うまくいけば、これで問題の可能性についていくつかのアイデアを思いつくことができます。吃音がどのように見えるかを正確に確認するためにビデオが必要な場合は、1つをまとめて、必要に応じてどこかにアップロードできます。

コードでわかるように、フレーム間で失われた時間は、発生した場合に移動を大きくすることで補いますが、そのドロップは時間的に非常に一貫して発生しているため、どこかで何か間違ったことをしていると思います。

私はいくつかの異なるマシンで試しましたが、問題はそれらすべてで解決しません。誰かが何かアイデアを持っているか、それがどこにあるのかを知ることができれば、それを指摘していただければ幸いです

ありがとう :)

ゲームのコンストラクターグラフィックスデバイスマネージャーのセットアップ

graphics = new GraphicsDeviceManager(this);
graphics.IsFullScreen = true;
graphics.SynchronizeWithVerticalRetrace = false;
graphics.PreferredBackBufferWidth = 1920;
graphics.PreferredBackBufferHeight = 1080;
Content.RootDirectory = "Content";
this.IsFixedTimeStep = false;

ゲームの更新メソッドからのコード

KeyboardState keyboard = Keyboard.GetState();
GamePadState gamePad = GamePad.GetState(PlayerIndex.One);

if (keyboard.IsKeyDown(Keys.Escape)) {
    this.Exit();
}

if ((keyboard.IsKeyDown(Keys.Left)) || (gamePad.DPad.Left == ButtonState.Pressed))
{
    this.player.MoveLeft((float)gameTime.ElapsedGameTime.TotalMilliseconds); 
} else if ((keyboard.IsKeyDown(Keys.Right)) || (gamePad.DPad.Right == ButtonState.Pressed))
{
    this.player.MoveRight((float)gameTime.ElapsedGameTime.TotalMilliseconds);
}

if ((keyboard.IsKeyDown(Keys.Up)) || (gamePad.DPad.Up == ButtonState.Pressed))
{
    this.player.MoveUp((float)gameTime.ElapsedGameTime.TotalMilliseconds);
} else if ((keyboard.IsKeyDown(Keys.Down)) || (gamePad.DPad.Down == ButtonState.Pressed))
{
    this.player.MoveDown((float)gameTime.ElapsedGameTime.TotalMilliseconds);
}

base.Update(gameTime);

上記の更新メソッドに見られる「移動」メソッド

public void MoveLeft(float moveBy)
{
    this.position.X -= (moveBy * this.velocity.X);
}
public void MoveRight(float moveBy)
{
    this.position.X += (moveBy * this.velocity.X);
}

public void MoveUp(float moveBy)
{
    this.position.Y -= (moveBy * this.velocity.Y);
}

public void MoveDown(float moveBy)
{
    this.position.Y += (moveBy * this.velocity.Y);
}

ゲームの描画方法

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();

spriteBatch.Draw(this.player.Texture, this.player.Position, null, Color.White, this.player.Rotation, this.player.Origin, 1.0f, SpriteEffects.None, 0.0f);

spriteBatch.End();

base.Draw(gameTime);

編集:言及するのを忘れました、Moveメソッドで使用される速度オブジェクトはVector2です

4

2 に答える 2

1

私はそれが一瞬で一度起こるのを見ることができました、それは私が問題であると思うものに私を導きました。動きの要素として生のElapsedGameTime.TotalMilliseconds値を使用しているため、プログラムで発生するすべてのコンピューターの遅延が動きに直接適用されます。たとえば、コンピュータ(OS)が20分の1秒間何か他のことを行う場合、経過時間の値は通常約0.3ミリ秒である約50ミリ秒の値に累積されます。これにより、通常のフレームの150倍のモーションを持つフレームが発生します。

これを手動で発生させるには、次のようにします。

// define a frame counter
private int mCounter;

...

protected override void Update(GameTime pGameTime)
{
   // save the elapsed time value
   float time = (float)pGameTime.ElapsedGameTime.TotalMilliseconds;

   ...

   // force a long frame every 2500th frame (change depending on your framerate)
   if (mCounter++ > 2500)
   {
      mCounter = 0;
      time = 75; // about 225 times longer frame
   }

   ...

   // use the time value in your move calls
   if ((keyboard.IsKeyDown(Keys.Left)) || (gamePad.DPad.Left == ButtonState.Pressed))
      mPlayer.MoveLeft(time);

これが発生しないようにするには(設定を除いて、IsFixedTimeStep = true;すぐに修正されますが、必要に応じIsFixedTimeStepfalse)、上記のように時間値を使用する必要がありますが、上限を設定します。モーションに対する経過時間の割合を決定し、フレームごとに通過できる適切な時間を決定するのはあなた次第です。元:

protected override void Update(GameTime pGameTime)
{
   // save the elapsed time value
   float time = (float)pGameTime.ElapsedGameTime.TotalMilliseconds;
   if (time > 1)
      time = 1;

   ...

   if ((keyboard.IsKeyDown(Keys.Left)) || (gamePad.DPad.Left == ButtonState.Pressed))
      mPlayer.MoveLeft(time);

   ...

これで現在のプログラムの問題は修正されますが、多くのことが発生していないため、フレームはそれぞれ0.3msしかありません。ゲームにさらに時間がかかると、フレームごとにより多くの時間が経過し、キャップを1msよりもはるかに高くする必要があります。

編集:明確にするために、これはCPU/OSからの「ダウンタイム」です。それはなくなることはありません*、それが起こったときに束を先にジャンプするか(たとえば、経過時間が2000msに達すると問題を引き起こす可能性があります)、これらのスパイクを制限してそれらを引き起こすかどうかはあなた次第です遅れ; いずれにせよ、あなたの動きにはあなたが埋めることができない「穴」があります。これは実際には正常であり、見た目ほど重要ではありません。ゲームでさらに多くのことが起こると、それはますます目立たなくなります。特にグラフィックが2つしかなく、他に何も起きていないため、現時点では非常に際立っています。

*(実際には、CPUが他のプログラムに借用されないようにするために閉じることができる他のアプリケーションやプロセスを探す場合がありますが、マルチタスクOSを使用しているため、CPUの使用が保証されることはありません。あなた自身に。)

于 2012-04-11T13:27:29.807 に答える
0

再度更新する

考えただけです。(float)gameTime.ElapsedGameTime.TotalMilliseconds無限大や負の数にならないことを確認したことがありますか?経過時間が負になると、スプライトが前後にジャンプすることが説明されます。

そのキーボード。これは、マウスの左と右から左への移動とマウスの右クリックを変更することで証明できます。キーダウントリガーとキーアップトリガーを使用して、iskeydownの代わりに状態を設定します。

アップデート:

XNAで「吃音」を引き起こすことがいくつかあるようです。確かにあなたの問題はキーボードの問題だと思いました。ただし、ゲームパッドを使用してコードをテストしたと想定することしかできず、同じ問題が発生します。

には別の問題がありIsFixedTimeStepますが、すでにfalseに設定されています。クイックグーグル検索は、明確な修正なしでこれらのタイプの問題を抱えている人が数人以上いることを示唆しています。

http://forums.create.msdn.com/forums/t/9934.aspx?PageIndex=6で長い議論があります

その他の注意事項:

フレームレートを60fpsに制限してみてください。とにかくそれを超える理由はありません。ある力は、何もしない2Dアプリが、非常に高いスループットでグラフィックスパイプラインを停止させる可能性があることを示唆しています。

IsSlowRunningが呼び出されたかどうかを確認します。ガベージコレクションとカオス理論により、これが設定される可能性があります。私

于 2012-04-10T23:04:57.217 に答える