2016-06-12 14 views
8

Sto riscontrando un problema dispari con il rilevamento delle collisioni. Sto usando il metodo di aggiornamento per spostare il giocatore (non voglio usare FixedUpdate perché crea un movimento strano indesiderato). Il timestep fisso è impostato sul valore predefinito 0.02 (ho provato a giocare con l'impostazione dell'ora ma non ha funzionato neanche). Ho impostato il rilevamento delle collisioni dei corpi rigidi di entrambi gli oggetti su "dinamica continua". Inoltre, ho impostato il frame rate di destinazione su 300 e questo non ha modificato nulla ...Rilevamento collisione lenta a frame rate bassi

Quando il framerate è basso o il dispositivo stesso è lento, il rilevamento delle collisioni non funziona sempre. Il giocatore può facilmente cadere attraverso l'oggetto con cui dovrebbe scontrarsi, anche se a volte no.

Per favore dimmi cosa posso fare per risolvere il problema perché ho pubblicato un gioco e molti utenti segnalano questo (serio) bug. Grazie per il vostro sostegno.

Questo è quello che dovrebbe accadere:

enter image description here

Questo è ciò che effettivamente accade:

enter image description here

(come si può vedere, il cubo esce dal muro e dall'altra parte)

Sposto il lettore quando l'utente rilascia il pulsante del mouse:

Script 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); 
    } 
} 

Script 2 allegata al lettore (cubo):

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; 
    } 
} 

L'obiettivo del cubo è un bambino del cubo più grande (il muro).

Se hai bisogno di chiarimenti, lascia un commento qui sotto. Potrei dare il link al mio gioco se hai bisogno di maggiori dettagli.

citazione da here (trovato grazie a @Logman): "Il problema esiste anche se si utilizza il rilevamento continuo di collisione dinamico perché gli oggetti in rapido movimento possono muoversi così velocemente che sono troppo distanti da se stesso da un fotogramma a quello successivo immediato È come se fossero teleportati e nessun rilevamento di collisione sarebbe mai stato attivato perché non c'era alcuna collisione, da ogni prospettiva di fotogramma, e quindi da tutti i calcoli elaborati. "

Nel mio caso, il cubo non sta andando veloce, ma si ottiene il concetto.

+2

Utilizzare FixedUpdate() e correggere il bug effettivo ("movimento strano indesiderato"). Se il problema persiste, allarga il collisore su dispositivi lenti o imposta un req hardware minimo. o ottimizza il codice se puoi. Oh! E ora giocare con il timestamp fisso ha funzionato perché (non sorprendentemente) è correlato all'elaborazione di FixedUpdate() –

+2

Stai cercando qualcosa ** che non esiste **. È un ** motore di gioco ** è fatto per fare cose come palle da rimbalzo nei giochi di basket, gare automobilistiche e giochi di combattimento. Non è disponibile per le simulazioni di fisica "microscopica". Mai, mai, mai alterare o essere coinvolti con fixedTimestep; non ha assolutamente alcuna connessione con ciò che stai facendo e non dovrebbe mai essere toccato. – Fattie

+1

Il tuo profilo "Delay" è sbagliato. Utilizza semplicemente ** Invoke ** in Unity per i timer. – Fattie

risposta

7

Ci sono diversi problemi con il tuo codice.

  1. Si sta chiedendo a Coroutine di cedere per 1/50 di secondo. Il tempo minimo per cui si verifica una resa è di un fotogramma. Se Time.deltaTime > 0.02f questo è già uno dei problemi.
  2. Si sta utilizzando Coroutine e yield return null per calcolare calcoli fisici. Essenzialmente, stai calcolando fisica nel Update(), che viene chiamato solo una volta per frame (null equivale a new WaitForEndOfFrame(): come menzionato in (1), una Coroutine in esecuzione non può essere resa tra i frame).Con un frame-rate basso, la quantità di movimento che un oggetto si è impegnato tra due frame potrebbe superare il range di collisione del trigger target. Supponendo movimento lineare non accelerato: ∆S = v∆t dove v = velocità, ΔS è il movimento da coprire nel frame corrente, Δt è Time.deltaTime. Come puoi vedere, ΔS scala proporzionalmente con Δt.

  3. Hai chiamate GetComponent<T>() all'interno di loop. Evita sempre di farlo: memorizza invece un riferimento come variabile membro (inizialo in Start()).

Il mio suggerimento per il più veloce mod di lavoro sarebbe quello di non preoccuparsi troppo di "essere pulito", e invece di creare subroutine che chiamate da FixedUpdate(), e (creare e) utilizzare membro bool s al condizionale di prova che subroutine a "eseguire" e quale a "saltare". È inoltre possibile utilizzare i membri bool s o enum s come trigger per passare da vari "stati".

Una soluzione migliore sarebbe quella di lasciare che l'Unità di gestire la cinematica e voi invece lavorare con rigidbody mutators (e non transform.position s), ma che può essere del tutto inutile per una situazione arcade, che potrebbe essere la vostra. In tal caso attenersi al trucco sopra.

Se si in realtà si desidera controllare a mano la cinematica, utilizzare un motore come SFML. Un tutorial su Particle System sarebbe un buon punto di partenza.

+0

Grazie per la risposta. Potete fornire un codice esemplificativo per il vostro "mod di lavoro più veloce"? – Dinovr

4

È il tuo galleggiante percentuale, tra le altre cose.

"Se è attivato il cinematico, le forze, le collisioni o le articolazioni non influenzeranno più il corpo rigido."

Questo proviene dalla pagina isKinematic della documentazione di Unity. Stai impostando su true quando il progresso raggiunge 100. Quindi, con frame rate più bassi, ci sarà un salto improvviso a causa del fatto che i passi Time.deltaTime sono molto più alti, il progresso è improvvisamente> = 100, isKinematic è impostato su true e il player non è più interessato da collisioni.

Penso che dovrai ripensare molto codice qui e fare alcune ottimizzazioni. Ma gli altri poster li hanno già pubblicati, quindi non ne ho bisogno.

MODIFICA: Ho capito male la domanda iniziale, ho pensato che significava che stavi cercando di rilevare le collisioni ma il tuo codice non le stava sempre rilevando. Non sapevo che in realtà significava far sì che le collisioni si verificassero in primo luogo.

+0

Grazie per la risposta. Potete fornire un codice di esempio? Non capisco davvero ... – Dinovr