简体   繁体   English

Unity3D协程错误

[英]Unity3D Coroutine Error

I'm stuck at Unity scripting. 我被Unity脚本困住了。 I got 3 files : Scene.cs , Player.cs and NetworkUtil.cs . 我有3个文件: Scene.csPlayer.csNetworkUtil.cs I can't compile my code, as I don't know how to pass Coroutine response back to Scene. 我无法编译我的代码,因为我不知道如何将Coroutine响应传递回Scene。

In Scene.cs ( MonoBehavior class ) : Scene.csMonoBehavior类)中:

void OnGUI() {
  if(GUI.Button(new Rect(0, 0, 100, 100), "Register")) {
    StartCoroutine(registerPlayer());
  }
}
IEnumerator registerPlayer() {
  return Player.NewPlayer("Raptor"); // since Player is not IEnumerator, this line causes error.
}

In Player.cs ( Object class ) : Player.csObject class)中:

public static Player NewPlayer(string name) {
  Player p = new Player();
  result = p.tryRegister();
  if(result) {
    return p;
  } else {
    return null;
  }
}

private bool tryRegister() {
  Dictionary<string, string> data = new Dictionary<string, string>();
  data.Add("some_key", "some_value");
  NetworkUtil.ExecuteAPI(data);
}

In NetworkUtil.cs ( Object class ) : NetworkUtil.csObject class)中:

public static IEnumerator ExecuteAPI(Dictionary<string, string> data) {
  WWWForm form = new WWWForm();
  form.AddField("mode", request);
  foreach(KeyValuePair<string, string> entry in data) {
    form.AddField(entry.Key, entry.Value);
  }

  WWW handler = new WWW(API_URL, form);
  yield return handler;
  if(handler.error != null) {
    Debug.Log("Error occurred: " + handler.error); // Server Error
  } else {
    Debug.Log("Response: " + handler.text);
  }
}

How can I change the codes to make the flow complete? 如何更改代码以使流程完整?

Note: In Object class, StartCoroutine() does not exist. 注意:在Object类中, StartCoroutine()不存在。


EDIT 编辑

I have changed my codes to use Delegates & Events: 我已更改代码以使用“代表和事件”:

// DelegatesAndEvents.cs
public class DelegatesAndEvents : MonoBehaviour {
    public delegate void RegisterEventHandler(Player player);
    public static event RegisterEventHandler onPlayerRegister;

    public static void NewPlayerRegistered(Player player) {
        if(onPlayerRegister != null) {
            onPlayerRegister(player);
        }
    }
}

Then in Scene.cs : 然后在Scene.cs

void Start() {
  DelegatesAndEvents.onPlayerRegister += this.userRegistered;
}

public void userRegistered(Player player) {
  Debug.Log("User registered.");
}

How should I put the trigger in NetworkUtil.cs & Player.cs ? 我应该如何将触发器放入NetworkUtil.csPlayer.cs

There are several ways of doing that, because you not only need to return an IEnumerator , but it's Unity itself that will iterate on it, so you don't have the possibility to catch the return value. 这样做有多种方法,因为您不仅需要返回IEnumerator ,而且要在其上进行迭代的是Unity本身,因此您不可能捕获返回值。

Technically is possible to do the following: 从技术上讲,可以执行以下操作:

IEnumerator registerPlayer() {
  yield return Player.NewPlayer("Raptor"); // this is legal, player will be the Current value of the IEnumerator
}

If you want to do do something like the code above, you need to wrap the coroutine inside another, and iterate on it by yourself (I did something similar implementing behavior trees): 如果您想做类似上面的代码的事情,则需要 coroutine 包装在另一个内,然后自己对其进行迭代(我做了类似的实现行为树的操作):

IEnumerator Wrap(IEnumerator playerRegister)
{
  while(playerRegister.MoveNext())
  {
    Player p = playerRegister.Current as Player; //this can be done if you know what you are doing
    yield return null; 
  }
}

Another way is not return anything and pass a delegate to the coroutine , that will be called passing back to the caller the required parameter. 另一种方法是不返回任何内容,而是将委托传递给coroutine ,这将被称为将必需的参数传递回调用方。

Something like: 就像是:

IEnumerator DoSomething(Action<Response> whenDone)
{
  while (doingSomething)
    yield return null;

  whenDone(response);
}

EDIT 编辑

The other problem with your code is that you are calling another coroutine ( ExecuteAPI )from inside Player 's constructor. 您的代码的另一个问题是您正在从Player的构造函数内部调用另一个协程( ExecuteAPI )。 So, making registerPlayer a coroutine is pointless since you are not yielding anything. 因此,使registerPlayer成为协程是没有意义的,因为您不会产生任何结果。

In your case the simplest way to go is to pass a delegate to ExecuteAPI that will be called when you receive the response from the server. 在您的情况下,最简单的方法是将一个委托传递给ExecuteAPI ,当您从服务器收到响应时将调用该委托。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM