2016-06-12 19 views
8

私は衝突検出に奇妙な問題が発生しています。私はプレイヤーを移動するためにUpdateメソッドを使用しています(私は、望ましくない奇妙な動きを生成するため、FixedUpdateを使用したくありません)。固定タイムステップはデフォルト0.02に設定されています(時間設定で再生しようとしましたが、どちらも動作しませんでした)。私は両方のオブジェクトの剛体の衝突検出を「連続的な動的」に設定しました。また、目標のフレームレートを300に設定しても、何も変更されませんでした。低フレームレートで低速衝突検出

フレームレートが低いか、デバイス自体の速度が遅い場合、衝突検出が常に機能するとは限りません。プレイヤーは、衝突するはずのオブジェクトに簡単に落ちることがありますが、そうでない場合もあります。

ゲームを公開し、多くのユーザーがこの(深刻な)バグを報告しているため、これを修正するために私ができることを教えてください。ご協力ありがとうございます。

これが起こることになっているものです。

enter image description here

これは、実際に何が起こるかです:あなたが見ることができるように、キューブが壁から外れる(

enter image description here

と他の側に)

ユーザーがマウスボタンを離したときにプレーヤーを移動します。

スクリプト1:プレイヤー(キューブ)に添付

public Script2 Jumper; 
public float TimeToJump; 

public void Update() 
{ 
     if (Input.GetMouseButtonUp(0)) 
    { 
      StartCoroutine (Delay (1f/50f)); //Don't mind the time. 
    } 
} 

IEnumerator Delay(float waitTime) 
{ 
    yield return new WaitForSeconds (waitTime); 
    if (Jumper != null) 
    { 
     Jumper.SetVelocityToJump (gameObject, TimeToJump); 
    } 
} 

スクリプト2:

public class Script2 : MonoBehaviour { 

    GameObject target; 
    private float timeToJump; 
    public bool isJumping = false; 

    public void SetVelocityToJump(GameObject goToJumpTo, float timeToJump) 
    { 
     StartCoroutine(jumpAndFollow(goToJumpTo, timeToJump)); 
     this.timeToJump = timeToJump; 
     this.target = goToJumpTo; 
    } 

    private IEnumerator jumpAndFollow(GameObject goToJumpTo, float timeToJump) 
    { 
     var startPosition = transform.position; 
     var targetTransform = goToJumpTo.transform; 
     var lastTargetPosition = targetTransform.position; 
     var initialVelocity = getInitialVelocity(lastTargetPosition - startPosition, timeToJump); 

     var progress = 0f; 
     while (progress < timeToJump) 
     { 
      progress += Time.deltaTime; 
      if (targetTransform.position != lastTargetPosition) 
      { 
       lastTargetPosition = targetTransform.position; 
       initialVelocity = getInitialVelocity(lastTargetPosition - startPosition, timeToJump); 
      } 

      float percentage = progress * 100/timeToJump; 
      GetComponent<Rigidbody>().isKinematic = percentage < 100.0f; 

      transform.position = startPosition + (progress * initialVelocity) + (0.5f * Mathf.Pow(progress, 2) * _gravity); 
      yield return null; 
     } 

     OnFinishJump (goToJumpTo, timeToJump); 
    } 


    private void OnFinishJump(GameObject target, float timeToJump) 
    { 
     if (stillJumping) 
     { 
      this.isJumping = false; 
     } 
    } 

    private Vector3 getInitialVelocity(Vector3 toTarget, float timeToJump) 
    { 
     return (toTarget - (0.5f * Mathf.Pow(timeToJump, 2) * _gravity))/timeToJump; 
    } 
} 

キューブの目標は、より大きなキューブ(壁)の子です。

説明が必要な場合は、次のようにコメントを残してください。詳細が必要な場合は、私のゲームへのリンクを与えるかもしれません。

「@Logmanのおかげで発見されました」「高速ダイナミックコリジョン検出を使用しても、問題は存在します。なぜなら、高速に動くオブジェクトは非常に速く動くので、あるフレームから次のフレームへ彼らはテレポートされたようなもので、各フレームの観点から、そして処理されたすべての計算からの衝突が存在しないため、衝突検出は実行されませんでした。

私の場合、キューブは速くはありませんが、コンセプトを得ることができます。

+2

FixedUpdate()を使用して、実際のバグ(「望ましくない奇妙な動き」)を修正します。それでも問題が発生した場合は、遅いデバイスでコライダーを拡大するか、最低限のハードウェア要件を設定してください。できるだけコードを最適化してください。ああ! FixedUpdate()処理に関連する(驚くことではない)ため、固定タイムスタンプで再生することができました。 –

+2

存在しない**を探しています。それは**ゲームエンジン**です。バスケットボールゲーム、カーレース、格闘ゲームでバウンスボールのようなものを作るために作られています。これは、「微視的な」物理シミュレーションでは利用できません。 fixedTimestepを変更したり、関与したりすることは絶対にありません。あなたがやっていることに全く関係がなく、決して触れてはいけません。 – Fattie

+1

アウトライン「遅延」が間違っています。タイマーについてはUnityで** Invoke **を使用するだけです。 – Fattie

答えて

7

コードにはいくつかの問題があります。

  1. コルーチンが1/50秒間降伏するように求めています。歩留まりが発生しなければならない最短時間は1フレームです。 Time.deltaTime > 0.02fこれは既に問題の1つです。
  2. 物理計算を計算するには、Coroutinesとyield return nullを使用しています。基本的にはUpdate()で計算する物理学はとなり、1フレームあたりとなります(nullnew WaitForEndOfFrame()と同じです:(1)で述べたように、実行中のコルーチンはフレーム間で降伏できません)。低フレームレートでは、オブジェクトが2つのフレーム間で移動する動きの量が、ターゲットトリガの衝突範囲を超える可能性があります。線形非加速動作を仮定すると、∆S = v∆tここでv =速度、ΔSは現在のフレームでカバーする動き、ΔtはTime.deltaTimeです。ご覧のように、ΔSはΔtに比例して変化します。

  3. ループ内でGetComponent<T>()コールがあります。常にこれを避けてください:代わりにメンバ変数として参照を格納してください(Start()に初期化してください)。

最速作業ハックのための私の提案をするだろう「清潔であること」についてはあまり心配し、代わりにあなたがFixedUpdate()から呼び出すサブルーチンを作成し、(作成して)条件付きテスト先のメンバーbool Sを使用しませんサブルーチンを「実行する」、および「スキップする」とする。メンバboolまたはenumをトリガとして使用して、さまざまな "状態"を切り替えることもできます。

もっと良い解決策は、ユニティにキネマティクスを処理させ、代わりにrigidbodyミューテータ(transform.positionではなく)で作業させることですが、それはあなたの状況にはまったく必要ないかもしれません。その場合は上記のハックに固執してください。

実際にの場合、運動学を手で制御したい場合は、SFMLのようなエンジンを使用してください。パーティクルシステムのチュートリアルは始めるのに適しています。

+0

あなたの答えをありがとう。あなたの「最速の作業ハック」のサンプルコードを提供していただけますか? – Dinovr

4

あなたのフロートパーセントなどです。

"isKinematicが有効になっていると、強制、衝突、または関節が剛体にもう影響しません。"

これはUnityのドキュメントのisKinematicページからのものです。進捗状況が100になると、それをtrueに設定します。したがって、低いフレームレートでは、Time.deltaTimeのステップが非常に高く、突然進捗が> 100、isKinematicがtrueに設定されているため、プレーヤーもはや衝突の影響を受けません。

私はここで多くのコードを再考し、いくつかの重大な最適化を行う必要があると思います。しかし、他のポスターは既にそれらを置いているので、私はする必要はありません。

EDIT:最初の質問が間違っていました。あなたが衝突を検出しようとしていたが、コードが常にそれらを検出していないと思ったと思っていました。衝突が最初に発生することを実際に意味することを認識していませんでした。

+0

あなたの答えをありがとう。サンプルコードを提供していただけますか?私は本当に理解していない... – Dinovr