1
\$\begingroup\$

I am making a tank game. I have a database on a server where I store information about Tank itself, Hulls, Turrets, and Guns.

When the server gets "Hull" request it returns all needed information about hull.

In my case it outputs text in this format: Hull-name/offsetX/offsetY/offsetZ

Same goes for all other tank parts.

For example if post data is: Key = "Turret" Value = "turret_id", Then output will be something like: superturret/0.12/-0.3/0.5

For posting the data I use unity's WWWForm. After receiving data from page I extract name and position values. By knowing name of the part I can find it in my "Resources" folder and spawn it. Then I assign position values, rotation values, and I am ready to go. Everything works perfect, except... I feel like code is too big for such a simple task.

Here is the code I am using, everything is commented and explained.

  public void Start()
  {   
    StartCoroutine(WaitForRequest());
  }
  IEnumerator WaitForRequest()
  {

    //----------------------------------------------------------------------------------------
    //get hull name and local offset
    var form = new WWWForm();
    form.AddField("hull", "ok");
    var download = new WWW(url, form);

    yield return download;

    Debug.Log(download.text);

    //that one is different because for now server only returns name of the hull. 
    //so download.text will be "superhull", while other parts of tanks will be like:
    //superturret/x/y/z

    GameObject hull = Instantiate(Resources.Load("hulls/" + download.text), transform.position, transform.rotation) as GameObject;

    //----------------------------------------------------------------------------------------
    //get turret name and local offset
    form = new WWWForm();
    form.AddField("turret", "ok");
    download = new WWW(url, form);

    yield return download;

    string turret_positi = download.text;

    Match turret_name = Regex.Match(download.text, @"^.*?(?=/)");
    GameObject turret = (GameObject)Instantiate(Resources.Load("turrets/" + turret_name), transform.position, transform.rotation);


    //----------------------------------------------------------------------------------------
    //And lastly get gun name and its local offset
    form = new WWWForm();
    form.AddField("gun", "ok");
    download = new WWW(url, form);

    yield return download;

    string gun_positi = download.text;

    Match gun_name = Regex.Match(download.text, @"^.*?(?=/)");
    GameObject tr = (GameObject)Resources.Load("guns/" + gun_name);

    GameObject gun = Instantiate(tr, transform.position, tr.transform.rotation);
    //----------------------------------------------------------------------------------------

    //set transforms to their parents (gun's parent is turret, and turrets parent is hull)
    gun.transform.parent = turret.transform;
    turret.transform.parent = hull.transform;

    hull.transform.parent = GameObject.Find("model").transform;

    //set local positions for each of them
    //for now, for hull I do it manually, but it will be also something like: VectorFromStr(hull_positi, '/')
    hull.transform.localPosition = new Vector3(-0.305f, 0.181f, 0.609f);

    turret.transform.localPosition = VectorFromStr(turret_positi, '/');
    gun.transform.localPosition = VectorFromStr(gun_positi, '/');

    //get Turret traverse speed from server
    form = new WWWForm();
    form.AddField("turretTraverse", "ok");
    download = new WWW(url, form);

    yield return download;
    turret.GetComponent<TurretRotator>().RotationSpeed = float.Parse(download.text);
}

Here is also VectorFromStr method:

 //It gets string like that: Text/0.143/-0.12/0.5
 //and returns: new Vector3(0.143, -0.12, 0.5);
 Vector3 VectorFromStr(string str, char divisor)
 {
    string posStr = str.Substring(str.IndexOf(divisor) + 1);
    var pos_arrStr = posStr.Split(divisor);
    Vector3 localPos = new Vector3(float.Parse(pos_arrStr[0]), float.Parse(pos_arrStr[1]), float.Parse(pos_arrStr[2]));

    return localPos;
 }

Now you can see that in the main code, I do almost exact same things 3 times! Basically, what I am trying to say that I wanted it to look something like this:

    //i was hoping to do something like this (pseudo code):

    GameObject hull = StartCouroutine(WaitForRequest("path1","hull_id"));
    GameObject turret = StartCouroutine(WaitForRequest("path2","turret_id"));
    GameObject gun = StartCouroutine(WaitForRequest("path3","gun_id"));

    gun.transform.parent = turret;
    turret.transform.parent = hull;
    hull.transform.parent = something else;


    IEnumerator WaitForRequest(string path, string object_id){
             1) do some web requesting stuff
             2) string obj_name = "get object name using regex or something else";
             3) GameObject temporary_obj = Instantiate(Resources.Load(path + obj_name), transform.position, transform.rotation) as GameObject;
             4) Vector3 obj_localPosition = VectorFromStr(download.text, '/');
             5) temporary_obj.transform.localPosition = obj_localPosition;
             6) GameObject default_transform = (GameObject)Resources.Load(path + obj_name);
             7) temporary_obj.transform.rotation = default_transform.rotation;

             .Finally: yield return temporary_obj;
    }
\$\endgroup\$
2
\$\begingroup\$

You could just have an array of the tank parts and then iterate through them using a for or foreach loop. Using this method you also make your code more expandable, for example if you want to add more parts like different tracks for the tank.

You should also try to generalize your code, the hull part should work the same as the gun part or turret part, this will make it easier to iterate through them aswell.

Example (Code not tested):

string[] parts = {"hull", "gun", "turret" };

WWWForm form;
for(int i = 0; i < parts.length; i++) {
    form = new WWWForm();
    form.AddField(parts[i], "ok");
    download = new WWW(url, form);

    yield return download;

    string pos = download.text;

    Match name = Regex.Match(download.text, @"^.*?(?=/)");
    GameObject obj = (GameObject)Instantiate(Resources.Load(parts[i] + "/" + name), transform.position, transform.rotation);
}

or use a function/coroutine that you've created:

string[] parts = {"hull", "gun", "turret" };

WWWForm form;
for(int i = 0; i < parts.length; i++) {
    //Your function or coroutine here
}
\$\endgroup\$
4
\$\begingroup\$

I don't know how much you're looking to change, but making three separate server calls is going to bite you later on when it turns into a huge bottleneck.

I would recommend making one request, which returns all necessary data at once, as signe katt mentioned.

However, using POST for a request where you are only retrieving data is not really necessary. You could just use a query string (e.g. "http://serverurl?turret=ok") and ditch the WWWForm altogether.

So for example, your request could be as simple as:

WWW download = new WWW(URL + "?hull=ok&turret=ok&gun=ok&turretTraverse=ok")
yield return download;

string[] response = download.text.Split("\n");
//each entry in the array corresponds to one of the requested objects
string hullName=response[0];
string turret_positi=response[1];
//etc
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.