2011-02-06 10 views
6

私は最初のxna 2dゲームで重力をシミュレートしようとしています。私はelapsedAirTime < maxAirTime は、しかし、私のコードは一度だけではなく、複数のスプライトを上に移動すると思われるいくつかの問題がある一方で2dスプライトに重力を追加するXna

 //Used for Jumping 
    double elapsedAirTime = 0.0; 
    double maxAirTime = 8.35; 
    //End Jumping 

を以下にだから私は一定量でスプライトを上に移動しようとしています持っています時間のこの部分の間に。ここに私の "player.cs"クラスのコード、またはクラスの更新メソッドがあります。

if (newState.IsKeyDown(Keys.Space)) 
     { 
      if(oldState.IsKeyUp(Keys.Space)) 
      { 
       //if we are standing or jumping then change the velocity 
       if (playerState == PlayerStates.Standing) 
       { 
        playerState = PlayerStates.Jumping; 
        this.position.Y -= (float)(30.0 + ((1.2)*elapsedAirTime)*elapsedAirTime); 
       } 
      } 
     } 
     //if we are jumping give it some time 
     if (playerState == PlayerStates.Jumping) 
     { 
      if ((elapsedAirTime < maxAirTime) && position.Y < 3) 
      { 
       this.position.Y -= (float)(30.0 + ((1.2) * elapsedAirTime)*elapsedAirTime); 
       elapsedAirTime += gameTime.ElapsedGameTime.TotalSeconds; 
      } 
      //otherwise time to fall 
      else 
      { 
       playerState = PlayerStates.Falling; 
      } 

     } 

     //add gravity to falling objects 
     if (playerState == PlayerStates.Falling || playerState == PlayerStates.Standing) 
     { 
      //if we are above the ground 
      if (this.position.Y < windowBot - 110) 
      { 
       //chnage state to falling 
       playerState = PlayerStates.Falling; 
       this.position.Y += 3.0f + ((float)(gameTime.ElapsedGameTime.TotalSeconds)); 
      } 
      else 
      { 
       playerState = PlayerStates.Standing; 
       elapsedAirTime = 0.0f; 
      } 
     } 

ご協力いただきありがとうございます。

答えて

11

スプライトに重力感を与えるには、速度と加速度をSpriteクラスに追加する必要があります。次に、SpriteのUpdateメソッドを作成し、毎回加速度をあなたのベロシティに追加し、ベロシティを追加して毎回の位置を決定します。位置は、経過した空気時間の量に基づいてはならない。あなたは一定の重力値に加速を設定し、ジャンプするたびにSpriteの速度に加算することができます。これは、素敵に見える流れる放物線のジャンプを作成します。タイミングを含める場合は、GameTimeをSpriteのUpdateメソッドに渡して、それを速度の変更子として使用できます。ここでは例の更新方法は次のとおりです。

 
void Update(GameTime gt) 
{ 
    int updateTime = gt.ElapsedGameTime.TotalMilliseconds - oldgt.ElapsedGameTime.TotalMilliseconds; 
    float timeScalar = updateTime/AVG_FRAME_TIME; 
    this.velocity += this.acceleration * timeScalar; 
    this.position += this.velocity; 
    oldgt = gt; 
} 

あなたはタイミングを使用する場合は、この方法は少し複雑です。更新がどれぐらいの時間を取ったかを記録し、その後、ベロシティを調整すべき量を得るために更新またはフレームを取るべき平均時間で除算する必要があります。タイミングがなければ、この方法は非常に簡単です:

 
void Update() 
{ 
    this.velocity += this.acceleration; 
    this.position += this.velocity; 
} 

あなたはタイミングが動作し、あなたがそれを実装する必要がある理由を正確にどのように理解するまで、私は簡単な方法を使用してお勧めします。

+0

なぜtimeScalarを計算して古いゲーム時間を保存するのですか?この更新機能がすべてのゲームループ(それがそうであるべきである)と呼ばれる場合、gt.ElapsedGameTimeはあなたのためにすべての重労働を既にしています。 –

+1

timeScalarを使用する理由は、a)デフォルトのフレームレートを変更する場合、またはb)コンピュータが遅すぎてデフォルトの60 UPS/FPSを使用できない場合です。どちらの場合でも、目標更新レートを下回ると、timeScalarコードなしで遅れているように見えます。 – Darkhydro

2

それは、この行が故障しているように見えます:仮定(

this.position.Y -= (float)(30.0 + ((1.2) * elapsedAirTime)*elapsedAirTime); 

私はあなたがこれは速くあなたが想像よりも、スプライトの位置を更新することを見つけるだろうと思い、スプライトは10のアップデートで画面最大330ピクセルずつ移動しますGame.IsFixedTimeStep == true)は、リアルタイムの10分の1秒です

&& position.Y < 3条件が満たされ、playerStateが変更される前に変更が反映されないことがあります。

スペースを確保している間は、1秒あたりxピクセルの速度で最大8.5秒間ジャンプしているようです。

計算をthis.position.y -= (float) (30 * gameTime.ElapsedGameTime.TotalSeconds)に変更すると、これはジャンプ動作に非常にライナーな動きを与えますが、スプライトが正確に30ピクセル/秒でジャンプすることを意味します。

デフォルトであるGame.IsFixedTimeStep == true - アップデートは毎秒60回呼び出されるため、gameTime.ElapsedGameTime.TotalSecondsは更新ごとに約0.1になる予定です。更新がスキップされて(例えば、レンダリングの問題など)何かが発生した場合、更新は遅れ、gameTime.ElapsedGameTime.TotalSecondsは0.3(2つの更新はスキップされます)でも正しいジャンプレートが実行されます。

関連する問題