0

I have this code right here:

using UnityEngine;
using Assets.Helpers; //DONT COPY
using System;
using System.Collections;

public class TileManager : MonoBehaviour {
[SerializeField]
private Settings _settings;

[SerializeField]
private Transform target;

[SerializeField]
private Texture2D texture;
private GameObject tile;

[SerializeField]//DONT COPY
private GameObject service;//DONT COPY

private float oldLat = 0f, oldLon = 0f;
private float lat = 0f, lon = 0f;

public PokemonManager pokeManager;

public float getLat {
    get {
        return lat;
    }
}

public float getLon {
    get { 
        return lon;
    }
}

IEnumerator Start()
{
    while (!Input.location.isEnabledByUser) {
        print ("Activate gps");
        yield return new WaitForSeconds (1f);
    }

    Debug.Log ("1");
    Input.location.Start(10f, 5f);

    int maxWait = 20;
    while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
    {
        yield return new WaitForSeconds(1);
        maxWait--;
        Debug.Log ("2");
    }

    if (maxWait < 1)
    {
        print("Timed out");
        yield break;
    }

    if (Input.location.status == LocationServiceStatus.Failed)
    {
        print("Unable to determine device location");
        yield break;
    }
    else
    {
        print("Location: " + Input.location.lastData.latitude + " " + Input.location.lastData.longitude + " " + Input.location.lastData.altitude + " " + Input.location.lastData.horizontalAccuracy + " " + Input.location.lastData.timestamp);
    }

    lat = Input.location.lastData.latitude;
    lon = Input.location.lastData.longitude;

    StartCoroutine (loadTiles (_settings.zoom));

    while (Input.location.isEnabledByUser) {

        yield return new WaitForSeconds (1f);           
    }

    yield return StartCoroutine (Start ());
    yield break;
}

public IEnumerator loadTiles(int zoom) {
    int size = _settings.size;
    string key = _settings.key;
    string style = _settings.style;

    lat = Input.location.lastData.latitude;
    lon = Input.location.lastData.longitude;

    string url = String.Format ("https://api.mapbox.com/v4/mapbox.{5}/{0},{1},{2}/{3}x{3}@2x.png?access_token={4}", lon, lat, zoom, size, key, style);

    WWW www = new WWW (url);
    yield return www;

    texture = www.texture;

    if (tile == null) {
        tile = GameObject.CreatePrimitive (PrimitiveType.Plane);
        tile.name = "Tile " + lat + "" + lon;
        tile.transform.localScale = Vector3.one * _settings.scale;
        tile.GetComponent<Renderer> ().material = _settings.material;
        tile.transform.parent = transform;
    }

    if (oldLat != 0 && oldLon != 0) {
        float x, y;
        Vector3 position = Vector3.zero;

        geodeticOffsetInv (lat * Mathf.Deg2Rad, lon * Mathf.Deg2Rad, oldLat * Mathf.Deg2Rad, oldLon * Mathf.Deg2Rad, out x, out y);

        if ((oldLat - lat) < 0 && (oldLon - lon) > 0 || (oldLat - lat) > 0 && (oldLon - lon) < 0) {
            position = new Vector3 (x, .5f, y);
        } else {
            position = new Vector3 (-x, .5f, -y);
        }

        position.x *= 0.300122f;
        position.z *= 0.123043f;

        target.position = position;
        Debug.Log ("called");
        /*float[] ll = px (lat, lon, _settings.zoom);
        float[] oll = px (oldLat, oldLon, _settings.zoom);
        x = ll [0] - oll [0];
        y = ll [0] - oll [0];

        float ps = 10 * _settings.scale / _settings.size;
        x *= ps;
        y *= ps;

        Debug.Log (x + " / " + y);*/
    }

    pokeManager.UpdatePokemonPosition ();

    tile.GetComponent<Renderer> ().material.mainTexture = texture;

    yield return new WaitForSeconds (1f);

    oldLat = lat;
    oldLon = lon;

    while (oldLat == lat && oldLon == lon) {
        lat = Input.location.lastData.latitude;
        lon = Input.location.lastData.longitude;
        yield return new WaitForSeconds (0.5f);
    }

    yield return new WaitUntil ( () => (oldLat != lat || oldLon != lon) );

    yield return StartCoroutine (loadTiles (_settings.zoom));
    yield break;
}

/*float[] px (float lat, float lon, int zoom) {
    float d = (_settings.size / 2 * Mathf.Pow (2, _settings.zoom));
    float f = Mathf.Min(Mathf.Max(Mathf.Sin(Mathf.Deg2Rad * lat), -0.9999f), 0.9999f);
    float x = Mathf.Round(d + lon * (_settings.size / 360 * Mathf.Pow (2, _settings.zoom)));
    float y = Mathf.Round(d + 0.5f * Mathf.Log((1 + f) / (1 - f)) * (-(_settings.size / (2 * Mathf.PI) * Mathf.Pow (2, _settings.zoom))));
    float[] result = new float[2];
    result [0] = x;
    result [1] = y;
    return result;
}*/

//SOURCE: http://stackoverflow.com/questions/4953150/convert-lat-longs-to-x-y-co-ordinates

float GD_semiMajorAxis = 6378137.000000f;
float GD_TranMercB     = 6356752.314245f;
float GD_geocentF      = 0.003352810664f;

void geodeticOffsetInv( float refLat, float refLon,
    float lat,    float lon,
    out float xOffset, out float yOffset )
{
    float a = GD_semiMajorAxis;
    float b = GD_TranMercB;
    float f = GD_geocentF;

    float L = lon - refLon;
    float U1    = Mathf.Atan((1-f) * Mathf.Tan(refLat));
    float U2    = Mathf.Atan((1-f) * Mathf.Tan(lat));
    float sinU1 = Mathf.Sin(U1);
    float cosU1 = Mathf.Cos(U1);
    float sinU2 = Mathf.Sin(U2);
    float cosU2 = Mathf.Cos(U2);

    float lambda = L;
    float lambdaP;
    float sinSigma;
    float sigma;
    float cosSigma;
    float cosSqAlpha;
    float cos2SigmaM;
    float sinLambda;
    float cosLambda;
    float sinAlpha;
    int iterLimit = 100;
    do {
        sinLambda = Mathf.Sin(lambda);
        cosLambda = Mathf.Cos(lambda);
        sinSigma = Mathf.Sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
            (cosU1*sinU2-sinU1*cosU2*cosLambda) *
            (cosU1*sinU2-sinU1*cosU2*cosLambda) );
        if (sinSigma==0)
        {
            xOffset = 0.0f;
            yOffset = 0.0f;
            return ;  // co-incident points
        }
        cosSigma    = sinU1*sinU2 + cosU1*cosU2*cosLambda;
        sigma       = Mathf.Atan2(sinSigma, cosSigma);
        sinAlpha    = cosU1 * cosU2 * sinLambda / sinSigma;
        cosSqAlpha  = 1 - sinAlpha*sinAlpha;
        cos2SigmaM  = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
        if (cos2SigmaM != cos2SigmaM) //isNaN
        {
            cos2SigmaM = 0;  // equatorial line: cosSqAlpha=0 (ยง6)
        }
        float C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
        lambdaP = lambda;
        lambda = L + (1-C) * f * sinAlpha *
            (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
    } while (Mathf.Abs(lambda-lambdaP) > 1e-12 && --iterLimit>0);

    if (iterLimit==0)
    {
        xOffset = 0.0f;
        yOffset = 0.0f;
        return;  // formula failed to converge
    }

    float uSq  = cosSqAlpha * (a*a - b*b) / (b*b);
    float A    = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
    float B    = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
    float deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
        B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
    float s = b*A*(sigma-deltaSigma);

    float bearing = Mathf.Atan2(cosU2*sinLambda,  cosU1*sinU2-sinU1*cosU2*cosLambda);
    xOffset = Mathf.Sin(bearing)*s;
    yOffset = Mathf.Cos(bearing)*s;
}

void Update() {
    service.SetActive (!Input.location.isEnabledByUser);//DONT COPY
    target.position = Vector3.Lerp (target.position, new Vector3 (0,.5f, 0), 2.0f * Time.deltaTime);
    Debug.Log ("lerped");
}

[Serializable]
public class Settings {
    [SerializeField]
    public Vector2 centerPosition;
    [SerializeField]
    public Material material;
    [SerializeField]
    public int zoom = 18;
    [SerializeField]
    public int size = 640;
    [SerializeField]
    public float scale = 1f;
    [SerializeField]
    public int range = 1;
    [SerializeField]
    public string key = "KEY_HERE";
    [SerializeField]
    public string style = "emerald";
}

}

My code runs for about 3 seconds then it hangs up as in I can't swipe anymore (There's another script assigned for swiping.). Then after about another 5 seconds, my application crashes. What's wrong with that?

EDITED CODE

using UnityEngine;
using Assets.Helpers; //DONT COPY
using System;
using System.Collections;

public class TileManager : MonoBehaviour {
[SerializeField]
private Settings _settings;

[SerializeField]
private Transform target;

[SerializeField]
private Texture2D texture;
private GameObject tile;

[SerializeField]//DONT COPY
private GameObject service;//DONT COPY

private float oldLat = 0f, oldLon = 0f;
private float lat = 0f, lon = 0f;

public PokemonManager pokeManager;

public Animator animator;

public float getLat {
    get {
        return lat;
    }
}

public float getLon {
    get { 
        return lon;
    }
}

IEnumerator Start()
{
    //Waiting for user to turn on GPS
    while (!Input.location.isEnabledByUser) {
        print ("Activate gps");
        yield return new WaitForSeconds (1f);
    }

    Input.location.Start(10f, 5f);

    //Waiting for GPS service to work
    int maxWait = 20;
    while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
    {
        yield return new WaitForSeconds(1);
        maxWait--;
    }

    //GPS Service failed to work so break
    //Break - Go out and end the function Start()
    if (maxWait < 1)
    {
        print("Timed out");
        yield break;
    }

    if (Input.location.status == LocationServiceStatus.Failed)
    {
        //GPS Service failed to work so break
        //Break - Go out and end the function Start()
        print("Unable to determine device location");
        yield break;
    }
    else
    {
        print("Location: " + Input.location.lastData.latitude + " " + Input.location.lastData.longitude + " " + Input.location.lastData.altitude + " " + Input.location.lastData.horizontalAccuracy + " " + Input.location.lastData.timestamp);
    }

    //Set latitude and longitude of user's current location
    lat = Input.location.lastData.latitude;
    lon = Input.location.lastData.longitude;

    //Call this coroutine which is responsible for:
    //1. Loading of the map
    //2. Updating of the map
    //StartCoroutine (loadTiles (_settings.zoom));

    while (Input.location.isEnabledByUser) {
        yield return new WaitForSeconds (1f);           
    }

    yield return null;
    StartCoroutine (Start ());
    yield break;
}

public IEnumerator loadTiles(int zoom) {
    int size = _settings.size;
    string key = _settings.key;
    string style = _settings.style;

    lat = Input.location.lastData.latitude;
    lon = Input.location.lastData.longitude;

    //string url = String.Format ("https://api.mapbox.com/v4/mapbox.{5}/{0},{1},{2}/{3}x{3}@2x.png?access_token={4}", lon, lat, zoom, size, key, style);
    string url = String.Format("https://api.mapbox.com/styles/v1/{5}/static/{0},{1},{2}/{3}x{3}@2x?access_token={4}", lon, lat, zoom, size, key, style);
    WWW www = null;

    www = new WWW (url);
    yield return www;

    texture = www.texture;

    if (tile == null) {
        tile = GameObject.CreatePrimitive (PrimitiveType.Plane);
        tile.name = "Tile " + lat + "" + lon;
        tile.transform.localScale = Vector3.one * _settings.scale;
        tile.GetComponent<Renderer> ().material = _settings.material;
        tile.transform.parent = transform;
    }

    if (oldLat != 0 && oldLon != 0) {
        float x, y;
        Vector3 position = Vector3.zero;

        geodeticOffsetInv (lat * Mathf.Deg2Rad, lon * Mathf.Deg2Rad, oldLat * Mathf.Deg2Rad, oldLon * Mathf.Deg2Rad, out x, out y);

        if ((oldLat - lat) < 0 && (oldLon - lon) > 0 || (oldLat - lat) > 0 && (oldLon - lon) < 0) {
            position = new Vector3 (x, .5f, y);
        } else {
            position = new Vector3 (-x, .5f, -y);
        }

        position.x *= 0.300122f;
        position.z *= 0.123043f;

        target.position = position;
    }

    pokeManager.UpdatePokemonPosition ();

    tile.GetComponent<Renderer> ().material.mainTexture = texture;

    yield return new WaitForSeconds (1f);

    oldLat = lat;
    oldLon = lon;

    while (oldLat == lat && oldLon == lon) {
        lat = Input.location.lastData.latitude;
        lon = Input.location.lastData.longitude;
        yield return new WaitForSeconds (0.5f);
    }

    yield return new WaitUntil ( () => (oldLat != lat || oldLon != lon) );

    yield return null;
    StartCoroutine (loadTiles (_settings.zoom));
    yield break;
}


//SOURCE: http://stackoverflow.com/questions/4953150/convert-lat-longs-to-x-y-co-ordinates

float GD_semiMajorAxis = 6378137.000000f;
float GD_TranMercB     = 6356752.314245f;
float GD_geocentF      = 0.003352810664f;

void geodeticOffsetInv( float refLat, float refLon, float lat, float lon,out float xOffset, out float yOffset)
{
    float a = GD_semiMajorAxis;
    float b = GD_TranMercB;
    float f = GD_geocentF;

    float L = lon - refLon;
    float U1    = Mathf.Atan((1-f) * Mathf.Tan(refLat));
    float U2    = Mathf.Atan((1-f) * Mathf.Tan(lat));
    float sinU1 = Mathf.Sin(U1);
    float cosU1 = Mathf.Cos(U1);
    float sinU2 = Mathf.Sin(U2);
    float cosU2 = Mathf.Cos(U2);

    float lambda = L;
    float lambdaP;
    float sinSigma;
    float sigma;
    float cosSigma;
    float cosSqAlpha;
    float cos2SigmaM;
    float sinLambda;
    float cosLambda;
    float sinAlpha;
    int iterLimit = 100;
    do {
        sinLambda = Mathf.Sin(lambda);
        cosLambda = Mathf.Cos(lambda);
        sinSigma = Mathf.Sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
            (cosU1*sinU2-sinU1*cosU2*cosLambda) *
            (cosU1*sinU2-sinU1*cosU2*cosLambda) );
        if (sinSigma==0)
        {
            xOffset = 0.0f;
            yOffset = 0.0f;
            return ;  // co-incident points
        }
        cosSigma    = sinU1*sinU2 + cosU1*cosU2*cosLambda;
        sigma       = Mathf.Atan2(sinSigma, cosSigma);
        sinAlpha    = cosU1 * cosU2 * sinLambda / sinSigma;
        cosSqAlpha  = 1 - sinAlpha*sinAlpha;
        cos2SigmaM  = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
        if (cos2SigmaM != cos2SigmaM) //isNaN
        {
            cos2SigmaM = 0;  // equatorial line: cosSqAlpha=0 (§6)
        }
        float C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
        lambdaP = lambda;
        lambda = L + (1-C) * f * sinAlpha *
            (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
    } while (Mathf.Abs(lambda-lambdaP) > 1e-12 && --iterLimit>0);

    if (iterLimit==0)
    {
        xOffset = 0.0f;
        yOffset = 0.0f;
        return;  // formula failed to converge
    }

    float uSq  = cosSqAlpha * (a*a - b*b) / (b*b);
    float A    = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
    float B    = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
    float deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
        B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
    float s = b*A*(sigma-deltaSigma);

    float bearing = Mathf.Atan2(cosU2*sinLambda,  cosU1*sinU2-sinU1*cosU2*cosLambda);
    xOffset = Mathf.Sin(bearing)*s;
    yOffset = Mathf.Cos(bearing)*s;
}

void Update() {
    //service.SetActive (!Input.location.isEnabledByUser);//DONT COPY
    target.position = Vector3.Lerp (target.position, new Vector3 (0,.5f, 0), 2.0f * Time.deltaTime);
}

[Serializable]
public class Settings {
    [SerializeField]
    public Vector2 centerPosition;
    [SerializeField]
    public Material material;
    [SerializeField]
    public int zoom = 18;
    [SerializeField]
    public int size = 640;
    [SerializeField]
    public float scale = 1f;
    [SerializeField]
    public int range = 1;
    [SerializeField]
    public string key = "KEY_HERE";
    [SerializeField]
    public string style = "emerald";
}
}
Jude Maranga
  • 865
  • 2
  • 9
  • 27
  • Uh...hm. Have you tried experimenting a little, disabling functionality until you identify the segment of code that is linked to the issue? This is a fair amount of logic for people to parse through, making it less likely you'll get a good answer to your question. – Serlite Mar 11 '17 at 23:28
  • @Serlite yees I did! I tried reducing my code in IEnumerator Start() to just while(true) { return new WaitForSeconds(1f); } – Jude Maranga Mar 11 '17 at 23:29
  • Comment out the `geodeticOffsetInv` function and check if it is still crashing – Programmer Mar 11 '17 at 23:29
  • @Programmer I already even commented out StartCoroutine(loadTiles(_settings.zoom)) in the Start function and it's still crashing – Jude Maranga Mar 11 '17 at 23:30
  • Editor or Android crash? – Programmer Mar 11 '17 at 23:49
  • @Programmer Android Crash. Like I BUILD & RUN so it's completely running on my phone. Oh btw, before I tried to BUILD & RUN, I was using Unity Remote and it was working! I mean it didn't crash or produced any error (as far as I know). – Jude Maranga Mar 11 '17 at 23:52
  • 1
    A lot of times when unity crashes this way, it's because it gets stuck in a infinite loop. – I.B Mar 12 '17 at 00:09
  • With your `geodeticOffsetInv` and `loadTiles` functions commented out, my solution should fix your problem. Do the-same thing to the `loadTiles` function. By the way, the `geodeticOffsetInv` scares me. If something goes wrong there, you will get an infinite loop there too. You probably should make that a coroutine that waits every frame or so. – Programmer Mar 12 '17 at 00:17
  • @Programmer Hello sir, I already tried your solution but still the same thing happens. It runs for a short time, but after 3 - 5 seconds, it crashes. By the way, I didn't make the geodeticOffsetInv a coroutine yet, I actually do not fully know how lol. I'm still a beginner at this, I have read the Unity Manual about Coroutines but it seems like what is in there is lacking in order for me to solve this issue. Oh btw, so what I did was 1.) yield return null 2.) StartCoroutine(Start()) AND StartCoroutine(loadTiles()) for the loadTiles function 3.) yield return break; – Jude Maranga Mar 12 '17 at 03:05
  • Glad it took you 2 hours to do that. Please put **EDIT** in your question and add the new code that is still crashing. Did you comment out `geodeticOffsetInv` and `loadTiles`. You must! – Programmer Mar 12 '17 at 03:13
  • @Programmer Oh sorry I went to church xD Okay I already put EDIT in my question and added the new code. And yes I tried commenting the StartCoroutine(loadTiles()) but it still failed – Jude Maranga Mar 12 '17 at 03:29
  • `loadTiles(int zoom)` is a public function. Are you sure that it's not being called from another place in another script or button? – Programmer Mar 12 '17 at 10:45
  • @Programmer Oh heey! I just figured out that the Input.location.Start() function does not work on my version of Unity 5.5 so I downloaded an older version of Unity and it's working smoothly! But I think your answer below has also helped in solving this problem and in clarifying some things I'm confused in Unity, so my biggest thanks to you sir Programmer! :D – Jude Maranga Mar 12 '17 at 15:01
  • 1
    That's just one of the problems. I've seen Input.location.Start() problem [before](http://stackoverflow.com/questions/41783288/auto-updating-gps-location/41783494#comment70763341_41783494) but didn't know your Unity version. Glad you solved it. – Programmer Mar 12 '17 at 15:11

1 Answers1

1

You are running into infinite loop.

Here is the problem:

yield return StartCoroutine (Start ());

When you do yield return StartCoroutine (Start ()), it will start new coroutine then wait for the old one to finish(which will never happen) then it will start another corutine while the first one is running.

The yield break; you have after the yield return StartCoroutine (Start ()) will not even be called. You can prove this by putting Debug.LogWarning("Finished coroutine!"); after that yield break;. That Debug.Log message will never show.

The biggest issue here is none of those coroutines are actually stopping. They yield then start another one then wait for that one to finish and then start another one. You can easily have thousands of coroutines running because of this.

Two things that must be done to fix this:

1.Remove yield return so that the coroutine can actually exit.

So, use StartCoroutine (Start ()); instead of yield return StartCoroutine (Start ()).

2.Put yield return null; before the StartCoroutine (Start ());. You must do this because if all of your logic in the Start() coroutine such as while (Input.location.isEnabledByUser) fail to run, there would be no yielding/waiting and you will get the infinite loop again.

Do the-same thing for your loadTiles coroutine.

Programmer
  • 121,791
  • 22
  • 236
  • 328