Domanda

I'm stuck at Unity scripting. I got 3 files : Scene.cs , Player.cs and NetworkUtil.cs . I can't compile my code, as I don't know how to pass Coroutine response back to Scene.

In Scene.cs ( MonoBehavior class ) :

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 ) :

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 ) :

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.


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:

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 ?

È stato utile?

Soluzione

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.

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):

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.

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. So, making registerPlayer a coroutine is pointless since you are not yielding anything.

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top