2015-05-15 21 views
5

Ich arbeite an einem Spiel in Einheit und stoße auf ein Problem, das ich nicht lösen kann. Ich verbinde mich über ein Standard-WWW-Objekt mit einem Webserver und verwende eine Coroutine, um eine POST-Anfrage auszuführen.Unity - Rückgabewert erst nach Abschluss der Koroutine

Der Code an sich funktioniert, aber ich muss einen Variablenwert aktualisieren und diese Variable zurückgeben, sobald die Coroutine beendet ist, was ich nicht tun kann.

public int POST(string username, string passw) 
{ 
    WWWForm form = new WWWForm(); 
    form.AddField("usr", username); 
    form.AddField("pass", passw); 

    WWW www = new WWW(url, form); 

    StartCoroutine(WaitForRequest(www)); 

    //problem is here ! 
    return success_fail; 
} 

private IEnumerator WaitForRequest(WWW www) 
{ 

    yield return www; 
    if (www.error == null) 
    { 

      if(www.text.Contains("user exists")) 
      { 

       success_fail = 2; 
      } 
      else 
      { 
       success_fail=1; 
      } 
    } else { 
     success_fail=0; 
    }  
} 

Die Coroutine aktualisiert den Wert von 'success_fail' mit dem entsprechenden Wert. Aber die 'Rückkehr success_fail;' Die Zeile in der POST-Methode wird ausgeführt, bevor die Coroutine beendet wird. Dadurch wird ein falscher Wert zurückgegeben.

Ich habe versucht, eine zusätzliche Coroutine aber erfolglos zu verwenden, angenommen, dass ich dort auch einen Fehler hatte. Wie kann ich den Wert 'success_fail' erst nach Abschluss der Coroutine zurückgeben?

Danke.

+0

Wenn Sie eine andere Coroutine aufrufen, wird gewartet, bis diese Coroutine beendet ist. http://answers.unity3d.com/questions/276055/question-about-coroutines-and-waiting-for-a-functi.html – Shelby115

+0

Sie vermischen synchronen und asynchronen Code. Vielleicht wäre eine Callback-Funktion sinnvoll? Sie könnten einen 'Action ' Delegaten verwenden, wobei' T' der Typ ist, den Sie "zurückgeben" möchten. – rutter

Antwort

2

Nur eine Coroutine kann auf eine andere Coroutine warten. Da Sie auf die von Ihnen gestartete Coroutine warten müssen (WaitForRequest), müssen Sie POST in eine Coroutine konvertieren und nicht int zurückgeben.

Es sieht so aus, als ob success_fail eine Membervariable ist. Wenn das also für jeden ausgegeben wird, der den POST startet (als Coroutine), müssten Sie ihn sowieso nicht zurückgeben.

public int success_fail 

IEnumerator POST(string username, string passw) 
{ 
    WWWForm form = new WWWForm(); 
    form.AddField("usr", username); 
    form.AddField("pass", passw); 

    WWW www = new WWW(url, form); 

    yield return StartCoroutine(WaitForRequest(www)); 
} 

private IEnumerator WaitForRequest(WWW www) 
{ 
    yield return www; 
    if (www.error == null) 
    { 
     if(www.text.Contains("user exists")) 
      { 
       success_fail = 2; 
      } 
      else 
      { 
       success_fail=1; 
      } 
    } else { 
     success_fail=0; 
    }  
} 

Wenn Sie möchten, dass Ihr Code "wartet", muss es eine Coroutine sein. Sie können keinen Anruf tätigen, der wartet, ohne die gesamte Engine zu blockieren (ohne irgendeine Art von Loop-Hack).

Dieser Thread gibt einen Weg, in dem Sie die int von Ihrem Koroutine zurückkehren könnte, wenn Sie wirklich brauchen, aber POST kann immer noch nicht ein blockierenden Aufruf sein ...

http://answers.unity3d.com/questions/24640/how-do-i-return-a-value-from-a-coroutine.html

5

Funktionen nicht warten Sie auf Coroutines vor der Rückkehr, aber Sie könnten eine Aktion verwenden, um eine Art von Rückkehr zu geben.

Dieses in Ihrer Start-Funktion

WWW www = new WWW("http://google.com"); 

StartCoroutine(WaitForRequest(www,(status)=>{ 
    print(status.ToString()); 
})); 

und diese hinzufügen.

private IEnumerator WaitForRequest(WWW www,Action<int> callback) { 
    int tempInt = 0; 
    yield return www; 
    if (string.IsNullOrEmpty(www.error)) { 
     if(!string.IsNullOrEmpty(www.text)) { 
      tempInt = 3; 
     } 
     else { 
      tempInt=2; 
     } 
    } else { 
     print(www.error); 
     tempInt=1; 
    } 
    callback(tempInt); 
} 

Probieren Sie es aus, obwohl die Funktion einen Wert ändern kann, gibt sie keinen Wert zurück und hat nur einen einzigen Parameter. Also im Grunde ist dies keine Lösung für die Rückgabe Ihrer Coroutine, aber sobald wir den Int von der Coroutine empfangen haben, sind wir dann in der Lage zu rechtfertigen, was damit zu tun ist und rufen sogar andere Funktionen aus dem Callback heraus auf.

StartCoroutine(WaitForRequest(www,(status)=>{ 
    print(status.ToString()); 
    Awake(); // we can call other functions within the callback to use other codeblocks and logic. 
    if(status != 0) 
     print("yay!"); 
    } 
)); 

Dies könnte für Sie von Nutzen sein. http://answers.unity3d.com/questions/744888/returning-an-ienumerator-as-an-int.html

+2

Dies sollte eigentlich die akzeptierte Antwort sein. – Programmer

Verwandte Themen